Merge branch 'master' of git://github.com/worklist/hifi into 19188

This commit is contained in:
tosh 2013-04-23 16:08:47 +02:00
commit 723d49d78c
38 changed files with 2104 additions and 1086 deletions

View file

@ -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)

View file

@ -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 ||

20
eve/CMakeLists.txt Normal file
View file

@ -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})

128
eve/src/main.cpp Normal file
View file

@ -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 <sys/time.h>
#include <SharedUtil.h>
#include <AgentTypes.h>
#include <PacketHeaders.h>
#include <AgentList.h>
#include <AvatarData.h>
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();
}

View file

@ -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)

File diff suppressed because it is too large Load diff

View file

@ -22,6 +22,13 @@
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp> //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

View file

@ -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();
}

View file

@ -14,6 +14,7 @@
#include <UDPSocket.h>
#include <AgentData.h>
#include <VoxelTree.h>
#include <ViewFrustum.h>
#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();
};

View file

@ -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<Agent>::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<Agent>::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");

View file

@ -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() {

View file

@ -13,8 +13,6 @@
#include <AgentData.h>
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__) */

View file

@ -20,8 +20,7 @@ using avatars_lib::printLog;
//
// tosh - yep, I noticed... :-)
//
// JJV - I noticed too :-)
//
static bool testingForNormalizationAndOrthogonality = false;
Orientation::Orientation() {

View file

@ -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);
}

View file

@ -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);

View file

@ -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;
};

View file

@ -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<Agent>::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<Agent>::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<Agent>::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<Agent>::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);

View file

@ -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();

View file

@ -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';

View file

@ -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()

View file

@ -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();

View file

@ -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;
}

View file

@ -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__) */

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;
};

View file

@ -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 <stdio.h>
@ -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);
}

View file

@ -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 <glm/glm.hpp>
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;
};

View file

@ -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 &center, 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 &center, 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);
}

View file

@ -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 &center, 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;
};

View file

@ -6,17 +6,23 @@
//
//
#include <stdio.h>
#include <cstring>
#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);
}

View file

@ -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__) */

View file

@ -17,6 +17,7 @@
#include "PacketHeaders.h"
#include "OctalCode.h"
#include "VoxelTree.h"
#include "ViewFrustum.h"
#include <fstream> // 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]);
}
}
}

View file

@ -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);

View file

@ -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})
link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR})
# link in the hifi avatars library
link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR})

View file

@ -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);
}

View file

@ -11,18 +11,17 @@
#include <iostream>
#include <AgentData.h>
#include <AvatarData.h>
#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;
};

View file

@ -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();
}