diff --git a/CMakeLists.txt b/CMakeLists.txt index 526ba77653..3923f543fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,7 @@ project(hifi) add_subdirectory(avatar-mixer) add_subdirectory(audio-mixer) add_subdirectory(domain-server) +add_subdirectory(eve) add_subdirectory(interface) add_subdirectory(injector) add_subdirectory(space-server) diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index 05e1583fca..fceedc6678 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -135,7 +135,11 @@ int main(int argc, const char * argv[]) !agent->matches((sockaddr *)&agentPublicAddress, (sockaddr *)&agentLocalAddress, agentType)) { if (memchr(SOLO_AGENT_TYPES_STRING, agent->getType(), 1) == NULL) { // this is an agent of which there can be multiple, just add them to the packet - currentBufferPos = addAgentToBroadcastPacket(currentBufferPos, &(*agent)); + // don't send avatar agents to other avatars, that will come from avatar mixer + if (agentType != AGENT_TYPE_AVATAR || agent->getType() != AGENT_TYPE_AVATAR) { + currentBufferPos = addAgentToBroadcastPacket(currentBufferPos, &(*agent)); + } + } else { // solo agent, we need to only send newest if (newestSoloAgents[agent->getType()] == NULL || diff --git a/eve/CMakeLists.txt b/eve/CMakeLists.txt new file mode 100644 index 0000000000..cb38529b2d --- /dev/null +++ b/eve/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 2.8) + +set(ROOT_DIR ..) +set(MACRO_DIR ${ROOT_DIR}/cmake/macros) + +# setup for find modules +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") + +set(TARGET_NAME eve) + +include(${MACRO_DIR}/SetupHifiProject.cmake) +setup_hifi_project(${TARGET_NAME}) + +include(${MACRO_DIR}/IncludeGLM.cmake) +include_glm(${TARGET_NAME} ${ROOT_DIR}) + +# link the required hifi libraries +include(${MACRO_DIR}/LinkHifiLibrary.cmake) +link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file diff --git a/eve/src/main.cpp b/eve/src/main.cpp new file mode 100644 index 0000000000..1478f3d1b2 --- /dev/null +++ b/eve/src/main.cpp @@ -0,0 +1,128 @@ +// +// main.cpp +// eve +// +// Created by Stephen Birarda on 4/22/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#include + +#include +#include +#include +#include +#include + +const int EVE_AGENT_LIST_PORT = 55441; +const float DATA_SEND_INTERVAL_MSECS = 10; + +bool stopReceiveAgentDataThread; + +void *receiveAgentData(void *args) +{ + sockaddr senderAddress; + ssize_t bytesReceived; + unsigned char incomingPacket[MAX_PACKET_SIZE]; + + AgentList *agentList = AgentList::getInstance(); + Agent *avatarMixer = NULL; + + while (!::stopReceiveAgentDataThread) { + if (agentList->getAgentSocket().receive(&senderAddress, incomingPacket, &bytesReceived)) { + switch (incomingPacket[0]) { + case PACKET_HEADER_BULK_AVATAR_DATA: + // this is the positional data for other agents + // eve doesn't care about this for now, so let's just update the receive time for the + // avatar mixer - this makes sure it won't be killed during silent agent removal + avatarMixer = agentList->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER); + + if (avatarMixer != NULL) { + avatarMixer->setLastRecvTimeUsecs(usecTimestampNow()); + } + + break; + default: + // have the agentList handle list of agents from DS, replies from other agents, etc. + agentList->processAgentData(&senderAddress, incomingPacket, bytesReceived); + break; + } + } + } + + pthread_exit(0); + return NULL; +} + +int main(int argc, char* argv[]) { + // create an AgentList instance to handle communication with other agents + AgentList *agentList = AgentList::createInstance(AGENT_TYPE_AVATAR, EVE_AGENT_LIST_PORT); + + // start telling the domain server that we are alive + agentList->startDomainServerCheckInThread(); + + // start the agent list thread that will kill off agents when they stop talking + agentList->startSilentAgentRemovalThread(); + + // start the ping thread that hole punches to create an active connection to other agents + agentList->startPingUnknownAgentsThread(); + + pthread_t receiveAgentDataThread; + pthread_create(&receiveAgentDataThread, NULL, receiveAgentData, NULL); + + // create an AvatarData object, "eve" + AvatarData eve = AvatarData(); + + // move eve away from the origin + eve.setBodyPosition(glm::vec3(3, 0, -3)); + + // turn her back towards the origin + eve.setBodyYaw(-45); + + // put her hand out so somebody can shake it + eve.setHandPosition(glm::vec3(eve.getBodyPosition()[0] - 0.2, + 0.25, + eve.getBodyPosition()[2] + 0.1)); + + unsigned char broadcastPacket[MAX_PACKET_SIZE]; + broadcastPacket[0] = PACKET_HEADER_HEAD_DATA; + + int numBytesToSend = 0; + + timeval thisSend; + double numMicrosecondsSleep = 0; + + while (true) { + // update the thisSend timeval to the current time + gettimeofday(&thisSend, NULL); + + // find the current avatar mixer + Agent *avatarMixer = agentList->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER); + + // make sure we actually have an avatar mixer with an active socket + if (avatarMixer != NULL && avatarMixer->getActiveSocket() != NULL) { + // use the getBroadcastData method in the AvatarData class to populate the broadcastPacket buffer + numBytesToSend = eve.getBroadcastData((broadcastPacket + 1)); + + + // use the UDPSocket instance attached to our agent list to send avatar data to mixer + agentList->getAgentSocket().send(avatarMixer->getActiveSocket(), broadcastPacket, numBytesToSend); + } + + // sleep for the correct amount of time to have data send be consistently timed + if ((numMicrosecondsSleep = (DATA_SEND_INTERVAL_MSECS * 1000) - (usecTimestampNow() - usecTimestamp(&thisSend))) > 0) { + usleep(numMicrosecondsSleep); + } + } + + // stop the receive agent data thread + stopReceiveAgentDataThread = true; + pthread_join(receiveAgentDataThread, NULL); + + // stop the agent list's threads + agentList->stopDomainServerCheckInThread(); + agentList->stopPingUnknownAgentsThread(); + agentList->stopSilentAgentRemovalThread(); +} + + diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index de9b31c9df..e4e8dc1614 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -8,7 +8,6 @@ project(${TARGET_NAME}) # setup for find modules set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") -set(GLM_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external) set(LODEPNG_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/LodePNG) set(PORTAUDIO_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/portaudio) diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index 6f77ee66dc..d1bbf5e65b 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -33,11 +33,9 @@ float MouthWidthChoices[3] = {0.5, 0.77, 0.3}; float browWidth = 0.8; float browThickness = 0.16; -bool usingBigSphereCollisionTest = false; +bool usingBigSphereCollisionTest = true; + -const float DECAY = 0.1; -const float THRUST_MAG = 10.0; -const float YAW_MAG = 300.0; char iris_texture_file[] = "resources/images/green_eye.png"; @@ -47,18 +45,24 @@ unsigned int iris_texture_height = 256; Head::Head(bool isMine) { - _avatar.orientation.setToIdentity(); - _avatar.velocity = glm::vec3( 0.0, 0.0, 0.0 ); - _avatar.thrust = glm::vec3( 0.0, 0.0, 0.0 ); + _orientation.setToIdentity(); + + _velocity = glm::vec3( 0.0, 0.0, 0.0 ); + _thrust = glm::vec3( 0.0, 0.0, 0.0 ); _rotation = glm::quat( 0.0f, 0.0f, 0.0f, 0.0f ); _closestOtherAvatar = 0; _bodyYaw = -90.0; _bodyPitch = 0.0; _bodyRoll = 0.0; _bodyYawDelta = 0.0; - _triggeringAction = false; + _mousePressed = false; _mode = AVATAR_MODE_STANDING; _isMine = isMine; + _maxArmLength = 0.0; + //_transmitterTimer = 0; + _transmitterHz = 0.0; + _transmitterPackets = 0; + _numOtherAvatarsInView = 0; initializeSkeleton(); @@ -67,49 +71,53 @@ Head::Head(bool isMine) { for (int i = 0; i < MAX_DRIVE_KEYS; i++) _driveKeys[i] = false; - _pupilSize = 0.10; - _interPupilDistance = 0.6; - _interBrowDistance = 0.75; - _nominalPupilSize = 0.10; - _headYaw = 0.0; - _eyebrowPitch[0] = -30; - _eyebrowPitch[1] = -30; - _eyebrowRoll [0] = 20; - _eyebrowRoll [1] = -20; - _mouthPitch = 0; - _mouthYaw = 0; - _mouthWidth = 1.0; - _mouthHeight = 0.2; - _eyeballPitch[0] = 0; - _eyeballPitch[1] = 0; - _eyeballScaleX = 1.2; - _eyeballScaleY = 1.5; - _eyeballScaleZ = 1.0; - _eyeballYaw[0] = 0; - _eyeballYaw[1] = 0; - _pitchTarget = 0; - _yawTarget = 0; - _noiseEnvelope = 1.0; - _pupilConverge = 10.0; - _leanForward = 0.0; - _leanSideways = 0.0; - _eyeContact = 1; - _eyeContactTarget = LEFT_EYE; - _scale = 1.0; - _renderYaw = 0.0; - _renderPitch = 0.0; - _audioAttack = 0.0; - _loudness = 0.0; - _averageLoudness = 0.0; - _lastLoudness = 0.0; - _browAudioLift = 0.0; - _noise = 0; - _handBeingMoved = false; - _previousHandBeingMoved = false; - _movedHandOffset = glm::vec3( 0.0, 0.0, 0.0 ); - _usingSprings = false; - _springForce = 6.0f; - _springVelocityDecay = 16.0f; + _head.pupilSize = 0.10; + _head.interPupilDistance = 0.6; + _head.interBrowDistance = 0.75; + _head.nominalPupilSize = 0.10; + _head.yaw = 0.0; + _head.pitch = 0.0; + _head.roll = 0.0; + _head.pitchRate = 0.0; + _head.yawRate = 0.0; + _head.rollRate = 0.0; + _head.eyebrowPitch[0] = -30; + _head.eyebrowPitch[1] = -30; + _head.eyebrowRoll [0] = 20; + _head.eyebrowRoll [1] = -20; + _head.mouthPitch = 0; + _head.mouthYaw = 0; + _head.mouthWidth = 1.0; + _head.mouthHeight = 0.2; + _head.eyeballPitch[0] = 0; + _head.eyeballPitch[1] = 0; + _head.eyeballScaleX = 1.2; + _head.eyeballScaleY = 1.5; + _head.eyeballScaleZ = 1.0; + _head.eyeballYaw[0] = 0; + _head.eyeballYaw[1] = 0; + _head.pitchTarget = 0; + _head.yawTarget = 0; + _head.noiseEnvelope = 1.0; + _head.pupilConverge = 10.0; + _head.leanForward = 0.0; + _head.leanSideways = 0.0; + _head.eyeContact = 1; + _head.eyeContactTarget = LEFT_EYE; + _head.scale = 1.0; + _head.audioAttack = 0.0; + _head.loudness = 0.0; + _head.averageLoudness = 0.0; + _head.lastLoudness = 0.0; + _head.browAudioLift = 0.0; + _head.noise = 0; + + _movedHandOffset = glm::vec3( 0.0, 0.0, 0.0 ); + _usingBodySprings = true; + _springForce = 6.0f; + _springVelocityDecay = 16.0f; + _renderYaw = 0.0; + _renderPitch = 0.0; _sphere = NULL; @@ -120,80 +128,99 @@ Head::Head(bool isMine) { printLog("error %u: %s\n", error, lodepng_error_text(error)); } } - - for (int o=0; ogetRelativeValue(HEAD_PITCH_RATE); - _headYawRate = serialInterface->getRelativeValue(HEAD_YAW_RATE); + _head.yawRate = serialInterface->getRelativeValue(HEAD_YAW_RATE); float measured_lateral_accel = serialInterface->getRelativeValue(ACCEL_X) - ROLL_ACCEL_COUPLING*serialInterface->getRelativeValue(HEAD_ROLL_RATE); float measured_fwd_accel = serialInterface->getRelativeValue(ACCEL_Z) - @@ -242,43 +269,42 @@ void Head::UpdateGyros(float frametime, SerialInterface * serialInterface, int h const float MAX_YAW = 85; const float MIN_YAW = -85; - if ((_headPitch < MAX_PITCH) && (_headPitch > MIN_PITCH)) + if ((_head.pitch < MAX_PITCH) && (_head.pitch > MIN_PITCH)) addPitch(measured_pitch_rate * -HEAD_ROTATION_SCALE * frametime); addRoll(-measured_roll_rate * HEAD_ROLL_SCALE * frametime); if (head_mirror) { - if ((_headYaw < MAX_YAW) && (_headYaw > MIN_YAW)) - addYaw(-_headYawRate * HEAD_ROTATION_SCALE * frametime); + if ((_head.yaw < MAX_YAW) && (_head.yaw > MIN_YAW)) + addYaw(-_head.yawRate * HEAD_ROTATION_SCALE * frametime); addLean(-measured_lateral_accel * frametime * HEAD_LEAN_SCALE, -measured_fwd_accel*frametime * HEAD_LEAN_SCALE); } else { - if ((_headYaw < MAX_YAW) && (_headYaw > MIN_YAW)) - addYaw(_headYawRate * -HEAD_ROTATION_SCALE * frametime); + if ((_head.yaw < MAX_YAW) && (_head.yaw > MIN_YAW)) + addYaw(_head.yawRate * -HEAD_ROTATION_SCALE * frametime); addLean(measured_lateral_accel * frametime * -HEAD_LEAN_SCALE, measured_fwd_accel*frametime * HEAD_LEAN_SCALE); } } void Head::addLean(float x, float z) { // Add Body lean as impulse - _leanSideways += x; - _leanForward += z; + _head.leanSideways += x; + _head.leanForward += z; } void Head::setLeanForward(float dist){ - _leanForward = dist; + _head.leanForward = dist; } void Head::setLeanSideways(float dist){ - _leanSideways = dist; + _head.leanSideways = dist; } -void Head::setTriggeringAction( bool d ) { - _triggeringAction = d; +void Head::setMousePressed( bool d ) { + _mousePressed = d; } - void Head::simulate(float deltaTime) { //------------------------------------------------------------- @@ -293,21 +319,38 @@ void Head::simulate(float deltaTime) { _closestOtherAvatar = -1; float closestDistance = 10000.0f; - /* AgentList * agentList = AgentList::getInstance(); + + _numOtherAvatarsInView =0; for(std::vector::iterator agent = agentList->getAgents().begin(); agent != agentList->getAgents().end(); agent++) { - if (( agent->getLinkedData() != NULL && ( agent->getType() == AGENT_TYPE_INTERFACE ) )) { + if (( agent->getLinkedData() != NULL && ( agent->getType() == AGENT_TYPE_AVATAR ) )) { Head *otherAvatar = (Head *)agent->getLinkedData(); - - // when this is working, I will grab the position here... - //glm::vec3 otherAvatarPosition = otherAvatar->getBodyPosition(); + + if ( _numOtherAvatarsInView < MAX_OTHER_AVATARS ) { + + //----------------------------------------------------------- + // test other avatar hand position for proximity... + //----------------------------------------------------------- + _otherAvatarHandPosition[ _numOtherAvatarsInView ] = otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND ); + glm::vec3 v( _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position ); + v -= _otherAvatarHandPosition[ _numOtherAvatarsInView ]; + + float distance = glm::length( v ); + if ( distance < _maxArmLength ) { + if ( distance < closestDistance ) { + closestDistance = distance; + _closestOtherAvatar = _numOtherAvatarsInView; + _numOtherAvatarsInView++; + } + } + } } } - */ + /* ///for testing only (prior to having real avs working) for (int o=0; o _bone[ AVATAR_BONE_RIGHT_FOOT ].radius * 2.0 ) { + _velocity += glm::dvec3( 0.0, -1.0, 0.0 ) * ( 6.0 * deltaTime ); + } + else { + if ( _bodyPosition.y < _bone[ AVATAR_BONE_RIGHT_FOOT ].radius ) { + _bodyPosition.y = _bone[ AVATAR_BONE_RIGHT_FOOT ].radius; + _velocity.y = 0.0; + } + } + } + //------------------------ // update avatar skeleton //------------------------ updateSkeleton(); - //------------------------------------------------------------------------ - // reset hand and elbow position according to hand movement - //------------------------------------------------------------------------ - if ( _handBeingMoved ){ - if (! _previousHandBeingMoved ){ - initializeBodySprings(); - _usingSprings = true; - //printLog( "just started moving hand\n" ); - } - } - else { - if ( _previousHandBeingMoved ){ - _usingSprings = false; - //printLog( "just stopped moving hand\n" ); - } - } - - if ( _handBeingMoved ) { + //------------------------------------------------------------ + // reset hand and arm positions according to hand movement + //------------------------------------------------------------ + if (_usingBodySprings) { updateHandMovement(); updateBodySprings( deltaTime ); } - - _previousHandBeingMoved = _handBeingMoved; - _handBeingMoved = false; - if ( _isMine ) { // driving the avatar around should only apply is this is my avatar (as opposed to an avatar being driven remotely) + if ( _isMine ) { // driving the avatar around should only apply if this is my avatar (as opposed to an avatar being driven remotely) //------------------------------------------------- // this handles the avatar being driven around... //------------------------------------------------- - _avatar.thrust = glm::vec3( 0.0, 0.0, 0.0 ); - + _thrust = glm::vec3( 0.0, 0.0, 0.0 ); + if (_driveKeys[FWD]) { - glm::vec3 front( _avatar.orientation.getFront().x, _avatar.orientation.getFront().y, _avatar.orientation.getFront().z ); - _avatar.thrust += front * THRUST_MAG; + glm::vec3 front( _orientation.getFront().x, _orientation.getFront().y, _orientation.getFront().z ); + _thrust += front * THRUST_MAG; } if (_driveKeys[BACK]) { - glm::vec3 front( _avatar.orientation.getFront().x, _avatar.orientation.getFront().y, _avatar.orientation.getFront().z ); - _avatar.thrust -= front * THRUST_MAG; + glm::vec3 front( _orientation.getFront().x, _orientation.getFront().y, _orientation.getFront().z ); + _thrust -= front * THRUST_MAG; } if (_driveKeys[RIGHT]) { - glm::vec3 right( _avatar.orientation.getRight().x, _avatar.orientation.getRight().y, _avatar.orientation.getRight().z ); - _avatar.thrust += right * THRUST_MAG; + glm::vec3 right( _orientation.getRight().x, _orientation.getRight().y, _orientation.getRight().z ); + _thrust += right * THRUST_MAG; } if (_driveKeys[LEFT]) { - glm::vec3 right( _avatar.orientation.getRight().x, _avatar.orientation.getRight().y, _avatar.orientation.getRight().z ); - _avatar.thrust -= right * THRUST_MAG; + glm::vec3 right( _orientation.getRight().x, _orientation.getRight().y, _orientation.getRight().z ); + _thrust -= right * THRUST_MAG; } if (_driveKeys[UP]) { - glm::vec3 up( _avatar.orientation.getUp().x, _avatar.orientation.getUp().y, _avatar.orientation.getUp().z ); - _avatar.thrust += up * THRUST_MAG; + glm::vec3 up( _orientation.getUp().x, _orientation.getUp().y, _orientation.getUp().z ); + _thrust += up * THRUST_MAG; } if (_driveKeys[DOWN]) { - glm::vec3 up( _avatar.orientation.getUp().x, _avatar.orientation.getUp().y, _avatar.orientation.getUp().z ); - _avatar.thrust -= up * THRUST_MAG; + glm::vec3 up( _orientation.getUp().x, _orientation.getUp().y, _orientation.getUp().z ); + _thrust -= up * THRUST_MAG; } if (_driveKeys[ROT_RIGHT]) { _bodyYawDelta -= YAW_MAG * deltaTime; @@ -405,7 +444,7 @@ void Head::simulate(float deltaTime) { //---------------------------------------------------------- - float translationalSpeed = glm::length( _avatar.velocity ); + float translationalSpeed = glm::length( _velocity ); float rotationalSpeed = fabs( _bodyYawDelta ); if ( translationalSpeed + rotationalSpeed > 0.2 ) { @@ -413,7 +452,7 @@ void Head::simulate(float deltaTime) { } else { - _mode = AVATAR_MODE_COMMUNICATING; + _mode = AVATAR_MODE_INTERACTING; } //---------------------------------------------------------- @@ -424,58 +463,56 @@ void Head::simulate(float deltaTime) { } // we will be eventually getting head rotation from elsewhere. For now, just setting it to body rotation - _headYaw = _bodyYaw; - _headPitch = _bodyPitch; - _headRoll = _bodyRoll; + _head.yaw = _bodyYaw; + _head.pitch = _bodyPitch; + _head.roll = _bodyRoll; //---------------------------------------------------------- // decay body yaw delta //---------------------------------------------------------- - const float TEST_YAW_DECAY = 5.0; _bodyYawDelta *= (1.0 - TEST_YAW_DECAY * deltaTime); //---------------------------------------------------------- // add thrust to velocity //---------------------------------------------------------- - _avatar.velocity += glm::dvec3(_avatar.thrust * deltaTime); + _velocity += glm::dvec3(_thrust * deltaTime); //---------------------------------------------------------- // update position by velocity //---------------------------------------------------------- - _bodyPosition += (glm::vec3)_avatar.velocity * deltaTime; + _bodyPosition += (glm::vec3)_velocity * deltaTime; //---------------------------------------------------------- // decay velocity //---------------------------------------------------------- - const float LIN_VEL_DECAY = 5.0; - _avatar.velocity *= ( 1.0 - LIN_VEL_DECAY * deltaTime ); + _velocity *= ( 1.0 - LIN_VEL_DECAY * deltaTime ); - if (!_noise) { + if (!_head.noise) { // Decay back toward center - _headPitch *= (1.0f - DECAY*2*deltaTime); - _headYaw *= (1.0f - DECAY*2*deltaTime); - _headRoll *= (1.0f - DECAY*2*deltaTime); + _head.pitch *= (1.0f - DECAY*2*deltaTime); + _head.yaw *= (1.0f - DECAY*2*deltaTime); + _head.roll *= (1.0f - DECAY*2*deltaTime); } else { // Move toward new target - _headPitch += (_pitchTarget - _headPitch)*10*deltaTime; // (1.f - DECAY*deltaTime)*Pitch + ; - _headYaw += (_yawTarget - _headYaw)*10*deltaTime; // (1.f - DECAY*deltaTime); - _headRoll *= (1.f - DECAY*deltaTime); + _head.pitch += (_head.pitchTarget - _head.pitch)*10*deltaTime; // (1.f - DECAY*deltaTime)*Pitch + ; + _head.yaw += (_head.yawTarget - _head.yaw )*10*deltaTime; // (1.f - DECAY*deltaTime); + _head.roll *= (1.f - DECAY*deltaTime); } - _leanForward *= (1.f - DECAY*30.f*deltaTime); - _leanSideways *= (1.f - DECAY*30.f*deltaTime); + _head.leanForward *= (1.f - DECAY*30.f*deltaTime); + _head.leanSideways *= (1.f - DECAY*30.f*deltaTime); // Update where the avatar's eyes are // // First, decide if we are making eye contact or not if (randFloat() < 0.005) { - _eyeContact = !_eyeContact; - _eyeContact = 1; - if (!_eyeContact) { + _head.eyeContact = !_head.eyeContact; + _head.eyeContact = 1; + if (!_head.eyeContact) { // If we just stopped making eye contact,move the eyes markedly away - _eyeballPitch[0] = _eyeballPitch[1] = _eyeballPitch[0] + 5.0 + (randFloat() - 0.5)*10; - _eyeballYaw[0] = _eyeballYaw[1] = _eyeballYaw[0] + 5.0 + (randFloat()- 0.5)*5; + _head.eyeballPitch[0] = _head.eyeballPitch[1] = _head.eyeballPitch[0] + 5.0 + (randFloat() - 0.5)*10; + _head.eyeballYaw [0] = _head.eyeballYaw [1] = _head.eyeballYaw [0] + 5.0 + (randFloat() - 0.5)*5; } else { // If now making eye contact, turn head to look right at viewer SetNewHeadTarget(0,0); @@ -485,56 +522,56 @@ void Head::simulate(float deltaTime) { const float DEGREES_BETWEEN_VIEWER_EYES = 3; const float DEGREES_TO_VIEWER_MOUTH = 7; - if (_eyeContact) { + if (_head.eyeContact) { // Should we pick a new eye contact target? if (randFloat() < 0.01) { // Choose where to look next if (randFloat() < 0.1) { - _eyeContactTarget = MOUTH; + _head.eyeContactTarget = MOUTH; } else { - if (randFloat() < 0.5) _eyeContactTarget = LEFT_EYE; else _eyeContactTarget = RIGHT_EYE; + if (randFloat() < 0.5) _head.eyeContactTarget = LEFT_EYE; else _head.eyeContactTarget = RIGHT_EYE; } } // Set eyeball pitch and yaw to make contact float eye_target_yaw_adjust = 0; float eye_target_pitch_adjust = 0; - if (_eyeContactTarget == LEFT_EYE) eye_target_yaw_adjust = DEGREES_BETWEEN_VIEWER_EYES; - if (_eyeContactTarget == RIGHT_EYE) eye_target_yaw_adjust = -DEGREES_BETWEEN_VIEWER_EYES; - if (_eyeContactTarget == MOUTH) eye_target_pitch_adjust = DEGREES_TO_VIEWER_MOUTH; + if (_head.eyeContactTarget == LEFT_EYE) eye_target_yaw_adjust = DEGREES_BETWEEN_VIEWER_EYES; + if (_head.eyeContactTarget == RIGHT_EYE) eye_target_yaw_adjust = -DEGREES_BETWEEN_VIEWER_EYES; + if (_head.eyeContactTarget == MOUTH) eye_target_pitch_adjust = DEGREES_TO_VIEWER_MOUTH; - _eyeballPitch[0] = _eyeballPitch[1] = -_headPitch + eye_target_pitch_adjust; - _eyeballYaw[0] = _eyeballYaw[1] = -_headYaw + eye_target_yaw_adjust; + _head.eyeballPitch[0] = _head.eyeballPitch[1] = -_head.pitch + eye_target_pitch_adjust; + _head.eyeballYaw[0] = _head.eyeballYaw[1] = -_head.yaw + eye_target_yaw_adjust; } - if (_noise) + if (_head.noise) { - _headPitch += (randFloat() - 0.5)*0.2*_noiseEnvelope; - _headYaw += (randFloat() - 0.5)*0.3*_noiseEnvelope; + _head.pitch += (randFloat() - 0.5)*0.2*_head.noiseEnvelope; + _head.yaw += (randFloat() - 0.5)*0.3*_head.noiseEnvelope; //PupilSize += (randFloat() - 0.5)*0.001*NoiseEnvelope; - if (randFloat() < 0.005) _mouthWidth = MouthWidthChoices[rand()%3]; + if (randFloat() < 0.005) _head.mouthWidth = MouthWidthChoices[rand()%3]; - if (!_eyeContact) { - if (randFloat() < 0.01) _eyeballPitch[0] = _eyeballPitch[1] = (randFloat() - 0.5)*20; - if (randFloat() < 0.01) _eyeballYaw[0] = _eyeballYaw[1] = (randFloat()- 0.5)*10; + if (!_head.eyeContact) { + if (randFloat() < 0.01) _head.eyeballPitch[0] = _head.eyeballPitch[1] = (randFloat() - 0.5)*20; + if (randFloat() < 0.01) _head.eyeballYaw[0] = _head.eyeballYaw[1] = (randFloat()- 0.5)*10; } - if ((randFloat() < 0.005) && (fabs(_pitchTarget - _headPitch) < 1.0) && (fabs(_yawTarget - _headYaw) < 1.0)) { + if ((randFloat() < 0.005) && (fabs(_head.pitchTarget - _head.pitch) < 1.0) && (fabs(_head.yawTarget - _head.yaw) < 1.0)) { SetNewHeadTarget((randFloat()-0.5)*20.0, (randFloat()-0.5)*45.0); } if (0) { // Pick new target - _pitchTarget = (randFloat() - 0.5)*45; - _yawTarget = (randFloat() - 0.5)*22; + _head.pitchTarget = (randFloat() - 0.5)*45; + _head.yawTarget = (randFloat() - 0.5)*22; } if (randFloat() < 0.01) { - _eyebrowPitch[0] = _eyebrowPitch[1] = BrowPitchAngle[rand()%3]; - _eyebrowRoll[0] = _eyebrowRoll[1] = BrowRollAngle[rand()%5]; - _eyebrowRoll[1]*=-1; + _head.eyebrowPitch[0] = _head.eyebrowPitch[1] = BrowPitchAngle[rand()%3]; + _head.eyebrowRoll [0] = _head.eyebrowRoll[1] = BrowRollAngle[rand()%5]; + _head.eyebrowRoll [1]*=-1; } } } @@ -556,37 +593,31 @@ void Head::updateBigSphereCollisionTest( float deltaTime ) { { for (int b=0; b 0.0) { - float amp = 1.0 - (distanceToBigSphereCenter / combinedRadius); - glm::vec3 collisionForce = vectorFromJointToBigSphere * amp; - _bone[b].springyVelocity += collisionForce * 8.0f * deltaTime; - _avatar.velocity += collisionForce * 18.0f * deltaTime; + glm::vec3 directionVector = vectorFromJointToBigSphereCenter / distanceToBigSphereCenter; + + float penetration = 1.0 - (distanceToBigSphereCenter / combinedRadius); + glm::vec3 collisionForce = vectorFromJointToBigSphereCenter * penetration; + + _bone[b].springyVelocity += collisionForce * 30.0f * deltaTime; + _velocity += collisionForce * 100.0f * deltaTime; + _bone[b].springyPosition = _TEST_bigSpherePosition + directionVector * combinedRadius; } } } if ( jointCollision ) { - //---------------------------------------------------------- - // add gravity to velocity - //---------------------------------------------------------- - _avatar.velocity += glm::dvec3( 0.0, -1.0, 0.0 ) * 0.05; - - //---------------------------------------------------------- - // ground collisions - //---------------------------------------------------------- - if ( _bodyPosition.y < 0.0 ) { - _bodyPosition.y = 0.0; - if ( _avatar.velocity.y < 0.0 ) { - _avatar.velocity.y *= -0.7; - } - } + if (!_usingBodySprings) { + _usingBodySprings = true; + initializeBodySprings(); + } } } } @@ -618,12 +649,7 @@ void Head::render(int faceToFace) { glutSolidSphere( 1, 20, 20 ); glPopMatrix(); } - - //--------------------------------------------------- - // show avatar orientation - //--------------------------------------------------- - renderOrientationDirections( _bone[ AVATAR_BONE_HEAD ].position, _bone[ AVATAR_BONE_HEAD ].orientation, 0.2f ); - + //--------------------------------------------------- // render body //--------------------------------------------------- @@ -639,25 +665,27 @@ void Head::render(int faceToFace) { //--------------------------------------------------------------------------- if ( _isMine ) { + /* //--------------------------------------------------- // render other avatars (DEBUG TEST) //--------------------------------------------------- - for (int o=0; o BROW_LIFT_THRESHOLD) - _browAudioLift += sqrt(_audioAttack)/1000.0; + if (_head.audioAttack > BROW_LIFT_THRESHOLD) + _head.browAudioLift += sqrt(_head.audioAttack)/1000.0; - _browAudioLift *= .90; + _head.browAudioLift *= .90; glPushMatrix(); - glTranslatef(-_interBrowDistance/2.0,0.4,0.45); + glTranslatef(-_head.interBrowDistance/2.0,0.4,0.45); for(side = 0; side < 2; side++) { glColor3fv(browColor); glPushMatrix(); - glTranslatef(0, 0.35 + _browAudioLift, 0); - glRotatef(_eyebrowPitch[side]/2.0, 1, 0, 0); - glRotatef(_eyebrowRoll[side]/2.0, 0, 0, 1); + glTranslatef(0, 0.35 + _head.browAudioLift, 0); + glRotatef(_head.eyebrowPitch[side]/2.0, 1, 0, 0); + glRotatef(_head.eyebrowRoll[side]/2.0, 0, 0, 1); glScalef(browWidth, browThickness, 1); glutSolidCube(0.5); glPopMatrix(); - glTranslatef(_interBrowDistance, 0, 0); + glTranslatef(_head.interBrowDistance, 0, 0); } glPopMatrix(); @@ -787,23 +775,23 @@ void Head::renderHead(int faceToFace) { glPushMatrix(); glTranslatef(0,-0.35,0.75); glColor3f(0,0,0); - glRotatef(_mouthPitch, 1, 0, 0); - glRotatef(_mouthYaw, 0, 0, 1); - glScalef(_mouthWidth*(.7 + sqrt(_averageLoudness)/60.0), _mouthHeight*(1.0 + sqrt(_averageLoudness)/30.0), 1); + glRotatef(_head.mouthPitch, 1, 0, 0); + glRotatef(_head.mouthYaw, 0, 0, 1); + glScalef(_head.mouthWidth*(.7 + sqrt(_head.averageLoudness)/60.0), _head.mouthHeight*(1.0 + sqrt(_head.averageLoudness)/30.0), 1); glutSolidCube(0.5); glPopMatrix(); glTranslatef(0, 1.0, 0); - glTranslatef(-_interPupilDistance/2.0,-0.68,0.7); + glTranslatef(-_head.interPupilDistance/2.0,-0.68,0.7); // Right Eye glRotatef(-10, 1, 0, 0); glColor3fv(eyeColor); glPushMatrix(); { - glTranslatef(_interPupilDistance/10.0, 0, 0.05); + glTranslatef(_head.interPupilDistance/10.0, 0, 0.05); glRotatef(20, 0, 0, 1); - glScalef(_eyeballScaleX, _eyeballScaleY, _eyeballScaleZ); + glScalef(_head.eyeballScaleX, _head.eyeballScaleY, _head.eyeballScaleZ); glutSolidSphere(0.25, 30, 30); } glPopMatrix(); @@ -820,40 +808,40 @@ void Head::renderHead(int faceToFace) { glPushMatrix(); { - glRotatef(_eyeballPitch[1], 1, 0, 0); - glRotatef(_eyeballYaw[1] + _pupilConverge, 0, 1, 0); + glRotatef(_head.eyeballPitch[1], 1, 0, 0); + glRotatef(_head.eyeballYaw[1] + _head.yaw + _head.pupilConverge, 0, 1, 0); glTranslatef(0,0,.35); glRotatef(-75,1,0,0); glScalef(1.0, 0.4, 1.0); glEnable(GL_TEXTURE_2D); - gluSphere(_sphere, _pupilSize, 15, 15); + gluSphere(_sphere, _head.pupilSize, 15, 15); glDisable(GL_TEXTURE_2D); } glPopMatrix(); // Left Eye glColor3fv(eyeColor); - glTranslatef(_interPupilDistance, 0, 0); + glTranslatef(_head.interPupilDistance, 0, 0); glPushMatrix(); { - glTranslatef(-_interPupilDistance/10.0, 0, .05); + glTranslatef(-_head.interPupilDistance/10.0, 0, .05); glRotatef(-20, 0, 0, 1); - glScalef(_eyeballScaleX, _eyeballScaleY, _eyeballScaleZ); + glScalef(_head.eyeballScaleX, _head.eyeballScaleY, _head.eyeballScaleZ); glutSolidSphere(0.25, 30, 30); } glPopMatrix(); // Left Pupil glPushMatrix(); { - glRotatef(_eyeballPitch[0], 1, 0, 0); - glRotatef(_eyeballYaw[0] - _pupilConverge, 0, 1, 0); + glRotatef(_head.eyeballPitch[0], 1, 0, 0); + glRotatef(_head.eyeballYaw[0] + _head.yaw - _head.pupilConverge, 0, 1, 0); glTranslatef(0, 0, .35); glRotatef(-75, 1, 0, 0); glScalef(1.0, 0.4, 1.0); glEnable(GL_TEXTURE_2D); - gluSphere(_sphere, _pupilSize, 15, 15); + gluSphere(_sphere, _head.pupilSize, 15, 15); glDisable(GL_TEXTURE_2D); } @@ -863,11 +851,19 @@ void Head::renderHead(int faceToFace) { glPopMatrix(); } - - +void Head::startHandMovement() { -void Head::setHandMovement( glm::vec3 handOffset ) { - _handBeingMoved = true; + if (!_usingBodySprings) { + initializeBodySprings(); + _usingBodySprings = true; + } +} + +void Head::stopHandMovement() { +//_usingBodySprings = false; +} + +void Head::setHandMovementValues( glm::vec3 handOffset ) { _movedHandOffset = handOffset; } @@ -875,7 +871,6 @@ AvatarMode Head::getMode() { return _mode; } - void Head::initializeSkeleton() { for (int b=0; b _avatar.maxArmLength ) { + if ( distance > _maxArmLength ) { //------------------------------------------------------------------------------- // reset right hand to be constrained to maximum arm length //------------------------------------------------------------------------------- _bone[ AVATAR_BONE_RIGHT_HAND ].position = _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position; glm::vec3 armNormal = armVector / distance; - armVector = armNormal * _avatar.maxArmLength; - distance = _avatar.maxArmLength; + armVector = armNormal * _maxArmLength; + distance = _maxArmLength; glm::vec3 constrainedPosition = _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position; constrainedPosition += armVector; _bone[ AVATAR_BONE_RIGHT_HAND ].position = constrainedPosition; @@ -1197,9 +1196,10 @@ void Head::updateHandMovement() { //----------------------------------------------------------------------------- glm::vec3 newElbowPosition = _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position; newElbowPosition += armVector * ONE_HALF; - glm::vec3 perpendicular = glm::cross( _avatar.orientation.getFront(), armVector ); +//glm::vec3 perpendicular = glm::cross( frontDirection, armVector ); + glm::vec3 perpendicular = glm::cross( _orientation.getFront(), armVector ); - newElbowPosition += perpendicular * ( 1.0f - ( _avatar.maxArmLength / distance ) ) * ONE_HALF; + newElbowPosition += perpendicular * ( 1.0f - ( _maxArmLength / distance ) ) * ONE_HALF; _bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].position = newElbowPosition; //----------------------------------------------------------------------------- @@ -1223,18 +1223,23 @@ void Head::renderBody() { // Render bone positions as spheres //----------------------------------------- for (int b=0; b #include //looks like we might not need this +const bool AVATAR_GRAVITY = true; +const float DECAY = 0.1; +const float THRUST_MAG = 10.0; +const float YAW_MAG = 300.0; +const float TEST_YAW_DECAY = 5.0; +const float LIN_VEL_DECAY = 5.0; + enum eyeContactTargets {LEFT_EYE, RIGHT_EYE, MOUTH}; #define FWD 0 @@ -34,17 +41,17 @@ enum eyeContactTargets {LEFT_EYE, RIGHT_EYE, MOUTH}; #define ROT_RIGHT 7 #define MAX_DRIVE_KEYS 8 -#define NUM_OTHER_AVATARS 5 // temporary - for testing purposes! +#define MAX_OTHER_AVATARS 50 // temporary - for testing purposes! enum AvatarMode { AVATAR_MODE_STANDING = 0, AVATAR_MODE_WALKING, - AVATAR_MODE_COMMUNICATING, + AVATAR_MODE_INTERACTING, NUM_AVATAR_MODES }; -enum AvatarBones +enum AvatarBoneID { AVATAR_BONE_NULL = -1, AVATAR_BONE_PELVIS_SPINE, // connects pelvis joint with torso joint (not supposed to be rotated) @@ -76,29 +83,63 @@ enum AvatarBones struct AvatarBone { - AvatarBones parent; // which bone is this bone connected to? - glm::vec3 position; // the position at the "end" of the bone - glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the "T-pose" - glm::vec3 springyPosition; // used for special effects (a 'flexible' variant of position) - glm::dvec3 springyVelocity; // used for special effects ( the velocity of the springy position) - float springBodyTightness; // how tightly the springy position tries to stay on the position - glm::quat rotation; // this will eventually replace yaw, pitch and roll (and maybe orientation) - float yaw; // the yaw Euler angle of the bone rotation off the parent - float pitch; // the pitch Euler angle of the bone rotation off the parent - float roll; // the roll Euler angle of the bone rotation off the parent - Orientation orientation; // three orthogonal normals determined by yaw, pitch, roll - float length; // the length of the bone - float radius; // used for detecting collisions for certain physical effects + AvatarBoneID parent; // which bone is this bone connected to? + glm::vec3 position; // the position at the "end" of the bone + glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the "T-pose" + glm::vec3 springyPosition; // used for special effects (a 'flexible' variant of position) + glm::dvec3 springyVelocity; // used for special effects ( the velocity of the springy position) + float springBodyTightness; // how tightly the springy position tries to stay on the position + glm::quat rotation; // this will eventually replace yaw, pitch and roll (and maybe orientation) + float yaw; // the yaw Euler angle of the bone rotation off the parent + float pitch; // the pitch Euler angle of the bone rotation off the parent + float roll; // the roll Euler angle of the bone rotation off the parent + Orientation orientation; // three orthogonal normals determined by yaw, pitch, roll + float length; // the length of the bone + float radius; // used for detecting collisions for certain physical effects }; -struct Avatar +struct AvatarHead { - glm::dvec3 velocity; - glm::vec3 thrust; - float maxArmLength; - Orientation orientation; + float pitch; + float yaw; + float roll; + float pitchRate; + float yawRate; + float rollRate; + float noise; + float eyeballPitch[2]; + float eyeballYaw [2]; + float eyebrowPitch[2]; + float eyebrowRoll [2]; + float eyeballScaleX; + float eyeballScaleY; + float eyeballScaleZ; + float interPupilDistance; + float interBrowDistance; + float nominalPupilSize; + float pupilSize; + float mouthPitch; + float mouthYaw; + float mouthWidth; + float mouthHeight; + float leanForward; + float leanSideways; + float pitchTarget; + float yawTarget; + float noiseEnvelope; + float pupilConverge; + float scale; + int eyeContact; + float browAudioLift; + eyeContactTargets eyeContactTarget; + + // Sound loudness information + float loudness, lastLoudness; + float averageLoudness; + float audioAttack; }; + class Head : public AvatarData { public: Head(bool isMine); @@ -106,56 +147,52 @@ class Head : public AvatarData { Head(const Head &otherHead); Head* clone() const; - void reset(); - void UpdateGyros(float frametime, SerialInterface * serialInterface, int head_mirror, glm::vec3 * gravity); - void setNoise (float mag) { _noise = mag; } - void setPitch(float p) {_headPitch = p; } - void setYaw(float y) {_headYaw = y; } - void setRoll(float r) {_headRoll = r; }; - void setScale(float s) {_scale = s; }; - void setRenderYaw(float y) {_renderYaw = y;} - void setRenderPitch(float p) {_renderPitch = p;} + void reset(); + void UpdateGyros(float frametime, SerialInterface * serialInterface, int head_mirror, glm::vec3 * gravity); + void setNoise (float mag) { _head.noise = mag; } + void setPitch(float p) {_head.pitch = p; } + void setYaw(float y) {_head.yaw = y; } + void setRoll(float r) {_head.roll = r; }; + void setScale(float s) {_head.scale = s; }; + void setRenderYaw(float y) {_renderYaw = y;} + void setRenderPitch(float p) {_renderPitch = p;} float getRenderYaw() {return _renderYaw;} float getRenderPitch() {return _renderPitch;} - void setLeanForward(float dist); - void setLeanSideways(float dist); - void addPitch(float p) {_headPitch -= p; } - void addYaw(float y){_headYaw -= y; } - void addRoll(float r){_headRoll += r; } - void addLean(float x, float z); - float getPitch() {return _headPitch;} - float getRoll() {return _headRoll;} - float getYaw() {return _headYaw;} - float getLastMeasuredYaw() {return _headYawRate;} - + void setLeanForward(float dist); + void setLeanSideways(float dist); + void addPitch(float p) {_head.pitch -= p; } + void addYaw(float y){_head.yaw -= y; } + void addRoll(float r){_head.roll += r; } + void addLean(float x, float z); + float getPitch() {return _head.pitch;} + float getRoll() {return _head.roll;} + float getYaw() {return _head.yaw;} + float getLastMeasuredYaw() {return _head.yawRate;} float getBodyYaw() {return _bodyYaw;}; - void addBodyYaw(float y) {_bodyYaw += y;}; + void addBodyYaw(float y) {_bodyYaw += y;}; glm::vec3 getHeadLookatDirection(); glm::vec3 getHeadLookatDirectionUp(); glm::vec3 getHeadLookatDirectionRight(); glm::vec3 getHeadPosition(); - glm::vec3 getBonePosition( AvatarBones b ); + glm::vec3 getBonePosition( AvatarBoneID b ); AvatarMode getMode(); - void setTriggeringAction( bool trigger ); - + void setMousePressed( bool pressed ); void render(int faceToFace); - void renderBody(); void renderHead( int faceToFace); - //void renderOrientationDirections( glm::vec3 position, Orientation orientation, float size ); - void simulate(float); - - void setHandMovement( glm::vec3 movement ); + void startHandMovement(); + void stopHandMovement(); + void setHandMovementValues( glm::vec3 movement ); void updateHandMovement(); - float getLoudness() {return _loudness;}; - float getAverageLoudness() {return _averageLoudness;}; - void setAverageLoudness(float al) {_averageLoudness = al;}; - void setLoudness(float l) {_loudness = l;}; + float getLoudness() {return _head.loudness;}; + float getAverageLoudness() {return _head.averageLoudness;}; + void setAverageLoudness(float al) {_head.averageLoudness = al;}; + void setLoudness(float l) {_head.loudness = l;}; void SetNewHeadTarget(float, float); @@ -164,9 +201,9 @@ class Head : public AvatarData { bool getDriveKeys(int key) { return _driveKeys[key]; }; // Set/Get update the thrust that will move the avatar around - void setThrust(glm::vec3 newThrust) { _avatar.thrust = newThrust; }; - void addThrust(glm::vec3 newThrust) { _avatar.thrust += newThrust; }; - glm::vec3 getThrust() { return _avatar.thrust; }; + void setThrust(glm::vec3 newThrust) { _thrust = newThrust; }; + void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; + glm::vec3 getThrust() { return _thrust; }; // // Related to getting transmitter UDP data used to animate the avatar hand @@ -176,67 +213,30 @@ class Head : public AvatarData { float getTransmitterHz() { return _transmitterHz; }; private: - bool _isMine; - float _noise; - float _headPitch; - float _headYaw; - float _headRoll; - float _headPitchRate; - float _headYawRate; - float _headRollRate; - float _eyeballPitch[2]; - float _eyeballYaw[2]; - float _eyebrowPitch[2]; - float _eyebrowRoll[2]; - float _eyeballScaleX, _eyeballScaleY, _eyeballScaleZ; - float _interPupilDistance; - float _interBrowDistance; - float _nominalPupilSize; - float _pupilSize; - float _mouthPitch; - float _mouthYaw; - float _mouthWidth; - float _mouthHeight; - float _leanForward; - float _leanSideways; - float _pitchTarget; - float _yawTarget; - float _noiseEnvelope; - float _pupilConverge; - float _scale; - - // Sound loudness information - float _loudness, _lastLoudness; - float _averageLoudness; - float _audioAttack; - float _browAudioLift; - + AvatarHead _head; + bool _isMine; glm::vec3 _TEST_bigSpherePosition; float _TEST_bigSphereRadius; - glm::vec3 _DEBUG_otherAvatarListPosition[ NUM_OTHER_AVATARS ]; - float _DEBUG_otherAvatarListTimer [ NUM_OTHER_AVATARS ]; - bool _triggeringAction; + glm::vec3 _otherAvatarHandPosition[ MAX_OTHER_AVATARS ]; + bool _mousePressed; float _bodyYawDelta; - float _closeEnoughToInteract; int _closestOtherAvatar; - bool _usingSprings; - bool _handBeingMoved; - bool _previousHandBeingMoved; + bool _usingBodySprings; glm::vec3 _movedHandOffset; float _springVelocityDecay; float _springForce; - glm::quat _rotation; // the rotation of the avatar body as a whole + glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion AvatarBone _bone[ NUM_AVATAR_BONES ]; AvatarMode _mode; - Avatar _avatar; + glm::dvec3 _velocity; + glm::vec3 _thrust; + float _maxArmLength; + Orientation _orientation; + int _numOtherAvatarsInView; int _driveKeys[MAX_DRIVE_KEYS]; - int _eyeContact; - eyeContactTargets _eyeContactTarget; - - GLUquadric *_sphere; - - float _renderYaw; - float _renderPitch; // Pitch from view frustum when this is own head. + GLUquadric* _sphere; + float _renderYaw; + float _renderPitch; // Pitch from view frustum when this is own head. // // Related to getting transmitter UDP data used to animate the avatar hand @@ -255,6 +255,8 @@ class Head : public AvatarData { void calculateBoneLengths(); void updateBigSphereCollisionTest( float deltaTime ); void readSensors(); + void renderBoneAsBlock( AvatarBoneID b ); + }; #endif diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 7b22525fde..c9e6b3186f 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -114,7 +114,7 @@ float VoxelSystem::getVoxelsBytesReadPerSecondAverage() { } -void VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { +int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { unsigned char command = *sourceBuffer; unsigned char *voxelData = sourceBuffer + 1; @@ -154,6 +154,7 @@ void VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { } setupNewVoxelsForDrawing(); + return numBytes; } void VoxelSystem::setupNewVoxelsForDrawing() { @@ -161,9 +162,8 @@ void VoxelSystem::setupNewVoxelsForDrawing() { writeVerticesEndPointer = writeVerticesArray; // call recursive function to populate in memory arrays // it will return the number of voxels added - float treeRoot[3] = {0,0,0}; + glm::vec3 treeRoot = glm::vec3(0,0,0); voxelsRendered = treeToArrays(tree->rootNode, treeRoot); - // copy the newly written data to the arrays designated for reading copyWrittenDataToReadArrays(); } @@ -176,42 +176,35 @@ void VoxelSystem::copyWrittenDataToReadArrays() { // copy the vertices and colors memcpy(readVerticesArray, writeVerticesArray, (endOfCurrentVerticesData - writeVerticesArray) * sizeof(GLfloat)); memcpy(readColorsArray, writeColorsArray, (endOfCurrentVerticesData - writeVerticesArray) * sizeof(GLubyte)); - // set the read vertices end pointer to the correct spot so the GPU knows how much to pull readVerticesEndPointer = readVerticesArray + (endOfCurrentVerticesData - writeVerticesArray); pthread_mutex_unlock(&bufferWriteLock); } -int VoxelSystem::treeToArrays(VoxelNode *currentNode, float nodePosition[3]) { +int VoxelSystem::treeToArrays(VoxelNode *currentNode, const glm::vec3& nodePosition) { int voxelsAdded = 0; float halfUnitForVoxel = powf(0.5, *currentNode->octalCode) * (0.5 * TREE_SCALE); glm::vec3 viewerPosition = viewerHead->getBodyPosition(); - // XXXBHG - Note: It appears as if the X and Z coordinates of Head or Agent are flip-flopped relative to the - // coords of the voxel space. This flip flop causes LOD behavior to be extremely odd. This is my temporary hack - // to fix this behavior. To disable this swap, set swapXandZ to false. - bool swapXandZ=true; - float viewerX = swapXandZ ? viewerPosition[2] : viewerPosition[0]; - float viewerZ = swapXandZ ? viewerPosition[0] : viewerPosition[2]; + // debug LOD code + glm::vec3 debugNodePosition; + copyFirstVertexForCode(currentNode->octalCode,(float*)&debugNodePosition); - // debugging code. - //printLog("treeToArrays() halfUnitForVoxel=%f\n",halfUnitForVoxel); - //printLog("treeToArrays() viewerPosition {x,y,z or [0],[1],[2]} ={%f,%f,%f}\n", - // viewerPosition[0],viewerPosition[1],viewerPosition[2]); - //printLog("treeToArrays() nodePosition {x,y,z or [0],[1],[2]} = {%f,%f,%f}\n", - // nodePosition[0],nodePosition[1],nodePosition[2]); - //float* vertices = firstVertexForCode(currentNode->octalCode); - //printLog("treeToArrays() firstVerticesForCode(currentNode->octalCode)={x,y,z or [0],[1],[2]} = {%f,%f,%f}\n", - // vertices[0],vertices[1],vertices[2]); - //delete []vertices; - - float distanceToVoxelCenter = sqrtf(powf(viewerX - nodePosition[0] - halfUnitForVoxel, 2) + - powf(viewerPosition[1] - nodePosition[1] - halfUnitForVoxel, 2) + - powf(viewerZ - nodePosition[2] - halfUnitForVoxel, 2)); + //printf("-----------------\n"); + //printf("halfUnitForVoxel=%f\n",halfUnitForVoxel); + //printf("viewer.x=%f y=%f z=%f \n", viewerPosition.x, viewerPosition.y, viewerPosition.z); + //printf("node.x=%f y=%f z=%f \n", nodePosition[0], nodePosition[1], nodePosition[2]); + //printf("debugNodePosition.x=%f y=%f z=%f \n", debugNodePosition[0], debugNodePosition[1], debugNodePosition[2]); - int boundaryPosition = boundaryDistanceForRenderLevel(*currentNode->octalCode + 1); - //printLog("treeToArrays() distanceToVoxelCenter=%f boundaryPosition=%d\n",distanceToVoxelCenter,boundaryPosition); + float distanceToVoxelCenter = sqrtf(powf(viewerPosition.x - nodePosition[0] - halfUnitForVoxel, 2) + + powf(viewerPosition.y - nodePosition[1] - halfUnitForVoxel, 2) + + powf(viewerPosition.z - nodePosition[2] - halfUnitForVoxel, 2)); + + int renderLevel = *currentNode->octalCode + 1; + int boundaryPosition = boundaryDistanceForRenderLevel(renderLevel); + //printLog("treeToArrays() renderLevel=%d distanceToVoxelCenter=%f boundaryPosition=%d\n", + // renderLevel,distanceToVoxelCenter,boundaryPosition); bool alwaysDraw = false; // XXXBHG - temporary debug code. Flip this to true to disable LOD blurring @@ -220,43 +213,46 @@ int VoxelSystem::treeToArrays(VoxelNode *currentNode, float nodePosition[3]) { // check if there is a child here if (currentNode->children[i] != NULL) { - // calculate the child's position based on the parent position - float childNodePosition[3]; + glm::vec3 childNodePosition; + copyFirstVertexForCode(currentNode->children[i]->octalCode,(float*)&childNodePosition); + childNodePosition *= (float)TREE_SCALE; // scale it up + /**** disabled ************************************************************************************************ + // Note: Stephen, I intentionally left this in so you would talk to me about it. Here's the deal, this code + // doesn't seem to work correctly. It returns X and Z flipped and the values are negative. Since we use the + // firstVertexForCode() function below to calculate the child vertex and that DOES work, I've decided to use + // that function to calculate our position for LOD handling. + // + // calculate the child's position based on the parent position for (int j = 0; j < 3; j++) { childNodePosition[j] = nodePosition[j]; - if (oneAtBit(branchIndexWithDescendant(currentNode->octalCode, - currentNode->children[i]->octalCode), - (7 - j))) { + if (oneAtBit(branchIndexWithDescendant(currentNode->octalCode,currentNode->children[i]->octalCode),(7 - j))) { childNodePosition[j] -= (powf(0.5, *currentNode->children[i]->octalCode) * TREE_SCALE); } } + **** disabled ************************************************************************************************/ voxelsAdded += treeToArrays(currentNode->children[i], childNodePosition); } } } - - - + // if we didn't get any voxels added then we're a leaf // add our vertex and color information to the interleaved array - if (voxelsAdded == 0 && currentNode->color[3] == 1) { - float * startVertex = firstVertexForCode(currentNode->octalCode); + if (voxelsAdded == 0 && currentNode->isColored()) { + float startVertex[3]; + copyFirstVertexForCode(currentNode->octalCode,(float*)&startVertex); float voxelScale = 1 / powf(2, *currentNode->octalCode); // populate the array with points for the 8 vertices // and RGB color for each added vertex for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) { *writeVerticesEndPointer = startVertex[j % 3] + (identityVertices[j] * voxelScale); - *(writeColorsArray + (writeVerticesEndPointer - writeVerticesArray)) = currentNode->color[j % 3]; + *(writeColorsArray + (writeVerticesEndPointer - writeVerticesArray)) = currentNode->getColor()[j % 3]; writeVerticesEndPointer++; } - voxelsAdded++; - - delete [] startVertex; } return voxelsAdded; @@ -363,4 +359,263 @@ void VoxelSystem::simulate(float deltaTime) { } +int VoxelSystem::_nodeCount = 0; +bool VoxelSystem::randomColorOperation(VoxelNode* node, bool down, void* extraData) { + + // we do our operations on the way up! + if (down) { + return true; + } + + _nodeCount++; + if (node->isColored()) { + nodeColor newColor = { 0,0,0,1 }; + newColor[0] = randomColorValue(150); + newColor[1] = randomColorValue(150); + newColor[1] = randomColorValue(150); + + //printf("randomize color node %d was %x,%x,%x NOW %x,%x,%x\n", + // _nodeCount,node->getTrueColor()[0],node->getTrueColor()[1],node->getTrueColor()[2], + // newColor[0],newColor[1],newColor[2]); + node->setColor(newColor); + } else { + //printf("not randomizing color node of %d since it has no color\n",_nodeCount); + } + return true; +} + +void VoxelSystem::randomizeVoxelColors() { + _nodeCount = 0; + tree->recurseTreeWithOperation(randomColorOperation); + printf("setting randomized true color for %d nodes\n",_nodeCount); + setupNewVoxelsForDrawing(); +} + +bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, bool down, void* extraData) { + + // we do our operations on the way up! + if (down) { + return true; + } + + _nodeCount++; + + // always false colorize + unsigned char newR = randomColorValue(150); + unsigned char newG = randomColorValue(150); + unsigned char newB = randomColorValue(150); + + printf("randomize FALSE color node %d was %x,%x,%x NOW %x,%x,%x\n", + _nodeCount,node->getTrueColor()[0],node->getTrueColor()[1],node->getTrueColor()[2], + newR,newG,newB); + node->setFalseColor(newR,newG,newB); + + return true; // keep going! +} + +void VoxelSystem::falseColorizeRandom() { + _nodeCount = 0; + tree->recurseTreeWithOperation(falseColorizeRandomOperation); + printf("setting randomized false color for %d nodes\n",_nodeCount); + setupNewVoxelsForDrawing(); +} + +bool VoxelSystem::trueColorizeOperation(VoxelNode* node, bool down, void* extraData) { + + // we do our operations on the way up! + if (down) { + return true; + } + + _nodeCount++; + node->setFalseColored(false); + //printf("setting true color for node %d\n",_nodeCount); + return true; +} + +void VoxelSystem::trueColorize() { + _nodeCount = 0; + tree->recurseTreeWithOperation(trueColorizeOperation); + printf("setting true color for %d nodes\n",_nodeCount); + setupNewVoxelsForDrawing(); +} + +// Will false colorize voxels that are not in view +bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, bool down, void* extraData) { + + // we do our operations on the way up! + if (down) { + return true; + } + + ViewFrustum* viewFrustum = (ViewFrustum*) extraData; + + _nodeCount++; + + // only do this for truely colored voxels... + if (node->isColored()) { + // first calculate the AAbox for the voxel + AABox voxelBox; + node->getAABox(voxelBox); + + voxelBox.scale(TREE_SCALE); + + printf("voxelBox corner=(%f,%f,%f) x=%f\n", + voxelBox.getCorner().x, voxelBox.getCorner().y, voxelBox.getCorner().z, + voxelBox.getSize().x); + + // If the voxel is outside of the view frustum, then false color it red + if (ViewFrustum::OUTSIDE == viewFrustum->boxInFrustum(voxelBox)) { + // Out of view voxels are colored RED + unsigned char newR = 255; + unsigned char newG = 0; + unsigned char newB = 0; + + //printf("voxel OUTSIDE view - FALSE colorizing node %d TRUE color is %x,%x,%x \n", + // _nodeCount,node->getTrueColor()[0],node->getTrueColor()[1],node->getTrueColor()[2]); + node->setFalseColor(newR,newG,newB); + } else { + printf("voxel NOT OUTSIDE view\n"); + } + } else { + printf("voxel not colored, don't consider it\n"); + } + + return true; // keep going! +} + +void VoxelSystem::falseColorizeInView(ViewFrustum* viewFrustum) { + _nodeCount = 0; + tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)viewFrustum); + printf("setting in view false color for %d nodes\n",_nodeCount); + setupNewVoxelsForDrawing(); +} + +// Will false colorize voxels based on distance from view +bool VoxelSystem::falseColorizeDistanceFromViewOperation(VoxelNode* node, bool down, void* extraData) { + + //printf("falseColorizeDistanceFromViewOperation() down=%s\n",(down ? "TRUE" : "FALSE")); + + // we do our operations on the way up! + if (down) { + return true; + } + + ViewFrustum* viewFrustum = (ViewFrustum*) extraData; + + // only do this for truly colored voxels... + if (node->isColored()) { + + // We need our distance for both up and down + glm::vec3 nodePosition; + float* startVertex = firstVertexForCode(node->octalCode); + nodePosition.x = startVertex[0]; + nodePosition.y = startVertex[1]; + nodePosition.z = startVertex[2]; + delete startVertex; + + // scale up the node position + nodePosition = nodePosition*(float)TREE_SCALE; + + float halfUnitForVoxel = powf(0.5, *node->octalCode) * (0.5 * TREE_SCALE); + glm::vec3 viewerPosition = viewFrustum->getPosition(); + + //printf("halfUnitForVoxel=%f\n",halfUnitForVoxel); + //printf("viewer.x=%f y=%f z=%f \n", viewerPosition.x, viewerPosition.y, viewerPosition.z); + //printf("node.x=%f y=%f z=%f \n", nodePosition.x, nodePosition.y, nodePosition.z); + + float distance = sqrtf(powf(viewerPosition.x - nodePosition.x - halfUnitForVoxel, 2) + + powf(viewerPosition.y - nodePosition.y - halfUnitForVoxel, 2) + + powf(viewerPosition.z - nodePosition.z - halfUnitForVoxel, 2)); + + // actually colorize + _nodeCount++; + + float distanceRatio = (_minDistance==_maxDistance) ? 1 : (distance - _minDistance)/(_maxDistance - _minDistance); + + // We want to colorize this in 16 bug chunks of color + const unsigned char maxColor = 255; + const unsigned char colorBands = 16; + const unsigned char gradientOver = 128; + unsigned char colorBand = (colorBands*distanceRatio); + unsigned char newR = (colorBand*(gradientOver/colorBands))+(maxColor-gradientOver); + unsigned char newG = 0; + unsigned char newB = 0; + //printf("Setting color down=%s distance=%f min=%f max=%f distanceRatio=%f color=%d \n", + // (down ? "TRUE" : "FALSE"), distance, _minDistance, _maxDistance, distanceRatio, (int)newR); + + node->setFalseColor(newR,newG,newB); + } else { + //printf("voxel not colored, don't consider it - down=%s\n",(down ? "TRUE" : "FALSE")); + } + return true; // keep going! +} + +float VoxelSystem::_maxDistance = 0.0; +float VoxelSystem::_minDistance = FLT_MAX; + +// Helper function will get the distance from view range, would be nice if you could just keep track +// of this as voxels are created and/or colored... seems like some transform math could do that so +// we wouldn't need to do two passes of the tree +bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, bool down, void* extraData) { + + // we do our operations on the way up! + if (down) { + return true; + } + + //printf("getDistanceFromViewRangeOperation() down=%s\n",(down ? "TRUE" : "FALSE")); + + ViewFrustum* viewFrustum = (ViewFrustum*) extraData; + + // only do this for truly colored voxels... + if (node->isColored()) { + + // We need our distance for both up and down + glm::vec3 nodePosition; + float* startVertex = firstVertexForCode(node->octalCode); + nodePosition.x = startVertex[0]; + nodePosition.y = startVertex[1]; + nodePosition.z = startVertex[2]; + delete startVertex; + + // scale up the node position + nodePosition = nodePosition*(float)TREE_SCALE; + + float halfUnitForVoxel = powf(0.5, *node->octalCode) * (0.5 * TREE_SCALE); + glm::vec3 viewerPosition = viewFrustum->getPosition(); + + float distance = sqrtf(powf(viewerPosition.x - nodePosition.x - halfUnitForVoxel, 2) + + powf(viewerPosition.y - nodePosition.y - halfUnitForVoxel, 2) + + powf(viewerPosition.z - nodePosition.z - halfUnitForVoxel, 2)); + + // on way down, calculate the range of distances + if (distance > _maxDistance) { + _maxDistance = distance; + //printf("new maxDistance=%f down=%s\n",_maxDistance, (down ? "TRUE" : "FALSE")); + } + if (distance < _minDistance) { + _minDistance = distance; + //printf("new minDistance=%f down=%s\n",_minDistance, (down ? "TRUE" : "FALSE")); + } + + _nodeCount++; + } + return true; // keep going! +} + +void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) { + _nodeCount = 0; + + _maxDistance = 0.0; + _minDistance = FLT_MAX; + tree->recurseTreeWithOperation(getDistanceFromViewRangeOperation,(void*)viewFrustum); + printf("determining distance range for %d nodes\n",_nodeCount); + + _nodeCount = 0; + + tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum); + printf("setting in distance false color for %d nodes\n",_nodeCount); + setupNewVoxelsForDrawing(); +} diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 76aaf57a4e..4c309a92ea 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -14,6 +14,7 @@ #include #include #include +#include #include "Head.h" #include "Util.h" #include "world.h" @@ -25,7 +26,7 @@ public: VoxelSystem(); ~VoxelSystem(); - void parseData(unsigned char* sourceBuffer, int numBytes); + int parseData(unsigned char* sourceBuffer, int numBytes); VoxelSystem* clone() const; void init(); @@ -44,7 +45,27 @@ public: float getVoxelsColoredPerSecondAverage(); float getVoxelsBytesReadPerSecondAverage(); + // Methods that recurse tree + void randomizeVoxelColors(); + void falseColorizeRandom(); + void trueColorize(); + void falseColorizeInView(ViewFrustum* viewFrustum); + void falseColorizeDistanceFromView(ViewFrustum* viewFrustum); + private: + // Operation functions for tree recursion methods + static int _nodeCount; + static bool randomColorOperation(VoxelNode* node, bool down, void* extraData); + static bool falseColorizeRandomOperation(VoxelNode* node, bool down, void* extraData); + static bool trueColorizeOperation(VoxelNode* node, bool down, void* extraData); + static bool falseColorizeInViewOperation(VoxelNode* node, bool down, void* extraData); + static bool falseColorizeDistanceFromViewOperation(VoxelNode* node, bool down, void* extraData); + static bool getDistanceFromViewRangeOperation(VoxelNode* node, bool down, void* extraData); + + // these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here + static float _maxDistance; + static float _minDistance; + int voxelsRendered; Head *viewerHead; VoxelTree *tree; @@ -59,7 +80,7 @@ private: GLuint vboIndicesID; pthread_mutex_t bufferWriteLock; - int treeToArrays(VoxelNode *currentNode, float nodePosition[3]); + int treeToArrays(VoxelNode *currentNode, const glm::vec3& nodePosition); void setupNewVoxelsForDrawing(); void copyWrittenDataToReadArrays(); }; diff --git a/interface/src/main.cpp b/interface/src/main.cpp index af3cb99762..66d3996e51 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -85,6 +85,7 @@ using namespace std; void reshape(int width, int height); // will be defined below +void loadViewFrustum(ViewFrustum& viewFrustum); // will be defined below pthread_t networkReceiveThread; @@ -168,15 +169,90 @@ int displayField = 0; int displayHeadMouse = 1; // Display sample mouse pointer controlled by head movement int headMouseX, headMouseY; -int mouseX, mouseY; // Where is the mouse +int mouseX = 0; +int mouseY = 0; // Mouse location at start of last down click -int mouseStartX = WIDTH / 2; -int mouseStartY = HEIGHT / 2; int mousePressed = 0; // true if mouse has been pressed (clear when finished) -Menu menu; // main menu -int menuOn = 1; // Whether to show onscreen menu +Menu menu; // main menu +int menuOn = 1; // Whether to show onscreen menu + +struct HandController +{ + bool enabled; + int startX; + int startY; + int x; + int y; + int lastX; + int lastY; + int velocityX; + int velocityY; + float rampUpRate; + float rampDownRate; + float envelope; +}; + +HandController handController; + +void initializeHandController() { + handController.enabled = false; + handController.startX = WIDTH / 2; + handController.startY = HEIGHT / 2; + handController.x = 0; + handController.y = 0; + handController.lastX = 0; + handController.lastY = 0; + handController.velocityX = 0; + handController.velocityY = 0; + handController.rampUpRate = 0.05; + handController.rampDownRate = 0.02; + handController.envelope = 0.0f; +} + +void updateHandController( int x, int y ) { + handController.lastX = handController.x; + handController.lastY = handController.y; + handController.x = x; + handController.y = y; + handController.velocityX = handController.x - handController.lastX; + handController.velocityY = handController.y - handController.lastY; + + if (( handController.velocityX != 0 ) + || ( handController.velocityY != 0 )) { + handController.enabled = true; + myAvatar.startHandMovement(); + if ( handController.envelope < 1.0 ) { + handController.envelope += handController.rampUpRate; + if ( handController.envelope >= 1.0 ) { + handController.envelope = 1.0; + } + } + } + + if ( ! handController.enabled ) { + if ( handController.envelope > 0.0 ) { + handController.envelope -= handController.rampDownRate; + if ( handController.envelope <= 0.0 ) { + handController.startX = WIDTH / 2; + handController.startY = HEIGHT / 2; + handController.envelope = 0.0; +//prototype +//myAvatar.stopHandMovement(); + } + } + } + + if ( handController.envelope > 0.0 ) { + float leftRight = ( ( handController.x - handController.startX ) / (float)WIDTH ) * handController.envelope; + float downUp = ( ( handController.y - handController.startY ) / (float)HEIGHT ) * handController.envelope; + float backFront = 0.0; + myAvatar.setHandMovementValues( glm::vec3( leftRight, downUp, backFront ) ); + } +} + + // // Serial USB Variables @@ -266,11 +342,15 @@ void displayStats(void) Agent *avatarMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER); char avatarMixerStats[200]; - sprintf(avatarMixerStats, "Avatar Mixer - %.f kbps, %.f pps", - roundf(avatarMixer->getAverageKilobitsPerSecond()), - roundf(avatarMixer->getAveragePacketsPerSecond())); + if (avatarMixer) { + sprintf(avatarMixerStats, "Avatar Mixer - %.f kbps, %.f pps", + roundf(avatarMixer->getAverageKilobitsPerSecond()), + roundf(avatarMixer->getAveragePacketsPerSecond())); + } else { + sprintf(avatarMixerStats, "No Avatar Mixer"); + } drawtext(10, statsVerticalOffset + 330, 0.10f, 0, 1.0, 0, avatarMixerStats); - + if (::perfStatsOn) { // Get the PerfStats group details. We need to allocate and array of char* long enough to hold 1+groups char** perfStatLinesArray = new char*[PerfStat::getGroupCount()+1]; @@ -304,6 +384,8 @@ void init(void) voxels.init(); voxels.setViewerHead(&myAvatar); myAvatar.setRenderYaw(startYaw); + + initializeHandController(); headMouseX = WIDTH/2; headMouseY = HEIGHT/2; @@ -369,22 +451,6 @@ void reset_sensors() } } -/* -void updateAvatarHand(float deltaTime) { - // If mouse is being dragged, send current force to the hand controller - if (mousePressed == 1) - { - // NOTE--PER: Need to re-implement when ready for new avatar hand movements - - const float MOUSE_HAND_FORCE = 1.5; - float dx = mouseX - mouseStartX; - float dy = mouseY - mouseStartY; - glm::vec3 vel(dx*MOUSE_HAND_FORCE, -dy*MOUSE_HAND_FORCE*(WIDTH/HEIGHT), 0); - //myAvatar.hand->addVelocity(vel*deltaTime); - } -} -*/ - // // Using gyro data, update both view frustum and avatar head position // @@ -457,6 +523,22 @@ void updateAvatar(float frametime) myAvatar.setAverageLoudness(averageLoudness); #endif + // Update Avatar with latest camera and view frustum data... + // NOTE: we get this from the view frustum, to make it simpler, since the + // loadViewFrumstum() method will get the correct details from the camera + // We could optimize this to not actually load the viewFrustum, since we don't + // actually need to calculate the view frustum planes to send these details + // to the server. + loadViewFrustum(::viewFrustum); + myAvatar.setCameraPosition(::viewFrustum.getPosition()); + myAvatar.setCameraDirection(::viewFrustum.getDirection()); + myAvatar.setCameraUp(::viewFrustum.getUp()); + myAvatar.setCameraRight(::viewFrustum.getRight()); + myAvatar.setCameraFov(::viewFrustum.getFieldOfView()); + myAvatar.setCameraAspectRatio(::viewFrustum.getAspectRatio()); + myAvatar.setCameraNearClip(::viewFrustum.getNearClip()); + myAvatar.setCameraFarClip(::viewFrustum.getFarClip()); + // Send my stream of head/hand data to the avatar mixer and voxel server unsigned char broadcastString[200]; *broadcastString = PACKET_HEADER_HEAD_DATA; @@ -494,34 +576,14 @@ void updateAvatar(float frametime) } ///////////////////////////////////////////////////////////////////////////////////// -// render_view_frustum() +// loadViewFrustum() // -// Description: this will render the view frustum bounds for EITHER the head +// Description: this will load the view frustum bounds for EITHER the head // or the "myCamera". // -// Frustum rendering mode. For debug purposes, we allow drawing the frustum in a couple of different ways. -// We can draw it with each of these parts: -// * Origin Direction/Up/Right vectors - these will be drawn at the point of the camera -// * Near plane - this plane is drawn very close to the origin point. -// * Right/Left planes - these two planes are drawn between the near and far planes. -// * Far plane - the plane is drawn in the distance. -// Modes - the following modes, will draw the following parts. -// * All - draws all the parts listed above -// * Planes - draws the planes but not the origin vectors -// * Origin Vectors - draws the origin vectors ONLY -// * Near Plane - draws only the near plane -// * Far Plane - draws only the far plane -#define FRUSTUM_DRAW_MODE_ALL 0 -#define FRUSTUM_DRAW_MODE_VECTORS 1 -#define FRUSTUM_DRAW_MODE_PLANES 2 -#define FRUSTUM_DRAW_MODE_NEAR_PLANE 3 -#define FRUSTUM_DRAW_MODE_FAR_PLANE 4 -#define FRUSTUM_DRAW_MODE_COUNT 5 -// These global scoped variables are used by our render_view_frustum() function below, but are also available as globals -// so that the keyboard and menu can manipulate them. - -int frustumDrawingMode = FRUSTUM_DRAW_MODE_ALL; // the mode we're drawing the frustum in, see notes above +// These global scoped variables are used by our loadViewFrustum() and renderViewFrustum functions below, but are also +// available as globals so that the keyboard and menu can manipulate them. bool frustumOn = false; // Whether or not to display the debug view frustum bool cameraFrustum = true; // which frustum to look at @@ -533,8 +595,7 @@ float viewFrustumOffsetRoll = 0.0; float viewFrustumOffsetDistance = 25.0; float viewFrustumOffsetUp = 0.0; -void render_view_frustum() { - +void loadViewFrustum(ViewFrustum& viewFrustum) { // We will use these below, from either the camera or head vectors calculated above glm::vec3 position; glm::vec3 direction; @@ -593,8 +654,44 @@ void render_view_frustum() { // Ask the ViewFrustum class to calculate our corners viewFrustum.calculate(); - - //viewFrustum.dump(); +} + +///////////////////////////////////////////////////////////////////////////////////// +// renderViewFrustum() +// +// Description: this will render the view frustum bounds for EITHER the head +// or the "myCamera". +// +// Frustum rendering mode. For debug purposes, we allow drawing the frustum in a couple of different ways. +// We can draw it with each of these parts: +// * Origin Direction/Up/Right vectors - these will be drawn at the point of the camera +// * Near plane - this plane is drawn very close to the origin point. +// * Right/Left planes - these two planes are drawn between the near and far planes. +// * Far plane - the plane is drawn in the distance. +// Modes - the following modes, will draw the following parts. +// * All - draws all the parts listed above +// * Planes - draws the planes but not the origin vectors +// * Origin Vectors - draws the origin vectors ONLY +// * Near Plane - draws only the near plane +// * Far Plane - draws only the far plane +#define FRUSTUM_DRAW_MODE_ALL 0 +#define FRUSTUM_DRAW_MODE_VECTORS 1 +#define FRUSTUM_DRAW_MODE_PLANES 2 +#define FRUSTUM_DRAW_MODE_NEAR_PLANE 3 +#define FRUSTUM_DRAW_MODE_FAR_PLANE 4 +#define FRUSTUM_DRAW_MODE_COUNT 5 + +int frustumDrawingMode = FRUSTUM_DRAW_MODE_ALL; // the mode we're drawing the frustum in, see notes above + +void renderViewFrustum(ViewFrustum& viewFrustum) { + + // Load it with the latest details! + loadViewFrustum(viewFrustum); + + glm::vec3 position = viewFrustum.getPosition(); + glm::vec3 direction = viewFrustum.getDirection(); + glm::vec3 up = viewFrustum.getUp(); + glm::vec3 right = viewFrustum.getRight(); // Get ready to draw some lines glDisable(GL_LIGHTING); @@ -722,18 +819,16 @@ void display(void) //-------------------------------------------------------- // camera settings //-------------------------------------------------------- - myCamera.setTargetPosition( myAvatar.getBodyPosition() ); - if ( displayHead ) { //----------------------------------------------- // set the camera to looking at my own face //----------------------------------------------- - myCamera.setTargetPosition ( myAvatar.getBodyPosition() ); // XXXBHG - Shouldn't we use Head position here? + myCamera.setTargetPosition ( myAvatar.getHeadPosition() ); myCamera.setYaw ( - myAvatar.getBodyYaw() ); - myCamera.setPitch ( 0.0 ); - myCamera.setRoll ( 0.0 ); - myCamera.setUp ( 0.6 ); - myCamera.setDistance ( 0.3 ); + myCamera.setPitch ( 0.0 ); + myCamera.setRoll ( 0.0 ); + myCamera.setUp ( 0.0 ); + myCamera.setDistance ( 0.2 ); myCamera.setTightness ( 100.0f ); myCamera.update ( 1.f/FPS ); } else { @@ -742,12 +837,12 @@ void display(void) //---------------------------------------------------- myCamera.setTargetPosition ( myAvatar.getBodyPosition() ); myCamera.setYaw ( 180.0 - myAvatar.getBodyYaw() ); - myCamera.setPitch ( 0.0 ); // temporarily, this must be 0.0 or else bad juju - myCamera.setRoll ( 0.0 ); - myCamera.setUp ( 0.45); - myCamera.setDistance ( 1.0 ); - myCamera.setTightness ( 10.0f ); - myCamera.update ( 1.f/FPS ); + myCamera.setPitch ( 0.0 ); // temporarily, this must be 0.0 or else bad juju + myCamera.setRoll ( 0.0 ); + myCamera.setUp ( 0.45 ); + myCamera.setDistance ( 1.0 ); + myCamera.setTightness ( 8.0f ); + myCamera.update ( 1.f/FPS); } // Note: whichCamera is used to pick between the normal camera myCamera for our @@ -755,7 +850,7 @@ void display(void) // is the viewFrustumOffsetCamera. But theoretically, we could use this same mechanism // to add other cameras. // - // Why have two cameras? Well, one reason is that because in the case of the render_view_frustum() + // Why have two cameras? Well, one reason is that because in the case of the renderViewFrustum() // code, we want to keep the state of "myCamera" intact, so we can render what the view frustum of // myCamera is. But we also want to do meaningful camera transforms on OpenGL for the offset camera Camera whichCamera = myCamera; @@ -811,14 +906,12 @@ void display(void) float sphereRadius = 0.25f; glColor3f(1,0,0); glPushMatrix(); - //glTranslatef( 0.0f, sphereRadius, 0.0f ); glutSolidSphere( sphereRadius, 15, 15 ); glPopMatrix(); //draw a grid gound plane.... drawGroundPlaneGrid( 5.0f, 9 ); - // Draw cloud of dots if (!displayHead) cloud.render(); @@ -836,11 +929,9 @@ void display(void) for(std::vector::iterator agent = agentList->getAgents().begin(); agent != agentList->getAgents().end(); agent++) { - if (agent->getLinkedData() != NULL) { - Head *agentHead = (Head *)agent->getLinkedData(); - glPushMatrix(); - agentHead->render(0); - glPopMatrix(); + if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) { + Head *avatar = (Head *)agent->getLinkedData(); + avatar->render(0); } } @@ -850,7 +941,7 @@ void display(void) if (!displayHead && statsOn) render_world_box(); // brad's frustum for debugging - if (::frustumOn) render_view_frustum(); + if (::frustumOn) renderViewFrustum(::viewFrustum); //Render my own avatar myAvatar.render(true); @@ -904,11 +995,18 @@ void display(void) menu.render(WIDTH,HEIGHT); } - // Draw number of nearby people always + // Stats at upper right of screen about who domain server is telling us about glPointSize(1.0f); char agents[100]; - sprintf(agents, "Agents: %ld\n", AgentList::getInstance()->getAgents().size()); - drawtext(WIDTH-100,20, 0.10, 0, 1.0, 0, agents, 1, 0, 0); + + int totalAgents = AgentList::getInstance()->getAgents().size(); + int totalAvatars = 0, totalServers = 0; + for (int i = 0; i < totalAgents; i++) { + (AgentList::getInstance()->getAgents()[i].getType() == AGENT_TYPE_AVATAR) + ? totalAvatars++ : totalServers++; + } + sprintf(agents, "Servers: %d, Avatars: %d\n", totalServers, totalAvatars); + drawtext(WIDTH-150,20, 0.10, 0, 1.0, 0, agents, 1, 0, 0); if (::paintOn) { @@ -1030,6 +1128,46 @@ int setFrustumRenderMode(int state) { return ::frustumDrawingMode; } +int doRandomizeVoxelColors(int state) { + if (state == MENU_ROW_PICKED) { + ::voxels.randomizeVoxelColors(); + } + return state; +} + + +int doFalseRandomizeVoxelColors(int state) { + if (state == MENU_ROW_PICKED) { + ::voxels.falseColorizeRandom(); + } + return state; +} + +int doTrueVoxelColors(int state) { + if (state == MENU_ROW_PICKED) { + ::voxels.trueColorize(); + } + return state; +} + +int doFalseColorizeByDistance(int state) { + if (state == MENU_ROW_PICKED) { + loadViewFrustum(::viewFrustum); + voxels.falseColorizeDistanceFromView(&::viewFrustum); + } + return state; +} + +int doFalseColorizeInView(int state) { + if (state == MENU_ROW_PICKED) { + loadViewFrustum(::viewFrustum); + // we probably want to make sure the viewFrustum is initialized first + voxels.falseColorizeInView(&::viewFrustum); + } + return state; +} + + const char* modeAll = " - All "; const char* modeVectors = " - Vectors "; const char* modePlanes = " - Planes "; @@ -1084,7 +1222,11 @@ void initMenu() { // Debug menuColumnDebug = menu.addColumn("Debug"); - + menuColumnDebug->addRow("Randomize Voxel TRUE Colors", doRandomizeVoxelColors); + menuColumnDebug->addRow("FALSE Color Voxels Randomly", doFalseRandomizeVoxelColors); + menuColumnDebug->addRow("FALSE Color Voxels by Distance", doFalseColorizeByDistance); + menuColumnDebug->addRow("FALSE Color Voxel Out of View", doFalseColorizeInView); + menuColumnDebug->addRow("Show TRUE Colors", doTrueVoxelColors); } void testPointToVoxel() @@ -1248,7 +1390,7 @@ void key(unsigned char k, int x, int y) // if (k == '\\') ViewFrustum::fovAngleAdust += 0.05; if (k == 'R') setFrustumRenderMode(MENU_ROW_PICKED); - + if (k == '&') { ::paintOn = !::paintOn; // toggle paint ::setupPaintingVoxel(); // also randomizes colors @@ -1267,7 +1409,6 @@ void key(unsigned char k, int x, int y) { myAvatar.setNoise(0); } - } if (k == 'h') { @@ -1316,8 +1457,7 @@ void *networkReceive(void *args) case PACKET_HEADER_BULK_AVATAR_DATA: AgentList::getInstance()->processBulkAgentData(&senderAddress, incomingPacket, - bytesReceived, - BYTES_PER_AVATAR); + bytesReceived); break; default: AgentList::getInstance()->processAgentData(&senderAddress, incomingPacket, bytesReceived); @@ -1339,40 +1479,29 @@ void idle(void) { if (diffclock(&lastTimeIdle, &check) > IDLE_SIMULATE_MSECS) { - //if ( myAvatar.getMode() == AVATAR_MODE_COMMUNICATING ) { - float leftRight = ( mouseX - mouseStartX ) / (float)WIDTH; - float downUp = ( mouseY - mouseStartY ) / (float)HEIGHT; - float backFront = 0.0; - glm::vec3 handMovement( leftRight, downUp, backFront ); - myAvatar.setHandMovement( handMovement ); - /*} - else { - mouseStartX = mouseX; - mouseStartY = mouseY; - //mouseStartX = (float)WIDTH / 2.0f; - //mouseStartY = (float)HEIGHT / 2.0f; - } - */ - - //-------------------------------------------------------- - // when the mouse is being pressed, an 'action' is being - // triggered in the avatar. The action is context-based. - //-------------------------------------------------------- + float deltaTime = 1.f/FPS; + + // update behaviors for avatar hand movement + updateHandController( mouseX, mouseY ); + + // tell my avatar if the mouse is being pressed... if ( mousePressed == 1 ) { - myAvatar.setTriggeringAction( true ); + myAvatar.setMousePressed( true ); } else { - myAvatar.setTriggeringAction( false ); + myAvatar.setMousePressed( false ); + } + + // walking triggers the handController to stop + if ( myAvatar.getMode() == AVATAR_MODE_WALKING ) { + handController.enabled = false; } - float deltaTime = 1.f/FPS; - // // Sample hardware, update view frustum if needed, Lsend avatar data to mixer/agents // - updateAvatar( 1.f/FPS ); + updateAvatar(deltaTime); - //loop through all the other avatars and simulate them. AgentList * agentList = AgentList::getInstance(); for(std::vector::iterator agent = agentList->getAgents().begin(); agent != agentList->getAgents().end(); agent++) @@ -1383,9 +1512,6 @@ void idle(void) { avatar->simulate(deltaTime); } } - - - //updateAvatarHand(1.f/FPS); field.simulate (deltaTime); myAvatar.simulate(deltaTime); @@ -1464,8 +1590,6 @@ void mouseFunc( int button, int state, int x, int y ) mouseX = x; mouseY = y; mousePressed = 1; - //mouseStartX = x; - //mouseStartY = y; } } if( button == GLUT_LEFT_BUTTON && state == GLUT_UP ) { @@ -1485,12 +1609,15 @@ void motionFunc( int x, int y) void mouseoverFunc( int x, int y) { menu.mouseOver(x, y); + mouseX = x; mouseY = y; if (mousePressed == 0) {} } + + void attachNewHeadToAgent(Agent *newAgent) { if (newAgent->getLinkedData() == NULL) { newAgent->setLinkedData(new Head(false)); @@ -1515,7 +1642,7 @@ int main(int argc, const char * argv[]) return EXIT_SUCCESS; } - AgentList::createInstance(AGENT_TYPE_INTERFACE); + AgentList::createInstance(AGENT_TYPE_AVATAR); gettimeofday(&applicationStartupTime, NULL); const char* domainIP = getCmdOption(argc, argv, "--domain"); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index f3ec0a31b0..d644937464 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -36,7 +36,15 @@ int unpackFloatAngleFromTwoByte(uint16_t* byteAnglePointer, float* destinationPo AvatarData::AvatarData() : _bodyYaw(-90.0), _bodyPitch(0.0), - _bodyRoll(0.0) { + _bodyRoll(0.0), + _cameraPosition(0,0,0), + _cameraDirection(0,0,0), + _cameraUp(0,0,0), + _cameraRight(0,0,0), + _cameraFov(0.0f), + _cameraAspectRatio(0.0f), + _cameraNearClip(0.0f), + _cameraFarClip(0.0f) { } @@ -64,17 +72,36 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { memcpy(destinationBuffer, &_handPosition, sizeof(float) * 3); destinationBuffer += sizeof(float) * 3; - - //printLog("%f, %f, %f\n", _handPosition.x, _handPosition.y, _handPosition.z); - + + // camera details + memcpy(destinationBuffer, &_cameraPosition, sizeof(_cameraPosition)); + destinationBuffer += sizeof(_cameraPosition); + memcpy(destinationBuffer, &_cameraDirection, sizeof(_cameraDirection)); + destinationBuffer += sizeof(_cameraDirection); + memcpy(destinationBuffer, &_cameraRight, sizeof(_cameraRight)); + destinationBuffer += sizeof(_cameraRight); + memcpy(destinationBuffer, &_cameraUp, sizeof(_cameraUp)); + destinationBuffer += sizeof(_cameraUp); + memcpy(destinationBuffer, &_cameraFov, sizeof(_cameraFov)); + destinationBuffer += sizeof(_cameraFov); + memcpy(destinationBuffer, &_cameraAspectRatio, sizeof(_cameraAspectRatio)); + destinationBuffer += sizeof(_cameraAspectRatio); + memcpy(destinationBuffer, &_cameraNearClip, sizeof(_cameraNearClip)); + destinationBuffer += sizeof(_cameraNearClip); + memcpy(destinationBuffer, &_cameraFarClip, sizeof(_cameraFarClip)); + destinationBuffer += sizeof(_cameraFarClip); + return destinationBuffer - bufferStart; } // called on the other agents - assigns it to my views of the others -void AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { +int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { + // increment to push past the packet header sourceBuffer++; + unsigned char* startPosition = sourceBuffer; + memcpy(&_bodyPosition, sourceBuffer, sizeof(float) * 3); sourceBuffer += sizeof(float) * 3; @@ -85,10 +112,25 @@ void AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { memcpy(&_handPosition, sourceBuffer, sizeof(float) * 3); sourceBuffer += sizeof(float) * 3; - //printLog( "_bodyYaw = %f", _bodyYaw ); - - //printLog("%f, %f, %f\n", _handPosition.x, _handPosition.y, _handPosition.z); - //printLog("%f, %f, %f\n", _bodyPosition.x, _bodyPosition.y, _bodyPosition.z); + // camera details + memcpy(&_cameraPosition, sourceBuffer, sizeof(_cameraPosition)); + sourceBuffer += sizeof(_cameraPosition); + memcpy(&_cameraDirection, sourceBuffer, sizeof(_cameraDirection)); + sourceBuffer += sizeof(_cameraDirection); + memcpy(&_cameraRight, sourceBuffer, sizeof(_cameraRight)); + sourceBuffer += sizeof(_cameraRight); + memcpy(&_cameraUp, sourceBuffer, sizeof(_cameraUp)); + sourceBuffer += sizeof(_cameraUp); + memcpy(&_cameraFov, sourceBuffer, sizeof(_cameraFov)); + sourceBuffer += sizeof(_cameraFov); + memcpy(&_cameraAspectRatio, sourceBuffer, sizeof(_cameraAspectRatio)); + sourceBuffer += sizeof(_cameraAspectRatio); + memcpy(&_cameraNearClip, sourceBuffer, sizeof(_cameraNearClip)); + sourceBuffer += sizeof(_cameraNearClip); + memcpy(&_cameraFarClip, sourceBuffer, sizeof(_cameraFarClip)); + sourceBuffer += sizeof(_cameraFarClip); + + return sourceBuffer - startPosition; } glm::vec3 AvatarData::getBodyPosition() { diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 22186c81a6..ea735c62fe 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -13,8 +13,6 @@ #include -const int BYTES_PER_AVATAR = 30; - class AvatarData : public AgentData { public: AvatarData(); @@ -27,7 +25,7 @@ public: void setHandPosition(glm::vec3 handPosition); int getBroadcastData(unsigned char* destinationBuffer); - void parseData(unsigned char* sourceBuffer, int numBytes); + int parseData(unsigned char* sourceBuffer, int numBytes); float getBodyYaw(); void setBodyYaw(float bodyYaw); @@ -37,6 +35,26 @@ public: float getBodyRoll(); void setBodyRoll(float bodyRoll); + + // getters for camera details + const glm::vec3& getCameraPosition() const { return _cameraPosition; }; + const glm::vec3& getCameraDirection() const { return _cameraDirection; } + const glm::vec3& getCameraUp() const { return _cameraUp; } + const glm::vec3& getCameraRight() const { return _cameraRight; } + float getCameraFov() const { return _cameraFov; } + float getCameraAspectRatio() const { return _cameraAspectRatio; } + float getCameraNearClip() const { return _cameraNearClip; } + float getCameraFarClip() const { return _cameraFarClip; } + + // setters for camera details + void setCameraPosition(const glm::vec3& position) { _cameraPosition = position; }; + void setCameraDirection(const glm::vec3& direction) { _cameraDirection = direction; } + void setCameraUp(const glm::vec3& up) { _cameraUp = up; } + void setCameraRight(const glm::vec3& right) { _cameraRight = right; } + void setCameraFov(float fov) { _cameraFov = fov; } + void setCameraAspectRatio(float aspectRatio) { _cameraAspectRatio = aspectRatio; } + void setCameraNearClip(float nearClip) { _cameraNearClip = nearClip; } + void setCameraFarClip(float farClip) { _cameraFarClip = farClip; } protected: glm::vec3 _bodyPosition; @@ -45,6 +63,18 @@ protected: float _bodyYaw; float _bodyPitch; float _bodyRoll; + + // camera details for the avatar + glm::vec3 _cameraPosition; + + // can we describe this in less space? For example, a Quaternion? or Euler angles? + glm::vec3 _cameraDirection; + glm::vec3 _cameraUp; + glm::vec3 _cameraRight; + float _cameraFov; + float _cameraAspectRatio; + float _cameraNearClip; + float _cameraFarClip; }; #endif /* defined(__hifi__AvatarData__) */ diff --git a/libraries/avatars/src/Orientation.cpp b/libraries/avatars/src/Orientation.cpp index 1cedb7305e..066c1edc58 100755 --- a/libraries/avatars/src/Orientation.cpp +++ b/libraries/avatars/src/Orientation.cpp @@ -20,8 +20,7 @@ using avatars_lib::printLog; // // tosh - yep, I noticed... :-) // -// JJV - I noticed too :-) -// + static bool testingForNormalizationAndOrthogonality = false; Orientation::Orientation() { diff --git a/libraries/shared/src/Agent.cpp b/libraries/shared/src/Agent.cpp index d05afe5e26..bb49783210 100644 --- a/libraries/shared/src/Agent.cpp +++ b/libraries/shared/src/Agent.cpp @@ -23,11 +23,19 @@ using shared_lib::printLog; Agent::Agent(sockaddr *agentPublicSocket, sockaddr *agentLocalSocket, char agentType, uint16_t thisAgentId) { - publicSocket = new sockaddr; - memcpy(publicSocket, agentPublicSocket, sizeof(sockaddr)); + if (agentPublicSocket != NULL) { + publicSocket = new sockaddr; + memcpy(publicSocket, agentPublicSocket, sizeof(sockaddr)); + } else { + publicSocket = NULL; + } - localSocket = new sockaddr; - memcpy(localSocket, agentLocalSocket, sizeof(sockaddr)); + if (agentLocalSocket != NULL) { + localSocket = new sockaddr; + memcpy(localSocket, agentLocalSocket, sizeof(sockaddr)); + } else { + localSocket = NULL; + } type = agentType; agentId = thisAgentId; @@ -44,11 +52,19 @@ Agent::Agent(sockaddr *agentPublicSocket, sockaddr *agentLocalSocket, char agent } Agent::Agent(const Agent &otherAgent) { - publicSocket = new sockaddr; - memcpy(publicSocket, otherAgent.publicSocket, sizeof(sockaddr)); + if (otherAgent.publicSocket != NULL) { + publicSocket = new sockaddr; + memcpy(publicSocket, otherAgent.publicSocket, sizeof(sockaddr)); + } else { + publicSocket = NULL; + } - localSocket = new sockaddr; - memcpy(localSocket, otherAgent.localSocket, sizeof(sockaddr)); + if (otherAgent.localSocket != NULL) { + localSocket = new sockaddr; + memcpy(localSocket, otherAgent.localSocket, sizeof(sockaddr)); + } else { + localSocket = NULL; + } agentId = otherAgent.agentId; @@ -132,7 +148,7 @@ const char* Agent::getTypeName() const { case AGENT_TYPE_VOXEL: name = AGENT_TYPE_NAME_VOXEL; break; - case AGENT_TYPE_INTERFACE: + case AGENT_TYPE_AVATAR: name = AGENT_TYPE_NAME_INTERFACE; break; case AGENT_TYPE_AUDIO_MIXER: @@ -248,18 +264,27 @@ void Agent::printLog(Agent const& agent) { sockaddr_in *agentPublicSocket = (sockaddr_in *) agent.publicSocket; sockaddr_in *agentLocalSocket = (sockaddr_in *) agent.localSocket; - - ::printLog("T: %s (%c) PA: %s:%d LA: %s:%d\n", agent.getTypeName(), agent.type, - inet_ntoa(agentPublicSocket->sin_addr), ntohs(agentPublicSocket->sin_port), - inet_ntoa(agentLocalSocket->sin_addr), ntohs(agentLocalSocket->sin_port)); -} - -std::ostream& operator<<(std::ostream& os, const Agent* agent) { - sockaddr_in *agentPublicSocket = (sockaddr_in *)agent->publicSocket; - sockaddr_in *agentLocalSocket = (sockaddr_in *)agent->localSocket; - os << "T: " << agent->getTypeName() << " (" << agent->type << ") PA: " << inet_ntoa(agentPublicSocket->sin_addr) << - ":" << ntohs(agentPublicSocket->sin_port) << " LA: " << inet_ntoa(agentLocalSocket->sin_addr) << - ":" << ntohs(agentLocalSocket->sin_port); - return os; + const char* publicAddressString = (agentPublicSocket == NULL) + ? "Unknown" + : inet_ntoa(agentPublicSocket->sin_addr); + unsigned short publicAddressPort = (agentPublicSocket == NULL) + ? 0 + : ntohs(agentPublicSocket->sin_port); + + const char* localAddressString = (agentLocalSocket == NULL) + ? "Unknown" + : inet_ntoa(agentLocalSocket->sin_addr); + unsigned short localAddressPort = (agentLocalSocket == NULL) + ? 0 + : ntohs(agentPublicSocket->sin_port); + + ::printLog("ID: %d T: %s (%c) PA: %s:%d LA: %s:%d\n", + agent.agentId, + agent.getTypeName(), + agent.type, + publicAddressString, + publicAddressPort, + localAddressString, + localAddressPort); } \ No newline at end of file diff --git a/libraries/shared/src/Agent.h b/libraries/shared/src/Agent.h index 14942defcb..b1d2347c21 100644 --- a/libraries/shared/src/Agent.h +++ b/libraries/shared/src/Agent.h @@ -63,7 +63,6 @@ public: float getAveragePacketsPerSecond(); static void printLog(Agent const&); - friend std::ostream& operator<<(std::ostream& os, const Agent* agent); private: void swap(Agent &first, Agent &second); diff --git a/libraries/shared/src/AgentData.h b/libraries/shared/src/AgentData.h index 640798b52b..f8bef16b41 100644 --- a/libraries/shared/src/AgentData.h +++ b/libraries/shared/src/AgentData.h @@ -12,7 +12,7 @@ class AgentData { public: virtual ~AgentData() = 0; - virtual void parseData(unsigned char* sourceBuffer, int numBytes) = 0; + virtual int parseData(unsigned char* sourceBuffer, int numBytes) = 0; virtual AgentData* clone() const = 0; }; diff --git a/libraries/shared/src/AgentList.cpp b/libraries/shared/src/AgentList.cpp index 5316eee79c..5744c0780a 100644 --- a/libraries/shared/src/AgentList.cpp +++ b/libraries/shared/src/AgentList.cpp @@ -106,7 +106,7 @@ void AgentList::processAgentData(sockaddr *senderAddress, unsigned char *packetD } } -void AgentList::processBulkAgentData(sockaddr *senderAddress, unsigned char *packetData, int numTotalBytes, int numBytesPerAgent) { +void AgentList::processBulkAgentData(sockaddr *senderAddress, unsigned char *packetData, int numTotalBytes) { // find the avatar mixer in our agent list and update the lastRecvTime from it int bulkSendAgentIndex = indexOfMatchingAgent(senderAddress); @@ -118,7 +118,7 @@ void AgentList::processBulkAgentData(sockaddr *senderAddress, unsigned char *pac unsigned char *startPosition = packetData; unsigned char *currentPosition = startPosition + 1; - unsigned char packetHolder[numBytesPerAgent + 1]; + unsigned char packetHolder[numTotalBytes]; packetHolder[0] = PACKET_HEADER_HEAD_DATA; @@ -126,39 +126,49 @@ void AgentList::processBulkAgentData(sockaddr *senderAddress, unsigned char *pac while ((currentPosition - startPosition) < numTotalBytes) { currentPosition += unpackAgentId(currentPosition, &agentID); - memcpy(packetHolder + 1, currentPosition, numBytesPerAgent); + memcpy(packetHolder + 1, currentPosition, numTotalBytes - (currentPosition - startPosition)); int matchingAgentIndex = indexOfMatchingAgent(agentID); - if (matchingAgentIndex >= 0) { + if (matchingAgentIndex < 0) { + // we're missing this agent, we need to add it to the list + addOrUpdateAgent(NULL, NULL, AGENT_TYPE_AVATAR, agentID); - updateAgentWithData(&agents[matchingAgentIndex], packetHolder, numBytesPerAgent + 1); + // theoretically if we can lock the vector we could assume this is size - 1 + matchingAgentIndex = indexOfMatchingAgent(agentID); } - currentPosition += numBytesPerAgent; + currentPosition += updateAgentWithData(&agents[matchingAgentIndex], + packetHolder, + numTotalBytes - (currentPosition - startPosition)); } } -void AgentList::updateAgentWithData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes) { +int AgentList::updateAgentWithData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes) { // find the agent by the sockaddr int agentIndex = indexOfMatchingAgent(senderAddress); if (agentIndex != -1) { - updateAgentWithData(&agents[agentIndex], packetData, dataBytes); + return updateAgentWithData(&agents[agentIndex], packetData, dataBytes); + } else { + return 0; } } -void AgentList::updateAgentWithData(Agent *agent, unsigned char *packetData, int dataBytes) { +int AgentList::updateAgentWithData(Agent *agent, unsigned char *packetData, int dataBytes) { agent->setLastRecvTimeUsecs(usecTimestampNow()); - agent->recordBytesReceived(dataBytes); + + if (agent->getActiveSocket() != NULL) { + agent->recordBytesReceived(dataBytes); + } if (agent->getLinkedData() == NULL) { if (linkedDataCreateCallback != NULL) { linkedDataCreateCallback(agent); } } - - agent->getLinkedData()->parseData(packetData, dataBytes); + + return agent->getLinkedData()->parseData(packetData, dataBytes); } int AgentList::indexOfMatchingAgent(sockaddr *senderAddress) { @@ -173,7 +183,7 @@ int AgentList::indexOfMatchingAgent(sockaddr *senderAddress) { int AgentList::indexOfMatchingAgent(uint16_t agentID) { for(std::vector::iterator agent = agents.begin(); agent != agents.end(); agent++) { - if (agent->getActiveSocket() != NULL && agent->getAgentId() == agentID) { + if (agent->getAgentId() == agentID) { return agent - agents.begin(); } } @@ -219,16 +229,19 @@ int AgentList::updateList(unsigned char *packetData, size_t dataBytes) { bool AgentList::addOrUpdateAgent(sockaddr *publicSocket, sockaddr *localSocket, char agentType, uint16_t agentId) { std::vector::iterator agent; - for (agent = agents.begin(); agent != agents.end(); agent++) { - if (agent->matches(publicSocket, localSocket, agentType)) { - // we already have this agent, stop checking - break; + if (publicSocket != NULL) { + for (agent = agents.begin(); agent != agents.end(); agent++) { + if (agent->matches(publicSocket, localSocket, agentType)) { + // we already have this agent, stop checking + break; + } } + } else { + agent = agents.end(); } if (agent == agents.end()) { // we didn't have this agent, so add them - Agent newAgent = Agent(publicSocket, localSocket, agentType, agentId); if (socketMatch(publicSocket, localSocket)) { @@ -281,7 +294,7 @@ void AgentList::broadcastToAgents(unsigned char *broadcastData, size_t dataBytes void AgentList::handlePingReply(sockaddr *agentAddress) { for(std::vector::iterator agent = agents.begin(); agent != agents.end(); agent++) { // check both the public and local addresses for each agent to see if we find a match - // prioritize the private address so that we prune erroneous local matches + // prioritize the private address so that we prune erroneous local matches if (socketMatch(agent->getPublicSocket(), agentAddress)) { agent->activatePublicSocket(); break; @@ -317,7 +330,8 @@ void *pingUnknownAgents(void *args) { for(std::vector::iterator agent = agentList->getAgents().begin(); agent != agentList->getAgents().end(); agent++) { - if (agent->getActiveSocket() == NULL) { + if (agent->getActiveSocket() == NULL + && (agent->getPublicSocket() != NULL && agent->getLocalSocket() != NULL)) { // ping both of the sockets for the agent so we can figure out // which socket we can use agentList->getAgentSocket().send(agent->getPublicSocket(), &PACKET_HEADER_PING, 1); diff --git a/libraries/shared/src/AgentList.h b/libraries/shared/src/AgentList.h index adc66333f9..f62d527116 100644 --- a/libraries/shared/src/AgentList.h +++ b/libraries/shared/src/AgentList.h @@ -50,10 +50,10 @@ public: bool addOrUpdateAgent(sockaddr *publicSocket, sockaddr *localSocket, char agentType, uint16_t agentId); void processAgentData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes); - void processBulkAgentData(sockaddr *senderAddress, unsigned char *packetData, int numTotalBytes, int numBytesPerAgent); + void processBulkAgentData(sockaddr *senderAddress, unsigned char *packetData, int numTotalBytes); - void updateAgentWithData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes); - void updateAgentWithData(Agent *agent, unsigned char *packetData, int dataBytes); + int updateAgentWithData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes); + int updateAgentWithData(Agent *agent, unsigned char *packetData, int dataBytes); void broadcastToAgents(unsigned char *broadcastData, size_t dataBytes, const char* agentTypes, int numAgentTypes); char getOwnerType(); diff --git a/libraries/shared/src/AgentTypes.h b/libraries/shared/src/AgentTypes.h index a5d79efac8..c43af79446 100644 --- a/libraries/shared/src/AgentTypes.h +++ b/libraries/shared/src/AgentTypes.h @@ -20,7 +20,7 @@ // Agent Type Codes const char AGENT_TYPE_DOMAIN = 'D'; const char AGENT_TYPE_VOXEL = 'V'; -const char AGENT_TYPE_INTERFACE = 'I'; // could also be injector??? +const char AGENT_TYPE_AVATAR = 'I'; // could also be injector??? const char AGENT_TYPE_AUDIO_MIXER = 'M'; const char AGENT_TYPE_AVATAR_MIXER = 'W'; diff --git a/libraries/shared/src/AudioRingBuffer.cpp b/libraries/shared/src/AudioRingBuffer.cpp index 2197d03706..5180e238cb 100644 --- a/libraries/shared/src/AudioRingBuffer.cpp +++ b/libraries/shared/src/AudioRingBuffer.cpp @@ -105,7 +105,7 @@ void AudioRingBuffer::setBearing(float newBearing) { bearing = newBearing; } -void AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { +int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { if (numBytes > (bufferLengthSamples * sizeof(int16_t))) { unsigned char *dataPtr = sourceBuffer + 1; @@ -140,7 +140,9 @@ void AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { if (endOfLastWrite >= buffer + ringBufferLengthSamples) { endOfLastWrite = buffer; - } + } + + return numBytes; } short AudioRingBuffer::diffLastWriteNextOutput() diff --git a/libraries/shared/src/AudioRingBuffer.h b/libraries/shared/src/AudioRingBuffer.h index a87331f330..48620aa133 100644 --- a/libraries/shared/src/AudioRingBuffer.h +++ b/libraries/shared/src/AudioRingBuffer.h @@ -18,7 +18,7 @@ class AudioRingBuffer : public AgentData { ~AudioRingBuffer(); AudioRingBuffer(const AudioRingBuffer &otherRingBuffer); - void parseData(unsigned char* sourceBuffer, int numBytes); + int parseData(unsigned char* sourceBuffer, int numBytes); AudioRingBuffer* clone() const; int16_t* getNextOutput(); diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 2a687f1cd4..898eaed377 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -104,9 +104,8 @@ unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber return newCode; } -float * firstVertexForCode(unsigned char * octalCode) { - float * firstVertex = new float[3]; - memset(firstVertex, 0, 3 * sizeof(float)); +void copyFirstVertexForCode(unsigned char * octalCode, float* output) { + memset(output, 0, 3 * sizeof(float)); float currentScale = 0.5; @@ -114,11 +113,16 @@ float * firstVertexForCode(unsigned char * octalCode) { int sectionIndex = sectionValue(octalCode + 1 + (3 * i / 8), (3 * i) % 8); for (int j = 0; j < 3; j++) { - firstVertex[j] += currentScale * (int)oneAtBit(sectionIndex, 5 + j); + output[j] += currentScale * (int)oneAtBit(sectionIndex, 5 + j); } currentScale *= 0.5; } - +} + +float * firstVertexForCode(unsigned char * octalCode) { + float * firstVertex = new float[3]; + copyFirstVertexForCode(octalCode, firstVertex); return firstVertex; } + diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index d5367fbddf..7569e99868 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -16,6 +16,11 @@ int bytesRequiredForCodeLength(unsigned char threeBitCodes); bool isDirectParentOfChild(unsigned char *parentOctalCode, unsigned char * childOctalCode); int branchIndexWithDescendant(unsigned char * ancestorOctalCode, unsigned char * descendantOctalCode); unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber); + + +// Note: copyFirstVertexForCode() is preferred because it doesn't allocate memory for the return +// but other than that these do the same thing. float * firstVertexForCode(unsigned char * octalCode); +void copyFirstVertexForCode(unsigned char * octalCode, float* output); #endif /* defined(__hifi__OctalCode__) */ diff --git a/libraries/shared/src/UDPSocket.cpp b/libraries/shared/src/UDPSocket.cpp index 42da682d7b..000f0e3d7d 100644 --- a/libraries/shared/src/UDPSocket.cpp +++ b/libraries/shared/src/UDPSocket.cpp @@ -28,20 +28,24 @@ using shared_lib::printLog; sockaddr_in destSockaddr, senderAddress; bool socketMatch(sockaddr *first, sockaddr *second) { - // utility function that indicates if two sockets are equivalent - - // currently only compares two IPv4 addresses - // expandable to IPv6 by adding else if for AF_INET6 - - if (first->sa_family != second->sa_family) { - // not the same family, can't be equal - return false; - } else if (first->sa_family == AF_INET) { - sockaddr_in *firstIn = (sockaddr_in *) first; - sockaddr_in *secondIn = (sockaddr_in *) second; + if (first != NULL && second != NULL) { + // utility function that indicates if two sockets are equivalent - return firstIn->sin_addr.s_addr == secondIn->sin_addr.s_addr + // currently only compares two IPv4 addresses + // expandable to IPv6 by adding else if for AF_INET6 + + if (first->sa_family != second->sa_family) { + // not the same family, can't be equal + return false; + } else if (first->sa_family == AF_INET) { + sockaddr_in *firstIn = (sockaddr_in *) first; + sockaddr_in *secondIn = (sockaddr_in *) second; + + return firstIn->sin_addr.s_addr == secondIn->sin_addr.s_addr && firstIn->sin_port == secondIn->sin_port; + } else { + return false; + } } else { return false; } diff --git a/libraries/voxels/src/AABox.cpp b/libraries/voxels/src/AABox.cpp index bc36bca7a9..0187bae853 100755 --- a/libraries/voxels/src/AABox.cpp +++ b/libraries/voxels/src/AABox.cpp @@ -1,76 +1,68 @@ -/* ------------------------------------------------------ - - Axis Aligned Boxes - Lighthouse3D - - -----------------------------------------------------*/ +// +// AABox.h - Axis Aligned Boxes +// hifi +// +// Added by Brad Hefta-Gaub on 04/11/13. +// Originally from lighthouse3d. Modified to utilize glm::vec3 and clean up to our coding standards +// +// Simple axis aligned box class. +// #include "AABox.h" -AABox::AABox(const glm::vec3& corner, float x, float y, float z) { - setBox(corner,x,y,z); +void AABox::scale(float scale) { + _corner = _corner*scale; + _size = _size*scale; } - -AABox::AABox(void) { - corner.x = 0; corner.y = 0; corner.z = 0; - x = 1.0f; - y = 1.0f; - z = 1.0f; -} - - -AABox::~AABox() {} - -void AABox::setBox(const glm::vec3& corner, float x, float y, float z) { - this->corner = corner; - if (x < 0.0) { - x = -x; - this->corner.x -= x; +void AABox::setBox(const glm::vec3& corner, const glm::vec3& size) { + _corner = corner; + _size = size; + + // In the event that the caller gave us negative sizes, fix things up to be reasonable + if (_size.x < 0.0) { + _size.x = -size.x; + _corner.x -= _size.x; } - if (y < 0.0) { - y = -y; - this->corner.y -= y; + if (_size.y < 0.0) { + _size.y = -size.y; + _corner.y -= _size.y; } - if (z < 0.0) { - z = -z; - this->corner.z -= z; + if (_size.z < 0.0) { + _size.z = -size.z; + _corner.z -= _size.z; } - this->x = x; - this->y = y; - this->z = z; } - - -glm::vec3 AABox::getVertexP(const glm::vec3 &normal) { - glm::vec3 res = corner; +glm::vec3 AABox::getVertexP(const glm::vec3 &normal) const { + glm::vec3 res = _corner; if (normal.x > 0) - res.x += x; + res.x += _size.x; if (normal.y > 0) - res.y += y; + res.y += _size.y; if (normal.z > 0) - res.z += z; + res.z += _size.z; return(res); } -glm::vec3 AABox::getVertexN(const glm::vec3 &normal) { - glm::vec3 res = corner; +glm::vec3 AABox::getVertexN(const glm::vec3 &normal) const { + glm::vec3 res = _corner; if (normal.x < 0) - res.x += x; + res.x += _size.x; if (normal.y < 0) - res.y += y; + res.y += _size.y; if (normal.z < 0) - res.z += z; + res.z += _size.z; return(res); } diff --git a/libraries/voxels/src/AABox.h b/libraries/voxels/src/AABox.h index abc20f38d5..0a69b8608d 100755 --- a/libraries/voxels/src/AABox.h +++ b/libraries/voxels/src/AABox.h @@ -1,9 +1,12 @@ -/* ------------------------------------------------------ - - Axis Aligned Boxes - Lighthouse3D - - -----------------------------------------------------*/ - +// +// AABox.h - Axis Aligned Boxes +// hifi +// +// Added by Brad Hefta-Gaub on 04/11/13. +// Originally from lighthouse3d. Modified to utilize glm::vec3 and clean up to our coding standards +// +// Simple axis aligned box class. +// #ifndef _AABOX_ #define _AABOX_ @@ -15,18 +18,26 @@ class AABox public: - glm::vec3 corner; - float x,y,z; + AABox(const glm::vec3& corner, float x, float y, float z) : _corner(corner), _size(x,y,z) { }; + AABox(const glm::vec3& corner, const glm::vec3& size) : _corner(corner), _size(size) { }; + AABox() : _corner(0,0,0), _size(0,0,0) { } + ~AABox() { } - AABox(const glm::vec3 &corner, float x, float y, float z); - AABox(void); - ~AABox(); - - void setBox(const glm::vec3& corner, float x, float y, float z); + void setBox(const glm::vec3& corner, float x, float y, float z) { setBox(corner,glm::vec3(x,y,z)); }; + void setBox(const glm::vec3& corner, const glm::vec3& size); // for use in frustum computations - glm::vec3 getVertexP(const glm::vec3& normal); - glm::vec3 getVertexN(const glm::vec3& normal); + glm::vec3 getVertexP(const glm::vec3& normal) const; + glm::vec3 getVertexN(const glm::vec3& normal) const; + + void scale(float scale); + + const glm::vec3& getCorner() const { return _corner; }; + const glm::vec3& getSize() const { return _size; }; + +private: + glm::vec3 _corner; + glm::vec3 _size; }; diff --git a/libraries/voxels/src/Plane.cpp b/libraries/voxels/src/Plane.cpp index 2f0d43925b..a5dc9a93bf 100755 --- a/libraries/voxels/src/Plane.cpp +++ b/libraries/voxels/src/Plane.cpp @@ -1,6 +1,12 @@ -// Plane.cpp // -////////////////////////////////////////////////////////////////////// +// Plane.h +// hifi +// +// Created by Brad Hefta-Gaub on 04/11/13. +// Originally from lighthouse3d. Modified to utilize glm::vec3 and clean up to our coding standards +// +// Simple plane class. +// #include "Plane.h" #include @@ -10,78 +16,55 @@ using voxels_lib::printLog; // These are some useful utilities that vec3 is missing -float vec3_length(const glm::vec3& v) { - return((float)sqrt(v.x*v.x + v.y*v.y + v.z*v.z)); +void printVec3(const char* name, const glm::vec3& v) { + printf("%s x=%f y=%f z=%f\n", name, v.x, v.y, v.z); } -void vec3_normalize(glm::vec3& v) { - - float len; - - len = vec3_length(v); - if (len) { - v.x /= len;; - v.y /= len; - v.z /= len; - } -} - -float vec3_innerProduct(const glm::vec3& v1,const glm::vec3& v2) { - - return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z); -} - - - -Plane::Plane(const glm::vec3 &v1, const glm::vec3 &v2, const glm::vec3 &v3) { - - set3Points(v1,v2,v3); -} - - -Plane::Plane() {} - -Plane::~Plane() {} - - void Plane::set3Points(const glm::vec3 &v1, const glm::vec3 &v2, const glm::vec3 &v3) { + glm::vec3 linev1v2, linev1v3; + linev1v2 = v2 - v1; + linev1v3 = v3 - v1; - glm::vec3 aux1, aux2; + // this will be perpendicular to both lines + _normal = glm::cross(linev1v2,linev1v3); + glm::normalize(_normal); - aux1 = v1 - v2; - aux2 = v3 - v2; + // this is a point on the plane + _point = v2; - normal = aux2 * aux1; - - vec3_normalize(normal); - point = v2; - d = -(vec3_innerProduct(normal,point)); + // the D coefficient from the form Ax+By+Cz=D + _dCoefficient = -(glm::dot(_normal,_point)); } void Plane::setNormalAndPoint(const glm::vec3 &normal, const glm::vec3 &point) { + _point = point; + _normal = normal; + glm::normalize(_normal); - this->normal = normal; - vec3_normalize(this->normal); - d = -(vec3_innerProduct(this->normal,point)); + // the D coefficient from the form Ax+By+Cz=D + _dCoefficient = -(glm::dot(_normal,_point)); } void Plane::setCoefficients(float a, float b, float c, float d) { + // set the normal vector + _normal = glm::vec3(a,b,c); - // set the normal vector - normal = glm::vec3(a,b,c); - //compute the lenght of the vector - float l = normal.length(); - // normalize the vector - normal = glm::vec3(a/l,b/l,c/l); - // and divide d by th length as well - this->d = d/l; + //compute the lenght of the vector + float l = glm::length(_normal); + + // normalize the vector + _normal = glm::vec3(a/l,b/l,c/l); + + // and divide d by th length as well + _dCoefficient = d/l; } -float Plane::distance(const glm::vec3 &p) { - return (d + vec3_innerProduct(normal,p)); +float Plane::distance(const glm::vec3 &point) const { + return (_dCoefficient + glm::dot(_normal,point)); } -void Plane::print() { - //printLog("Plane(");normal.print();printLog("# %f)",d); +void Plane::print() const { + printf("Plane - point (x=%f y=%f z=%f) normal (x=%f y=%f z=%f) d=%f\n", + _point.x, _point.y, _point.z, _normal.x, _normal.y, _normal.z, _dCoefficient); } diff --git a/libraries/voxels/src/Plane.h b/libraries/voxels/src/Plane.h index 5c23993dc9..8ce0e5042e 100755 --- a/libraries/voxels/src/Plane.h +++ b/libraries/voxels/src/Plane.h @@ -1,34 +1,43 @@ -////////////////////////////////////////////////////////////////////// -// Plane.h - inspired and modified from lighthouse3d.com // - +// Plane.h +// hifi +// +// Created by Brad Hefta-Gaub on 04/11/13. +// Originally from lighthouse3d. Modified to utilize glm::vec3 and clean up to our coding standards +// +// Simple plane class. +// #ifndef _PLANE_ #define _PLANE_ #include - class Plane { - public: + Plane(const glm::vec3 &v1, const glm::vec3 &v2, const glm::vec3 &v3) { set3Points(v1,v2,v3); } + Plane() : _normal(0,0,0), _point(0,0,0), _dCoefficient(0) {}; + ~Plane() {} ; - glm::vec3 normal,point; - float d; - - - Plane(const glm::vec3 &v1, const glm::vec3 &v2, const glm::vec3 &v3); - Plane(void); - ~Plane(); - + // methods for defining the plane void set3Points(const glm::vec3 &v1, const glm::vec3 &v2, const glm::vec3 &v3); void setNormalAndPoint(const glm::vec3 &normal, const glm::vec3 &point); void setCoefficients(float a, float b, float c, float d); - float distance(const glm::vec3 &p); - void print(); + // getters + const glm::vec3& getNormal() const { return _normal; }; + const glm::vec3& getPoint() const { return _point; }; + float getDCoefficient() const { return _dCoefficient; }; + // utilities + float distance(const glm::vec3 &point) const; + void print() const; + +private: + glm::vec3 _normal; + glm::vec3 _point; + float _dCoefficient; }; diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index 867b47922f..8bdb2d97cb 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -53,102 +53,134 @@ void ViewFrustum::calculate() { glm::vec3 front = _direction; // Calculating field of view. - float fovInRadians = this->_fieldOfView * PI_OVER_180; + float fovInRadians = _fieldOfView * PI_OVER_180; float twoTimesTanHalfFOV = 2.0f * tan(fovInRadians/2.0f); // Do we need this? //tang = (float)tan(ANG2RAD * angle * 0.5) ; - float nearClip = this->_nearClip; - float farClip = this->_farClip; + float nearClip = _nearClip; + float farClip = _farClip; - this->_nearHeight = (twoTimesTanHalfFOV * nearClip); - this->_nearWidth = this->_nearHeight * this->_aspectRatio; - this->_farHeight = (twoTimesTanHalfFOV * farClip); - this->_farWidth = this->_farHeight * this->_aspectRatio; + _nearHeight = (twoTimesTanHalfFOV * nearClip); + _nearWidth = _nearHeight * _aspectRatio; + _farHeight = (twoTimesTanHalfFOV * farClip); + _farWidth = _farHeight * _aspectRatio; - float farHalfHeight = (this->_farHeight * 0.5f); - float farHalfWidth = (this->_farWidth * 0.5f); - this->_farCenter = this->_position+front * farClip; - this->_farTopLeft = this->_farCenter + (this->_up * farHalfHeight) - (this->_right * farHalfWidth); - this->_farTopRight = this->_farCenter + (this->_up * farHalfHeight) + (this->_right * farHalfWidth); - this->_farBottomLeft = this->_farCenter - (this->_up * farHalfHeight) - (this->_right * farHalfWidth); - this->_farBottomRight = this->_farCenter - (this->_up * farHalfHeight) + (this->_right * farHalfWidth); + float farHalfHeight = (_farHeight * 0.5f); + float farHalfWidth = (_farWidth * 0.5f); + _farCenter = _position+front * farClip; + _farTopLeft = _farCenter + (_up * farHalfHeight) - (_right * farHalfWidth); + _farTopRight = _farCenter + (_up * farHalfHeight) + (_right * farHalfWidth); + _farBottomLeft = _farCenter - (_up * farHalfHeight) - (_right * farHalfWidth); + _farBottomRight = _farCenter - (_up * farHalfHeight) + (_right * farHalfWidth); - float nearHalfHeight = (this->_nearHeight * 0.5f); - float nearHalfWidth = (this->_nearWidth * 0.5f); - this->_nearCenter = this->_position+front * nearClip; - this->_nearTopLeft = this->_nearCenter + (this->_up * nearHalfHeight) - (this->_right * nearHalfWidth); - this->_nearTopRight = this->_nearCenter + (this->_up * nearHalfHeight) + (this->_right * nearHalfWidth); - this->_nearBottomLeft = this->_nearCenter - (this->_up * nearHalfHeight) - (this->_right * nearHalfWidth); - this->_nearBottomRight = this->_nearCenter - (this->_up * nearHalfHeight) + (this->_right * nearHalfWidth); + float nearHalfHeight = (_nearHeight * 0.5f); + float nearHalfWidth = (_nearWidth * 0.5f); + _nearCenter = _position+front * nearClip; + _nearTopLeft = _nearCenter + (_up * nearHalfHeight) - (_right * nearHalfWidth); + _nearTopRight = _nearCenter + (_up * nearHalfHeight) + (_right * nearHalfWidth); + _nearBottomLeft = _nearCenter - (_up * nearHalfHeight) - (_right * nearHalfWidth); + _nearBottomRight = _nearCenter - (_up * nearHalfHeight) + (_right * nearHalfWidth); // compute the six planes - // the function set3Points assumes that the points - // are given in counter clockwise order - this->_planes[TOPP].set3Points(this->_nearTopRight,this->_nearTopLeft,this->_farTopLeft); - this->_planes[BOTTOMP].set3Points(this->_nearBottomLeft,this->_nearBottomRight,this->_farBottomRight); - this->_planes[LEFTP].set3Points(this->_nearTopLeft,this->_nearBottomLeft,this->_farBottomLeft); - this->_planes[RIGHTP].set3Points(this->_nearBottomRight,this->_nearTopRight,this->_farBottomRight); - this->_planes[NEARP].set3Points(this->_nearTopLeft,this->_nearTopRight,this->_nearBottomRight); - this->_planes[FARP].set3Points(this->_farTopRight,this->_farTopLeft,this->_farBottomLeft); + // The planes are defined such that the normal points towards the inside of the view frustum. + // Testing if an object is inside the view frustum is performed by computing on which side of + // the plane the object resides. This can be done computing the signed distance from the point + // to the plane. If it is on the side that the normal is pointing, i.e. the signed distance + // is positive, then it is on the right side of the respective plane. If an object is on the + // right side of all six planes then the object is inside the frustum. + + // the function set3Points assumes that the points are given in counter clockwise order, assume you + // are inside the frustum, facing the plane. Start with any point, and go counter clockwise for + // three consecutive points + + _planes[TOP_PLANE ].set3Points(_nearTopRight,_nearTopLeft,_farTopLeft); + _planes[BOTTOM_PLANE].set3Points(_nearBottomLeft,_nearBottomRight,_farBottomRight); + _planes[LEFT_PLANE ].set3Points(_nearBottomLeft,_farBottomLeft,_farTopLeft); + _planes[RIGHT_PLANE ].set3Points(_farBottomRight,_nearBottomRight,_nearTopRight); + _planes[NEAR_PLANE ].set3Points(_nearBottomRight,_nearBottomLeft,_nearTopLeft); + _planes[FAR_PLANE ].set3Points(_farBottomLeft,_farBottomRight,_farTopRight); } -void ViewFrustum::dump() { +void ViewFrustum::dump() const { - printLog("position.x=%f, position.y=%f, position.z=%f\n", this->_position.x, this->_position.y, this->_position.z); - printLog("direction.x=%f, direction.y=%f, direction.z=%f\n", this->_direction.x, this->_direction.y, this->_direction.z); - printLog("up.x=%f, up.y=%f, up.z=%f\n", this->_up.x, this->_up.y, this->_up.z); - printLog("right.x=%f, right.y=%f, right.z=%f\n", this->_right.x, this->_right.y, this->_right.z); + printLog("position.x=%f, position.y=%f, position.z=%f\n", _position.x, _position.y, _position.z); + printLog("direction.x=%f, direction.y=%f, direction.z=%f\n", _direction.x, _direction.y, _direction.z); + printLog("up.x=%f, up.y=%f, up.z=%f\n", _up.x, _up.y, _up.z); + printLog("right.x=%f, right.y=%f, right.z=%f\n", _right.x, _right.y, _right.z); - printLog("farDist=%f\n", this->_farClip); - printLog("farHeight=%f\n", this->_farHeight); - printLog("farWidth=%f\n", this->_farWidth); + printLog("farDist=%f\n", _farClip); + printLog("farHeight=%f\n", _farHeight); + printLog("farWidth=%f\n", _farWidth); - printLog("nearDist=%f\n", this->_nearClip); - printLog("nearHeight=%f\n", this->_nearHeight); - printLog("nearWidth=%f\n", this->_nearWidth); + printLog("nearDist=%f\n", _nearClip); + printLog("nearHeight=%f\n", _nearHeight); + printLog("nearWidth=%f\n", _nearWidth); printLog("farCenter.x=%f, farCenter.y=%f, farCenter.z=%f\n", - this->_farCenter.x, this->_farCenter.y, this->_farCenter.z); + _farCenter.x, _farCenter.y, _farCenter.z); printLog("farTopLeft.x=%f, farTopLeft.y=%f, farTopLeft.z=%f\n", - this->_farTopLeft.x, this->_farTopLeft.y, this->_farTopLeft.z); + _farTopLeft.x, _farTopLeft.y, _farTopLeft.z); printLog("farTopRight.x=%f, farTopRight.y=%f, farTopRight.z=%f\n", - this->_farTopRight.x, this->_farTopRight.y, this->_farTopRight.z); + _farTopRight.x, _farTopRight.y, _farTopRight.z); printLog("farBottomLeft.x=%f, farBottomLeft.y=%f, farBottomLeft.z=%f\n", - this->_farBottomLeft.x, this->_farBottomLeft.y, this->_farBottomLeft.z); + _farBottomLeft.x, _farBottomLeft.y, _farBottomLeft.z); printLog("farBottomRight.x=%f, farBottomRight.y=%f, farBottomRight.z=%f\n", - this->_farBottomRight.x, this->_farBottomRight.y, this->_farBottomRight.z); + _farBottomRight.x, _farBottomRight.y, _farBottomRight.z); printLog("nearCenter.x=%f, nearCenter.y=%f, nearCenter.z=%f\n", - this->_nearCenter.x, this->_nearCenter.y, this->_nearCenter.z); + _nearCenter.x, _nearCenter.y, _nearCenter.z); printLog("nearTopLeft.x=%f, nearTopLeft.y=%f, nearTopLeft.z=%f\n", - this->_nearTopLeft.x, this->_nearTopLeft.y, this->_nearTopLeft.z); + _nearTopLeft.x, _nearTopLeft.y, _nearTopLeft.z); printLog("nearTopRight.x=%f, nearTopRight.y=%f, nearTopRight.z=%f\n", - this->_nearTopRight.x, this->_nearTopRight.y, this->_nearTopRight.z); + _nearTopRight.x, _nearTopRight.y, _nearTopRight.z); printLog("nearBottomLeft.x=%f, nearBottomLeft.y=%f, nearBottomLeft.z=%f\n", - this->_nearBottomLeft.x, this->_nearBottomLeft.y, this->_nearBottomLeft.z); + _nearBottomLeft.x, _nearBottomLeft.y, _nearBottomLeft.z); printLog("nearBottomRight.x=%f, nearBottomRight.y=%f, nearBottomRight.z=%f\n", - this->_nearBottomRight.x, this->_nearBottomRight.y, this->_nearBottomRight.z); + _nearBottomRight.x, _nearBottomRight.y, _nearBottomRight.z); } -int ViewFrustum::pointInFrustum(glm::vec3 &p) { +//enum { TOP_PLANE = 0, BOTTOM_PLANE, LEFT_PLANE, RIGHT_PLANE, NEAR_PLANE, FAR_PLANE }; +const char* ViewFrustum::debugPlaneName (int plane) const { + switch (plane) { + case TOP_PLANE: return "Top Plane"; + case BOTTOM_PLANE: return "Bottom Plane"; + case LEFT_PLANE: return "Left Plane"; + case RIGHT_PLANE: return "Right Plane"; + case NEAR_PLANE: return "Near Plane"; + case FAR_PLANE: return "Far Plane"; + } + return "Unknown"; +} + + +int 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; for(int i=0; i < 6; i++) { - if (this->_planes[i].distance(p) < 0) + float distance = _planes[i].distance(point); + + //printf("plane[%d] %s -- distance=%f \n",i,debugPlaneName(i),distance); + + if (distance < 0) { return OUTSIDE; + } } return(result); } -int ViewFrustum::sphereInFrustum(glm::vec3 ¢er, float radius) { +int ViewFrustum::sphereInFrustum(const glm::vec3& center, float radius) const { int result = INSIDE; float distance; for(int i=0; i < 6; i++) { - distance = this->_planes[i].distance(center); + distance = _planes[i].distance(center); if (distance < -radius) return OUTSIDE; else if (distance < radius) @@ -158,13 +190,37 @@ int ViewFrustum::sphereInFrustum(glm::vec3 ¢er, float radius) { } -int ViewFrustum::boxInFrustum(AABox &b) { +int 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; for(int i=0; i < 6; i++) { - if (this->_planes[i].distance(b.getVertexP(this->_planes[i].normal)) < 0) + + //printf("plane[%d] -- point(%f,%f,%f) normal(%f,%f,%f) d=%f \n",i, + // _planes[i].getPoint().x, _planes[i].getPoint().y, _planes[i].getPoint().z, + // _planes[i].getNormal().x, _planes[i].getNormal().y, _planes[i].getNormal().z, + // _planes[i].getDCoefficient() + //); + + glm::vec3 normal = _planes[i].getNormal(); + glm::vec3 boxVertexP = box.getVertexP(normal); + float planeToBoxVertexPDistance = _planes[i].distance(boxVertexP); + + glm::vec3 boxVertexN = box.getVertexN(normal); + float planeToBoxVertexNDistance = _planes[i].distance(boxVertexN); + + //printf("plane[%d] normal=(%f,%f,%f) bVertexP=(%f,%f,%f) planeToBoxVertexPDistance=%f boxVertexN=(%f,%f,%f) planeToBoxVertexNDistance=%f\n",i, + // normal.x,normal.y,normal.z, + // boxVertexP.x,boxVertexP.y,boxVertexP.z,planeToBoxVertexPDistance, + // boxVertexN.x,boxVertexN.y,boxVertexN.z,planeToBoxVertexNDistance + // ); + + if (planeToBoxVertexPDistance < 0) { return OUTSIDE; - else if (this->_planes[i].distance(b.getVertexN(this->_planes[i].normal)) < 0) + } else if (planeToBoxVertexNDistance < 0) { result = INTERSECT; + } } return(result); } diff --git a/libraries/voxels/src/ViewFrustum.h b/libraries/voxels/src/ViewFrustum.h index 15bdb484fb..9ebfba6e9a 100644 --- a/libraries/voxels/src/ViewFrustum.h +++ b/libraries/voxels/src/ViewFrustum.h @@ -45,15 +45,23 @@ private: glm::vec3 _nearTopRight; glm::vec3 _nearBottomLeft; glm::vec3 _nearBottomRight; - enum { TOPP = 0, BOTTOMP, LEFTP, RIGHTP, NEARP, FARP }; + enum { TOP_PLANE = 0, BOTTOM_PLANE, LEFT_PLANE, RIGHT_PLANE, NEAR_PLANE, FAR_PLANE }; Plane _planes[6]; // How will this be used? + const char* debugPlaneName (int plane) const; + public: // setters for camera attributes void setPosition (const glm::vec3& p) { _position = p; } void setOrientation (const glm::vec3& d, const glm::vec3& u, const glm::vec3& r ) { _direction = d; _up = u; _right = r; } + // getters for camera attributes + const glm::vec3& getPosition() const { return _position; }; + const glm::vec3& getDirection() const { return _direction; }; + const glm::vec3& getUp() const { return _up; }; + const glm::vec3& getRight() const { return _right; }; + // setters for lens attributes void setFieldOfView ( float f ) { _fieldOfView = f; } void setAspectRatio ( float a ) { _aspectRatio = a; } @@ -82,13 +90,13 @@ public: ViewFrustum(); - void dump(); + void dump() const; enum {OUTSIDE, INTERSECT, INSIDE}; - int pointInFrustum(glm::vec3 &p); - int sphereInFrustum(glm::vec3 ¢er, float radius); - int boxInFrustum(AABox &b); + int pointInFrustum(const glm::vec3& point) const; + int sphereInFrustum(const glm::vec3& center, float radius) const; + int boxInFrustum(const AABox& box) const; }; diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 5f36ad9e59..4278d8d75e 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -6,17 +6,23 @@ // // +#include #include #include "SharedUtil.h" //#include "voxels_Log.h" #include "VoxelNode.h" #include "OctalCode.h" +#include "AABox.h" // using voxels_lib::printLog; VoxelNode::VoxelNode() { octalCode = NULL; +#ifdef HAS_FALSE_COLOR + _falseColored = false; // assume true color +#endif + // default pointers to child nodes to NULL for (int i = 0; i < 8; i++) { children[i] = NULL; @@ -28,13 +34,36 @@ VoxelNode::~VoxelNode() { // delete all of this node's children for (int i = 0; i < 8; i++) { - delete children[i]; + if (children[i]) { + delete children[i]; + } } } +void VoxelNode::getAABox(AABox& box) const { + + glm::vec3 corner; + glm::vec3 size; + + // copy corner into box + copyFirstVertexForCode(octalCode,(float*)&corner); + + // this tells you the "size" of the voxel + float voxelScale = 1 / powf(2, *octalCode); + size = glm::vec3(voxelScale,voxelScale,voxelScale); + + box.setBox(corner,size); +} + void VoxelNode::addChildAtIndex(int childIndex) { children[childIndex] = new VoxelNode(); + // XXXBHG - When the node is constructed, it should be cleanly set up as + // true colored, but for some reason, not so much. I've added a a basecamp + // to-do to research this. But for now we'll use belt and suspenders and set + // it to not-false-colored here! + children[childIndex]->setFalseColored(false); + // give this child its octal code children[childIndex]->octalCode = childOctalCode(octalCode, childIndex); } @@ -43,30 +72,60 @@ void VoxelNode::addChildAtIndex(int childIndex) { void VoxelNode::setColorFromAverageOfChildren() { int colorArray[4] = {0,0,0,0}; for (int i = 0; i < 8; i++) { - if (children[i] != NULL && children[i]->color[3] == 1) { + if (children[i] != NULL && children[i]->isColored()) { for (int j = 0; j < 3; j++) { - colorArray[j] += children[i]->color[j]; + colorArray[j] += children[i]->getTrueColor()[j]; // color averaging should always be based on true colors } 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 // or if we have none we generate random values for (int c = 0; c < 3; c++) { // set the average color value - color[c] = colorArray[c] / colorArray[3]; + newColor[c] = colorArray[c] / colorArray[3]; } // set the alpha to 1 to indicate that this isn't transparent - color[3] = 1; - } else { - // some children, but not enough - // set this node's alpha to 0 - color[3] = 0; - } + newColor[3] = 1; + } + // actually set our color, note, if we didn't have enough children + // this will be the default value all zeros, and therefore be marked as + // transparent with a 4th element of 0 + setColor(newColor); } +// Note: !NO_FALSE_COLOR implementations of setFalseColor(), setFalseColored(), and setColor() here. +// the actual NO_FALSE_COLOR version are inline in the VoxelNode.h +#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color +void VoxelNode::setFalseColor(colorPart red, colorPart green, colorPart blue) { + _falseColored=true; + _currentColor[0] = red; + _currentColor[1] = green; + _currentColor[2] = blue; + _currentColor[3] = 1; // XXXBHG - False colors are always considered set +} + +void VoxelNode::setFalseColored(bool isFalseColored) { + // if we were false colored, and are no longer false colored, then swap back + if (_falseColored && !isFalseColored) { + memcpy(&_currentColor,&_trueColor,sizeof(nodeColor)); + } + _falseColored = isFalseColored; +}; + + +void VoxelNode::setColor(const nodeColor& color) { + //printf("VoxelNode::setColor() isFalseColored=%s\n",_falseColored ? "Yes" : "No"); + memcpy(&_trueColor,&color,sizeof(nodeColor)); + if (!_falseColored) { + memcpy(&_currentColor,&color,sizeof(nodeColor)); + } +} +#endif + // will detect if children are leaves AND the same color // and in that case will delete the children and make this node // a leaf, returns TRUE if all the leaves are collapsed into a @@ -77,16 +136,17 @@ bool VoxelNode::collapseIdenticalLeaves() { int red,green,blue; for (int i = 0; i < 8; i++) { // if no child, or child doesn't have a color - if (children[i] == NULL || children[i]->color[3] != 1) { + if (children[i] == NULL || !children[i]->isColored()) { allChildrenMatch=false; //printLog("SADNESS child missing or not colored! i=%d\n",i); break; } else { if (i==0) { - red = children[i]->color[0]; - green = children[i]->color[1]; - blue = children[i]->color[2]; - } else if (red != children[i]->color[0] || green != children[i]->color[1] || blue != children[i]->color[2]) { + red = children[i]->getColor()[0]; + green = children[i]->getColor()[1]; + blue = children[i]->getColor()[2]; + } else if (red != children[i]->getColor()[0] || + green != children[i]->getColor()[1] || blue != children[i]->getColor()[2]) { allChildrenMatch=false; break; } @@ -100,18 +160,22 @@ bool VoxelNode::collapseIdenticalLeaves() { delete children[i]; // delete all the child nodes children[i]=NULL; // set it to NULL } - color[0]=red; - color[1]=green; - color[2]=blue; - color[3]=1; // color is set + nodeColor collapsedColor; + collapsedColor[0]=red; + collapsedColor[1]=green; + collapsedColor[2]=blue; + collapsedColor[3]=1; // color is set + setColor(collapsedColor); } return allChildrenMatch; } void VoxelNode::setRandomColor(int minimumBrightness) { + nodeColor newColor; for (int c = 0; c < 3; c++) { - color[c] = randomColorValue(minimumBrightness); + newColor[c] = randomColorValue(minimumBrightness); } - color[3] = 1; + newColor[3] = 1; + setColor(newColor); } diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index b82c07a09d..cf644a1fd1 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -9,7 +9,18 @@ #ifndef __hifi__VoxelNode__ #define __hifi__VoxelNode__ +#include "AABox.h" + +typedef unsigned char colorPart; +typedef unsigned char nodeColor[4]; + class VoxelNode { +private: + nodeColor _trueColor; +#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color + nodeColor _currentColor; + bool _falseColored; +#endif public: VoxelNode(); ~VoxelNode(); @@ -20,8 +31,27 @@ public: bool collapseIdenticalLeaves(); unsigned char *octalCode; - unsigned char color[4]; VoxelNode *children[8]; + + bool isColored() const { return (_trueColor[3]==1); }; + +#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color + void setFalseColor(colorPart red, colorPart green, colorPart blue); + void setFalseColored(bool isFalseColored); + bool getFalseColored() { return _falseColored; }; + void setColor(const nodeColor& color); + const nodeColor& getTrueColor() const { return _trueColor; }; + const nodeColor& getColor() const { return _currentColor; }; +#else + void setFalseColor(colorPart red, colorPart green, colorPart blue) { /* no op */ }; + void setFalseColored(bool isFalseColored) { /* no op */ }; + bool getFalseColored() { return false; }; + void setColor(const nodeColor& color) { memcpy(_trueColor,color,sizeof(nodeColor)); }; + const nodeColor& getTrueColor() const { return _trueColor; }; + const nodeColor& getColor() const { return _trueColor; }; +#endif + + void getAABox(AABox& box) const; }; #endif /* defined(__hifi__VoxelNode__) */ diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 2c2599bc80..db69535e14 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -17,6 +17,7 @@ #include "PacketHeaders.h" #include "OctalCode.h" #include "VoxelTree.h" +#include "ViewFrustum.h" #include // to load voxels from file using voxels_lib::printLog; @@ -66,6 +67,27 @@ VoxelTree::~VoxelTree() { } } +// Recurses voxel tree calling the RecurseVoxelTreeOperation function for each node. +// stops recursion if operation function returns false. +void VoxelTree::recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData) { + recurseNodeWithOperation(rootNode, operation,extraData); +} + +// Recurses voxel node with an operation function +void VoxelTree::recurseNodeWithOperation(VoxelNode* node,RecurseVoxelTreeOperation operation, void* extraData) { + // call the operation function going "down" first, stop deeper recursion if function returns false + if (operation(node,true,extraData)) { + for (int i = 0; i < sizeof(node->children)/sizeof(node->children[0]); i++) { + VoxelNode* child = node->children[i]; + if (child) { + recurseNodeWithOperation(child,operation,extraData); + } + } + // call operation on way back up + operation(node,false,extraData); + } +} + VoxelNode * VoxelTree::nodeForOctalCode(VoxelNode *ancestorNode, unsigned char * needleCode, VoxelNode** parentOfFoundNode) { // find the appropriate branch index based on this ancestorNode if (*needleCode > 0) { @@ -127,8 +149,10 @@ int VoxelTree::readNodeData(VoxelNode *destinationNode, } // pull the color for this child - memcpy(destinationNode->children[i]->color, nodeData + bytesRead, 3); - destinationNode->children[i]->color[3] = 1; + nodeColor newColor; + memcpy(newColor, nodeData + bytesRead, 3); + newColor[3] = 1; + destinationNode->children[i]->setColor(newColor); this->voxelsColored++; this->voxelsColoredStats.updateAverage(1); @@ -233,15 +257,20 @@ void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) { // give this node its color int octalCodeBytes = bytesRequiredForCodeLength(*codeColorBuffer); - memcpy(lastCreatedNode->color, codeColorBuffer + octalCodeBytes, 3); - lastCreatedNode->color[3] = 1; + + nodeColor newColor; + memcpy(newColor, codeColorBuffer + octalCodeBytes, 3); + newColor[3] = 1; + lastCreatedNode->setColor(newColor); } unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, VoxelNode *currentVoxelNode, MarkerNode *currentMarkerNode, - float * agentPosition, + const glm::vec3& agentPosition, float thisNodePosition[3], + const ViewFrustum& viewFrustum, + bool viewFrustumCulling, unsigned char * stopOctalCode) { static unsigned char *initialBitstreamPos = bitstreamBuffer; @@ -268,22 +297,38 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, unsigned char * childMaskPointer = NULL; float halfUnitForVoxel = powf(0.5, *currentVoxelNode->octalCode) * (0.5 * TREE_SCALE); - - // XXXBHG - Note: It appears as if the X and Z coordinates of Head or Agent are flip-flopped relative to the - // coords of the voxel space. This flip flop causes LOD behavior to be extremely odd. This is my temporary hack - // to fix this behavior. To disable this swap, set swapXandZ to false. - // XXXBHG - 2013/04/11 - adding a note to my branch, I think this code is now broken. - bool swapXandZ=true; - float agentX = swapXandZ ? agentPosition[2] : agentPosition[0]; - float agentZ = swapXandZ ? agentPosition[0] : agentPosition[2]; - - float distanceToVoxelCenter = sqrtf(powf(agentX - thisNodePosition[0] - halfUnitForVoxel, 2) + + float distanceToVoxelCenter = sqrtf(powf(agentPosition[0] - thisNodePosition[0] - halfUnitForVoxel, 2) + powf(agentPosition[1] - thisNodePosition[1] - halfUnitForVoxel, 2) + - powf(agentZ - thisNodePosition[2] - halfUnitForVoxel, 2)); + powf(agentPosition[2] - thisNodePosition[2] - halfUnitForVoxel, 2)); + + // If the voxel is outside of the view frustum, then don't bother sending or recursing + bool voxelInView = true; + + /**** not yet working properly at this level! ************************************************************************** + if (viewFrustumCulling) { + float fullUnitForVoxel = halfUnitForVoxel * 2.0f; + AABox voxelBox; + voxelBox.setBox(glm::vec3(thisNodePosition[0],thisNodePosition[1],thisNodePosition[2]), + fullUnitForVoxel,fullUnitForVoxel,fullUnitForVoxel); + + //printf("VoxelTree::loadBitstreamBuffer() voxelBox.corner=(%f,%f,%f) x=%f \n", + // voxelBox.getCorner().x,voxelBox.getCorner().y,voxelBox.getCorner().z, voxelBox.getSize().x); + + voxelInView = (ViewFrustum::OUTSIDE != viewFrustum.pointInFrustum(voxelBox.getCorner())); + } else { + voxelInView = true; + } + **********************************************************************************************************************/ // if the distance to this voxel's center is less than the threshold // distance for its children, we should send the children - if (distanceToVoxelCenter < boundaryDistanceForRenderLevel(*currentVoxelNode->octalCode + 1)) { + bool voxelIsClose = (distanceToVoxelCenter < boundaryDistanceForRenderLevel(*currentVoxelNode->octalCode + 1)); + bool sendVoxel = voxelIsClose && voxelInView; + + //printf("VoxelTree::loadBitstreamBuffer() sendVoxel=%d, voxelIsClose=%d, voxelInView=%d, viewFrustumCulling=%d\n", + // sendVoxel, voxelIsClose, voxelInView, viewFrustumCulling); + + if (sendVoxel) { // write this voxel's data if we're below or at // or at the same level as the stopOctalCode @@ -315,16 +360,78 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, for (int i = 0; i < 8; i++) { - // check if the child exists and is not transparent - if (currentVoxelNode->children[i] != NULL - && currentVoxelNode->children[i]->color[3] != 0) { + // Rules for including a child: + // 1) child must exists + if ((currentVoxelNode->children[i] != NULL)) { + // 2) child must have a color... + if (currentVoxelNode->children[i]->isColored()) { - // copy in the childs color to bitstreamBuffer - memcpy(colorPointer, currentVoxelNode->children[i]->color, 3); - colorPointer += 3; + unsigned char* childOctalCode = currentVoxelNode->children[i]->octalCode; + + float childPosition[3]; + copyFirstVertexForCode(childOctalCode,(float*)&childPosition); + childPosition[0] *= TREE_SCALE; // scale it up + childPosition[1] *= TREE_SCALE; // scale it up + childPosition[2] *= TREE_SCALE; // scale it up - // set the colorMask by bitshifting the value of childExists - *bitstreamBuffer += (1 << (7 - i)); + float halfChildVoxel = powf(0.5, *childOctalCode) * (0.5 * TREE_SCALE); + float distanceToChildCenter = sqrtf(powf(agentPosition[0] - childPosition[0] - halfChildVoxel, 2) + + powf(agentPosition[1] - childPosition[1] - halfChildVoxel, 2) + + powf(agentPosition[2] - childPosition[2] - halfChildVoxel, 2)); + + float fullChildVoxel = halfChildVoxel * 2.0f; + AABox childBox; + childBox.setBox(glm::vec3(childPosition[0], childPosition[1], childPosition[2]), + fullChildVoxel, fullChildVoxel, fullChildVoxel); + + //printf("VoxelTree::loadBitstreamBuffer() childBox.corner=(%f,%f,%f) x=%f \n", + // childBox.getCorner().x,childBox.getCorner().y,childBox.getCorner().z, childBox.getSize().x); + + // XXXBHG - not sure we want to do this "distance/LOD culling" at this level. + //bool childIsClose = (distanceToChildCenter < boundaryDistanceForRenderLevel(*childOctalCode + 1)); + + bool childIsClose = true; // for now, assume we're close enough + bool childInView = !viewFrustumCulling || + (ViewFrustum::OUTSIDE != viewFrustum.boxInFrustum(childBox)); + + /// XXXBHG - debug code, switch this to true, and we'll send everything but include false coloring + // on voxels based on whether or not they match these rules. + bool falseColorInsteadOfCulling = false; + + // removed childIsClose - until we determine if we want to include that + bool sendChild = (childInView) || falseColorInsteadOfCulling; + + //printf("VoxelTree::loadBitstreamBuffer() childIsClose=%d, childInView=%d\n", + // childIsClose, childInView); + + // if we sendAnyway, we'll do false coloring of the voxels based on childIsClose && childInView + if (sendChild) { + + // copy in the childs color to bitstreamBuffer + if (childIsClose && childInView) { + // true color + memcpy(colorPointer, currentVoxelNode->children[i]->getTrueColor(), 3); + } else { + unsigned char red[3] = {255,0,0}; + unsigned char green[3] = {0,255,0}; + unsigned char blue[3] = {0,0,255}; + if (!childIsClose && !childInView) { + // If both too far, and not in view, color them red + memcpy(colorPointer, red, 3); + } else if (!childIsClose) { + // If too far, but in view, color them blue + memcpy(colorPointer, blue, 3); + } else { + // If close, but out of view, color them green + memcpy(colorPointer, green, 3); + } + } + colorPointer += 3; + + // set the colorMask by bitshifting the value of childExists + *bitstreamBuffer += (1 << (7 - i)); + } + } } } @@ -358,9 +465,19 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, currentMarkerNode->children[i] = new MarkerNode(); } - // calculate the child's position based on the parent position float childNodePosition[3]; - + copyFirstVertexForCode(currentVoxelNode->children[i]->octalCode,(float*)&childNodePosition); + childNodePosition[0] *= TREE_SCALE; // scale it up + childNodePosition[1] *= TREE_SCALE; // scale it up + childNodePosition[2] *= TREE_SCALE; // scale it up + + /**** disabled ***************************************************************************************** + // Note: Stephen, I intentionally left this in so you would talk to me about it. Here's the deal, this + // code doesn't seem to work correctly. It returns X and Z flipped and the values are negative. Since + // we use the firstVertexForCode() function in VoxelSystem to calculate the child vertex and that DOES + // work, I've decided to use that function to calculate our position for LOD handling. + // + // calculate the child's position based on the parent position for (int j = 0; j < 3; j++) { childNodePosition[j] = thisNodePosition[j]; @@ -370,6 +487,7 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, childNodePosition[j] -= (powf(0.5, *currentVoxelNode->children[i]->octalCode) * TREE_SCALE); } } + **** disabled *****************************************************************************************/ // ask the child to load the bitstream buffer with their data childStopOctalCode = loadBitstreamBuffer(bitstreamBuffer, @@ -377,6 +495,8 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, currentMarkerNode->children[i], agentPosition, childNodePosition, + viewFrustum, + viewFrustumCulling, stopOctalCode); if (bitstreamBuffer - arrBufferBeforeChild > 0) { @@ -437,7 +557,7 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { // create the color mask for (int i = 0; i < 8; i++) { - if (startNode->children[i] != NULL && startNode->children[i]->color[3] != 0) { + if (startNode->children[i] != NULL && startNode->children[i]->isColored()) { colorMask += (1 << (7 - i)); } } @@ -446,9 +566,9 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { // output the colors we have for (int j = 0; j < 8; j++) { - if (startNode->children[j] != NULL && startNode->children[j]->color[3] != 0) { + if (startNode->children[j] != NULL && startNode->children[j]->isColored()) { for (int c = 0; c < 3; c++) { - outputBits(startNode->children[j]->color[c]); + outputBits(startNode->children[j]->getTrueColor()[c]); } } } diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 4c18a23028..60c66925ec 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -11,6 +11,7 @@ #include "SimpleMovingAverage.h" +#include "ViewFrustum.h" #include "VoxelNode.h" #include "MarkerNode.h" @@ -18,6 +19,9 @@ const int MAX_VOXEL_PACKET_SIZE = 1492; const int MAX_TREE_SLICE_BYTES = 26; const int TREE_SCALE = 10; +// Callback function, for recuseTreeWithOperation +typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, bool down, void* extraData); + class VoxelTree { public: // when a voxel is created in the tree (object new'd) @@ -47,13 +51,19 @@ public: unsigned char * loadBitstreamBuffer(unsigned char *& bitstreamBuffer, VoxelNode *currentVoxelNode, MarkerNode *currentMarkerNode, - float * agentPosition, + const glm::vec3& agentPosition, float thisNodePosition[3], + const ViewFrustum& viewFrustum, + bool viewFrustumCulling, unsigned char * octalCode = NULL); void loadVoxelsFile(const char* fileName, bool wantColorRandomizer); void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer); + + void recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData=NULL); + private: + void recurseNodeWithOperation(VoxelNode* node,RecurseVoxelTreeOperation operation, void* extraData); VoxelNode * nodeForOctalCode(VoxelNode *ancestorNode, unsigned char * needleCode, VoxelNode** parentOfFoundNode); VoxelNode * createMissingNode(VoxelNode *lastParentNode, unsigned char *deepestCodeToCreate); int readNodeData(VoxelNode *destinationNode, unsigned char * nodeData, int bufferSizeBytes); diff --git a/voxel-server/CMakeLists.txt b/voxel-server/CMakeLists.txt index 5f9ff87fd7..2bdba8f6e3 100644 --- a/voxel-server/CMakeLists.txt +++ b/voxel-server/CMakeLists.txt @@ -5,6 +5,13 @@ set(TARGET_NAME voxel-server) set(ROOT_DIR ..) set(MACRO_DIR ${ROOT_DIR}/cmake/macros) +# setup for find modules +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") + +# set up the external glm library +include(${MACRO_DIR}/IncludeGLM.cmake) +include_glm(${TARGET_NAME} ${ROOT_DIR}) + include(${MACRO_DIR}/SetupHifiProject.cmake) setup_hifi_project(${TARGET_NAME}) @@ -14,4 +21,8 @@ include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) # link in the hifi voxels library -link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file +link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR}) + +# link in the hifi avatars library +link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR}) + diff --git a/voxel-server/src/VoxelAgentData.cpp b/voxel-server/src/VoxelAgentData.cpp index 8f9b41e4ca..4476cff056 100644 --- a/voxel-server/src/VoxelAgentData.cpp +++ b/voxel-server/src/VoxelAgentData.cpp @@ -19,18 +19,10 @@ VoxelAgentData::~VoxelAgentData() { } VoxelAgentData::VoxelAgentData(const VoxelAgentData &otherAgentData) { - memcpy(position, otherAgentData.position, sizeof(float) * 3); + memcpy(&_bodyPosition, &otherAgentData._bodyPosition, sizeof(_bodyPosition)); rootMarkerNode = new MarkerNode(); } VoxelAgentData* VoxelAgentData::clone() const { return new VoxelAgentData(*this); } - -void VoxelAgentData::parseData(unsigned char* sourceBuffer, int numBytes) { - // push past the packet header - sourceBuffer++; - - // pull the position from the interface agent data packet - memcpy(&position, sourceBuffer, sizeof(float) * 3); -} diff --git a/voxel-server/src/VoxelAgentData.h b/voxel-server/src/VoxelAgentData.h index 98ec7e9ed7..4ca7949b92 100644 --- a/voxel-server/src/VoxelAgentData.h +++ b/voxel-server/src/VoxelAgentData.h @@ -11,18 +11,17 @@ #include #include +#include #include "MarkerNode.h" -class VoxelAgentData : public AgentData { +class VoxelAgentData : public AvatarData { public: - float position[3]; MarkerNode *rootMarkerNode; VoxelAgentData(); ~VoxelAgentData(); VoxelAgentData(const VoxelAgentData &otherAgentData); - void parseData(unsigned char* sourceBuffer, int numBytes); VoxelAgentData* clone() const; }; diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 8f6bab7dc7..91fa2fd596 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -48,6 +48,8 @@ const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4; VoxelTree randomTree; bool wantColorRandomizer = false; +bool debugViewFrustum = false; +bool viewFrustumCulling = true; // for now void addSphere(VoxelTree * tree,bool random, bool wantColorRandomizer) { float r = random ? randFloatInRange(0.05,0.1) : 0.25; @@ -165,6 +167,24 @@ void *distributeVoxelsToListeners(void *args) { Agent *thisAgent = (Agent *)&agentList->getAgents()[i]; VoxelAgentData *agentData = (VoxelAgentData *)(thisAgent->getLinkedData()); + ViewFrustum viewFrustum; + // get position and orientation details from the camera + viewFrustum.setPosition(agentData->getCameraPosition()); + viewFrustum.setOrientation(agentData->getCameraDirection(), agentData->getCameraUp(), agentData->getCameraRight()); + + // Also make sure it's got the correct lens details from the camera + viewFrustum.setFieldOfView(agentData->getCameraFov()); + viewFrustum.setAspectRatio(agentData->getCameraAspectRatio()); + viewFrustum.setNearClip(agentData->getCameraNearClip()); + viewFrustum.setFarClip(agentData->getCameraFarClip()); + + viewFrustum.calculate(); + + // debug for fun!! + if (::debugViewFrustum) { + viewFrustum.dump(); + } + // lock this agent's delete mutex so that the delete thread doesn't // kill the agent while we are working with it pthread_mutex_lock(thisAgent->deleteMutex); @@ -179,8 +199,10 @@ void *distributeVoxelsToListeners(void *args) { stopOctal = randomTree.loadBitstreamBuffer(voxelPacketEnd, randomTree.rootNode, agentData->rootMarkerNode, - agentData->position, + agentData->getBodyPosition(), treeRoot, + viewFrustum, + ::viewFrustumCulling, stopOctal); agentList->getAgentSocket().send(thisAgent->getActiveSocket(), voxelPacket, voxelPacketEnd - voxelPacket); @@ -249,37 +271,43 @@ int main(int argc, const char * argv[]) agentList->startDomainServerCheckInThread(); srand((unsigned)time(0)); + + const char* DEBUG_VIEW_FRUSTUM = "--DebugViewFrustum"; + ::debugViewFrustum = cmdOptionExists(argc, argv, DEBUG_VIEW_FRUSTUM); + printf("debugViewFrustum=%s\n", (::debugViewFrustum ? "yes" : "no")); + + const char* NO_VIEW_FRUSTUM_CULLING = "--NoViewFrustumCulling"; + ::viewFrustumCulling = !cmdOptionExists(argc, argv, NO_VIEW_FRUSTUM_CULLING); + printf("viewFrustumCulling=%s\n", (::viewFrustumCulling ? "yes" : "no")); + const char* WANT_COLOR_RANDOMIZER = "--WantColorRandomizer"; + ::wantColorRandomizer = cmdOptionExists(argc, argv, WANT_COLOR_RANDOMIZER); + printf("wantColorRandomizer=%s\n", (::wantColorRandomizer ? "yes" : "no")); + // Check to see if the user passed in a command line option for loading a local // Voxel File. If so, load it now. - const char* WANT_COLOR_RANDOMIZER="--WantColorRandomizer"; - const char* INPUT_FILE="-i"; - ::wantColorRandomizer = cmdOptionExists(argc, argv, WANT_COLOR_RANDOMIZER); - - printf("wantColorRandomizer=%s\n",(wantColorRandomizer?"yes":"no")); + const char* INPUT_FILE = "-i"; const char* voxelsFilename = getCmdOption(argc, argv, INPUT_FILE); - if (voxelsFilename) { randomTree.loadVoxelsFile(voxelsFilename,wantColorRandomizer); } - const char* ADD_RANDOM_VOXELS="--AddRandomVoxels"; + const char* ADD_RANDOM_VOXELS = "--AddRandomVoxels"; if (cmdOptionExists(argc, argv, ADD_RANDOM_VOXELS)) { // create an octal code buffer and load it with 0 so that the recursive tree fill can give // octal codes to the tree nodes that it is creating randomlyFillVoxelTree(MAX_VOXEL_TREE_DEPTH_LEVELS, randomTree.rootNode); } - - const char* ADD_SPHERE="--AddSphere"; - const char* ADD_RANDOM_SPHERE="--AddRandomSphere"; + 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* NO_ADD_SCENE="--NoAddScene"; + const char* NO_ADD_SCENE = "--NoAddScene"; if (!cmdOptionExists(argc, argv, NO_ADD_SCENE)) { addSphereScene(&randomTree,wantColorRandomizer); } @@ -345,7 +373,7 @@ int main(int argc, const char * argv[]) // Now send this to the connected agents so they know to delete printf("rebroadcasting delete voxel message to connected agents... agentList.broadcastToAgents()\n"); - agentList->broadcastToAgents(packetData,receivedBytes, &AGENT_TYPE_INTERFACE, 1); + agentList->broadcastToAgents(packetData,receivedBytes, &AGENT_TYPE_AVATAR, 1); } if (packetData[0] == PACKET_HEADER_Z_COMMAND) { @@ -373,14 +401,14 @@ int main(int argc, const char * argv[]) // Now send this to the connected agents so they can also process these messages printf("rebroadcasting Z message to connected agents... agentList.broadcastToAgents()\n"); - agentList->broadcastToAgents(packetData,receivedBytes, &AGENT_TYPE_INTERFACE, 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_INTERFACE, 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. if (packetData[0] == PACKET_HEADER_HEAD_DATA) { if (agentList->addOrUpdateAgent(&agentPublicAddress, &agentPublicAddress, - AGENT_TYPE_INTERFACE, + AGENT_TYPE_AVATAR, agentList->getLastAgentId())) { agentList->increaseAgentId(); }