mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-13 20:43:45 +02:00
Merge remote-tracking branch 'upstream/master' into invensense
This commit is contained in:
commit
d2ca0d4dc4
35 changed files with 1403 additions and 1034 deletions
|
@ -92,13 +92,15 @@ void *sendBuffer(void *args)
|
|||
if (!agentBuffer->isStarted()
|
||||
&& agentBuffer->diffLastWriteNextOutput() <= BUFFER_LENGTH_SAMPLES_PER_CHANNEL + JITTER_BUFFER_SAMPLES) {
|
||||
printf("Held back buffer for agent with ID %d.\n", agent->getAgentId());
|
||||
agentBuffer->setShouldBeAddedToMix(false);
|
||||
} else if (agentBuffer->diffLastWriteNextOutput() < BUFFER_LENGTH_SAMPLES_PER_CHANNEL) {
|
||||
printf("Buffer from agent with ID %d starved.\n", agent->getAgentId());
|
||||
agentBuffer->setStarted(false);
|
||||
agentBuffer->setShouldBeAddedToMix(false);
|
||||
} else {
|
||||
// good buffer, add this to the mix
|
||||
agentBuffer->setStarted(true);
|
||||
agentBuffer->setAddedToMix(true);
|
||||
agentBuffer->setShouldBeAddedToMix(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -129,89 +131,91 @@ void *sendBuffer(void *args)
|
|||
if (otherAgent != agent || (otherAgent == agent && agentWantsLoopback)) {
|
||||
AudioRingBuffer* otherAgentBuffer = (AudioRingBuffer*) otherAgent->getLinkedData();
|
||||
|
||||
float *agentPosition = agentRingBuffer->getPosition();
|
||||
float *otherAgentPosition = otherAgentBuffer->getPosition();
|
||||
|
||||
// calculate the distance to the other agent
|
||||
|
||||
// use the distance to the other agent to calculate the change in volume for this frame
|
||||
int lowAgentIndex = std::min(agent.getAgentIndex(), otherAgent.getAgentIndex());
|
||||
int highAgentIndex = std::max(agent.getAgentIndex(), otherAgent.getAgentIndex());
|
||||
|
||||
if (distanceCoeffs[lowAgentIndex][highAgentIndex] == 0) {
|
||||
float distanceToAgent = sqrtf(powf(agentPosition[0] - otherAgentPosition[0], 2) +
|
||||
powf(agentPosition[1] - otherAgentPosition[1], 2) +
|
||||
powf(agentPosition[2] - otherAgentPosition[2], 2));
|
||||
if (otherAgentBuffer->shouldBeAddedToMix()) {
|
||||
float *agentPosition = agentRingBuffer->getPosition();
|
||||
float *otherAgentPosition = otherAgentBuffer->getPosition();
|
||||
|
||||
float minCoefficient = std::min(1.0f,
|
||||
powf(0.5, (logf(DISTANCE_RATIO * distanceToAgent) / logf(3)) - 1));
|
||||
distanceCoeffs[lowAgentIndex][highAgentIndex] = minCoefficient;
|
||||
}
|
||||
|
||||
|
||||
// get the angle from the right-angle triangle
|
||||
float triangleAngle = atan2f(fabsf(agentPosition[2] - otherAgentPosition[2]),
|
||||
fabsf(agentPosition[0] - otherAgentPosition[0])) * (180 / M_PI);
|
||||
float angleToSource;
|
||||
|
||||
|
||||
// find the angle we need for calculation based on the orientation of the triangle
|
||||
if (otherAgentPosition[0] > agentPosition[0]) {
|
||||
if (otherAgentPosition[2] > agentPosition[2]) {
|
||||
angleToSource = -90 + triangleAngle - agentBearing;
|
||||
} else {
|
||||
angleToSource = -90 - triangleAngle - agentBearing;
|
||||
// calculate the distance to the other agent
|
||||
|
||||
// use the distance to the other agent to calculate the change in volume for this frame
|
||||
int lowAgentIndex = std::min(agent.getAgentIndex(), otherAgent.getAgentIndex());
|
||||
int highAgentIndex = std::max(agent.getAgentIndex(), otherAgent.getAgentIndex());
|
||||
|
||||
if (distanceCoeffs[lowAgentIndex][highAgentIndex] == 0) {
|
||||
float distanceToAgent = sqrtf(powf(agentPosition[0] - otherAgentPosition[0], 2) +
|
||||
powf(agentPosition[1] - otherAgentPosition[1], 2) +
|
||||
powf(agentPosition[2] - otherAgentPosition[2], 2));
|
||||
|
||||
float minCoefficient = std::min(1.0f,
|
||||
powf(0.5, (logf(DISTANCE_RATIO * distanceToAgent) / logf(3)) - 1));
|
||||
distanceCoeffs[lowAgentIndex][highAgentIndex] = minCoefficient;
|
||||
}
|
||||
} else {
|
||||
if (otherAgentPosition[2] > agentPosition[2]) {
|
||||
angleToSource = 90 - triangleAngle - agentBearing;
|
||||
|
||||
|
||||
// get the angle from the right-angle triangle
|
||||
float triangleAngle = atan2f(fabsf(agentPosition[2] - otherAgentPosition[2]),
|
||||
fabsf(agentPosition[0] - otherAgentPosition[0])) * (180 / M_PI);
|
||||
float angleToSource;
|
||||
|
||||
|
||||
// find the angle we need for calculation based on the orientation of the triangle
|
||||
if (otherAgentPosition[0] > agentPosition[0]) {
|
||||
if (otherAgentPosition[2] > agentPosition[2]) {
|
||||
angleToSource = -90 + triangleAngle - agentBearing;
|
||||
} else {
|
||||
angleToSource = -90 - triangleAngle - agentBearing;
|
||||
}
|
||||
} else {
|
||||
angleToSource = 90 + triangleAngle - agentBearing;
|
||||
if (otherAgentPosition[2] > agentPosition[2]) {
|
||||
angleToSource = 90 - triangleAngle - agentBearing;
|
||||
} else {
|
||||
angleToSource = 90 + triangleAngle - agentBearing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (angleToSource > 180) {
|
||||
angleToSource -= 360;
|
||||
} else if (angleToSource < -180) {
|
||||
angleToSource += 360;
|
||||
}
|
||||
|
||||
angleToSource *= (M_PI / 180);
|
||||
|
||||
float sinRatio = fabsf(sinf(angleToSource));
|
||||
int numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio;
|
||||
float weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio);
|
||||
|
||||
int16_t *goodChannel = angleToSource > 0 ? clientMix + BUFFER_LENGTH_SAMPLES_PER_CHANNEL : clientMix;
|
||||
int16_t *delayedChannel = angleToSource > 0 ? clientMix : clientMix + BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
|
||||
|
||||
int16_t *delaySamplePointer = otherAgentBuffer->getNextOutput() == otherAgentBuffer->getBuffer()
|
||||
|
||||
if (angleToSource > 180) {
|
||||
angleToSource -= 360;
|
||||
} else if (angleToSource < -180) {
|
||||
angleToSource += 360;
|
||||
}
|
||||
|
||||
angleToSource *= (M_PI / 180);
|
||||
|
||||
float sinRatio = fabsf(sinf(angleToSource));
|
||||
int numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio;
|
||||
float weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio);
|
||||
|
||||
int16_t *goodChannel = angleToSource > 0 ? clientMix + BUFFER_LENGTH_SAMPLES_PER_CHANNEL : clientMix;
|
||||
int16_t *delayedChannel = angleToSource > 0 ? clientMix : clientMix + BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
|
||||
|
||||
int16_t *delaySamplePointer = otherAgentBuffer->getNextOutput() == otherAgentBuffer->getBuffer()
|
||||
? otherAgentBuffer->getBuffer() + RING_BUFFER_SAMPLES - numSamplesDelay
|
||||
: otherAgentBuffer->getNextOutput() - numSamplesDelay;
|
||||
|
||||
|
||||
for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) {
|
||||
|
||||
if (s < numSamplesDelay) {
|
||||
// pull the earlier sample for the delayed channel
|
||||
|
||||
for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) {
|
||||
|
||||
int earlierSample = delaySamplePointer[s] *
|
||||
distanceCoeffs[lowAgentIndex][highAgentIndex] *
|
||||
otherAgentBuffer->getAttenuationRatio();
|
||||
if (s < numSamplesDelay) {
|
||||
// pull the earlier sample for the delayed channel
|
||||
|
||||
int earlierSample = delaySamplePointer[s] *
|
||||
distanceCoeffs[lowAgentIndex][highAgentIndex] *
|
||||
otherAgentBuffer->getAttenuationRatio();
|
||||
|
||||
plateauAdditionOfSamples(delayedChannel[s], earlierSample * weakChannelAmplitudeRatio);
|
||||
}
|
||||
|
||||
plateauAdditionOfSamples(delayedChannel[s], earlierSample * weakChannelAmplitudeRatio);
|
||||
}
|
||||
|
||||
int16_t currentSample = (otherAgentBuffer->getNextOutput()[s] *
|
||||
distanceCoeffs[lowAgentIndex][highAgentIndex] *
|
||||
otherAgentBuffer->getAttenuationRatio());
|
||||
plateauAdditionOfSamples(goodChannel[s], currentSample);
|
||||
|
||||
if (s + numSamplesDelay < BUFFER_LENGTH_SAMPLES_PER_CHANNEL) {
|
||||
plateauAdditionOfSamples(delayedChannel[s + numSamplesDelay],
|
||||
currentSample *
|
||||
weakChannelAmplitudeRatio *
|
||||
int16_t currentSample = (otherAgentBuffer->getNextOutput()[s] *
|
||||
distanceCoeffs[lowAgentIndex][highAgentIndex] *
|
||||
otherAgentBuffer->getAttenuationRatio());
|
||||
plateauAdditionOfSamples(goodChannel[s], currentSample);
|
||||
|
||||
if (s + numSamplesDelay < BUFFER_LENGTH_SAMPLES_PER_CHANNEL) {
|
||||
plateauAdditionOfSamples(delayedChannel[s + numSamplesDelay],
|
||||
currentSample *
|
||||
weakChannelAmplitudeRatio *
|
||||
otherAgentBuffer->getAttenuationRatio());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -222,14 +226,14 @@ void *sendBuffer(void *args)
|
|||
|
||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
AudioRingBuffer* agentBuffer = (AudioRingBuffer*) agent->getLinkedData();
|
||||
if (agentBuffer->wasAddedToMix()) {
|
||||
if (agentBuffer->shouldBeAddedToMix()) {
|
||||
agentBuffer->setNextOutput(agentBuffer->getNextOutput() + BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
|
||||
|
||||
if (agentBuffer->getNextOutput() >= agentBuffer->getBuffer() + RING_BUFFER_SAMPLES) {
|
||||
agentBuffer->setNextOutput(agentBuffer->getBuffer());
|
||||
}
|
||||
|
||||
agentBuffer->setAddedToMix(false);
|
||||
agentBuffer->setShouldBeAddedToMix(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ bool stopReceiveAgentDataThread;
|
|||
bool injectAudioThreadRunning = false;
|
||||
|
||||
int TEMP_AUDIO_LISTEN_PORT = 55439;
|
||||
// UDPSocket audioSocket(TEMP_AUDIO_LISTEN_PORT);
|
||||
UDPSocket audioSocket(TEMP_AUDIO_LISTEN_PORT);
|
||||
|
||||
void *receiveAgentData(void *args) {
|
||||
sockaddr senderAddress;
|
||||
|
@ -80,7 +80,7 @@ void *injectAudio(void *args) {
|
|||
}
|
||||
|
||||
// we have an active audio mixer we can send data to
|
||||
// eveAudioInjector->injectAudio(&::audioSocket, audioMixer->getActiveSocket());
|
||||
eveAudioInjector->injectAudio(&::audioSocket, audioMixer->getActiveSocket());
|
||||
}
|
||||
|
||||
::injectAudioThreadRunning = false;
|
||||
|
@ -113,7 +113,8 @@ int main(int argc, const char* argv[]) {
|
|||
// move eve away from the origin
|
||||
// pick a random point inside a 10x10 grid
|
||||
|
||||
eve.setPosition(glm::vec3(randFloatInRange(-RANDOM_POSITION_MAX_DIMENSION, RANDOM_POSITION_MAX_DIMENSION), 0.4,
|
||||
eve.setPosition(glm::vec3(randFloatInRange(-RANDOM_POSITION_MAX_DIMENSION, RANDOM_POSITION_MAX_DIMENSION),
|
||||
0.32, // this is the same as the pelvis standing height (as of 4/26/13)
|
||||
randFloatInRange(-RANDOM_POSITION_MAX_DIMENSION, RANDOM_POSITION_MAX_DIMENSION)));
|
||||
|
||||
// face any instance of eve down the z-axis
|
||||
|
@ -121,10 +122,10 @@ int main(int argc, const char* argv[]) {
|
|||
|
||||
// put her hand out so somebody can shake it
|
||||
eve.setHandPosition(glm::vec3(eve.getPosition()[0] - 0.2,
|
||||
0.32, // this is the same as the pelvis standing height (as of 4/26/13)
|
||||
0.25,
|
||||
eve.getPosition()[2] + 0.1));
|
||||
// read eve's audio data
|
||||
AudioInjector eveAudioInjector("eve.raw");
|
||||
AudioInjector eveAudioInjector("/etc/highfidelity/eve/resources/eve.raw");
|
||||
|
||||
unsigned char broadcastPacket[MAX_PACKET_SIZE];
|
||||
broadcastPacket[0] = PACKET_HEADER_HEAD_DATA;
|
||||
|
@ -134,8 +135,8 @@ int main(int argc, const char* argv[]) {
|
|||
timeval thisSend;
|
||||
double numMicrosecondsSleep = 0;
|
||||
|
||||
// int numIterationsLeftBeforeAudioSend = 0;
|
||||
// pthread_t injectAudioThread;
|
||||
int numIterationsLeftBeforeAudioSend = 0;
|
||||
pthread_t injectAudioThread;
|
||||
|
||||
int handStateTimer = 0;
|
||||
|
||||
|
@ -156,16 +157,16 @@ int main(int argc, const char* argv[]) {
|
|||
}
|
||||
|
||||
// temporarily disable Eve's audio sending until the file is actually available on EC2 box
|
||||
// if (numIterationsLeftBeforeAudioSend == 0) {
|
||||
// if (!::injectAudioThreadRunning) {
|
||||
// pthread_create(&injectAudioThread, NULL, injectAudio, (void*) &eveAudioInjector);
|
||||
//
|
||||
// numIterationsLeftBeforeAudioSend = randIntInRange(MIN_ITERATIONS_BETWEEN_AUDIO_SENDS,
|
||||
// MAX_ITERATIONS_BETWEEN_AUDIO_SENDS);
|
||||
// }
|
||||
// } else {
|
||||
// numIterationsLeftBeforeAudioSend--;
|
||||
// }
|
||||
if (numIterationsLeftBeforeAudioSend == 0) {
|
||||
if (!::injectAudioThreadRunning) {
|
||||
pthread_create(&injectAudioThread, NULL, injectAudio, (void*) &eveAudioInjector);
|
||||
|
||||
numIterationsLeftBeforeAudioSend = randIntInRange(MIN_ITERATIONS_BETWEEN_AUDIO_SENDS,
|
||||
MAX_ITERATIONS_BETWEEN_AUDIO_SENDS);
|
||||
}
|
||||
} else {
|
||||
numIterationsLeftBeforeAudioSend--;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
|
|
@ -30,8 +30,12 @@ include_glm(${TARGET_NAME} ${ROOT_DIR})
|
|||
# create the InterfaceConfig.h file based on GL_HEADERS above
|
||||
configure_file(InterfaceConfig.h.in ${PROJECT_BINARY_DIR}/includes/InterfaceConfig.h)
|
||||
|
||||
# grab the implementation and header files from src dir
|
||||
# grab the implementation and header files from src dirs
|
||||
file(GLOB INTERFACE_SRCS src/*.cpp src/*.h)
|
||||
foreach(SUBDIR ui)
|
||||
file(GLOB SUBDIR_SRCS src/${SUBDIR}/*.cpp src/${SUBDIR}/*.h)
|
||||
set(INTERFACE_SRCS ${INTERFACE_SRCS} ${SUBDIR_SRCS})
|
||||
endforeach(SUBDIR)
|
||||
|
||||
# project subdirectories
|
||||
add_subdirectory(src/starfield)
|
||||
|
@ -73,6 +77,10 @@ include_directories(
|
|||
${LODEPNG_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
find_package(Qt4 REQUIRED QtCore QtGui)
|
||||
include(${QT_USE_FILE})
|
||||
target_link_libraries(${TARGET_NAME} ${QT_LIBRARIES})
|
||||
|
||||
if (NOT APPLE)
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(GLUT REQUIRED)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//
|
||||
// Created by Philip Rosedale on 9/11/12.
|
||||
// adapted by Jeffrey Ventrella
|
||||
// Copyright (c) 2012 Physical, Inc.. All rights reserved.
|
||||
// Copyright (c) 2013 Physical, Inc.. All rights reserved.
|
||||
//
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
@ -13,13 +13,35 @@
|
|||
#include <SharedUtil.h>
|
||||
#include "Avatar.h"
|
||||
#include "Log.h"
|
||||
#include "ui/TextRenderer.h"
|
||||
#include <AgentList.h>
|
||||
#include <AgentTypes.h>
|
||||
#include <PacketHeaders.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
const bool BALLS_ON = false;
|
||||
/*
|
||||
const bool BALLS_ON = false;
|
||||
|
||||
const bool AVATAR_GRAVITY = true;
|
||||
const float DECAY = 0.1;
|
||||
|
||||
//const float THRUST_MAG = 1200.0;
|
||||
const float THRUST_MAG = 0.0;
|
||||
|
||||
const float YAW_MAG = 500.0; //JJV - changed from 300.0;
|
||||
const float TEST_YAW_DECAY = 5.0;
|
||||
const float LIN_VEL_DECAY = 5.0;
|
||||
const float MY_HAND_HOLDING_PULL = 0.2;
|
||||
const float YOUR_HAND_HOLDING_PULL = 1.0;
|
||||
const float BODY_SPRING_FORCE = 6.0f;
|
||||
const float BODY_SPRING_DECAY = 16.0f;
|
||||
const float COLLISION_RADIUS_SCALAR = 1.8;
|
||||
const float COLLISION_BALL_FORCE = 0.6;
|
||||
const float COLLISION_BODY_FORCE = 6.0;
|
||||
const float COLLISION_BALL_FRICTION = 200.0;
|
||||
const float COLLISION_BODY_FRICTION = 0.5;
|
||||
*/
|
||||
|
||||
float skinColor[] = {1.0, 0.84, 0.66};
|
||||
float lightBlue[] = { 0.7, 0.8, 1.0 };
|
||||
|
@ -39,7 +61,7 @@ bool usingBigSphereCollisionTest = true;
|
|||
|
||||
char iris_texture_file[] = "resources/images/green_eye.png";
|
||||
|
||||
float chatMessageScale = 0.00025;
|
||||
float chatMessageScale = 0.001;
|
||||
float chatMessageHeight = 0.4;
|
||||
|
||||
vector<unsigned char> iris_texture;
|
||||
|
@ -50,72 +72,77 @@ Avatar::Avatar(bool isMine) {
|
|||
|
||||
_orientation.setToIdentity();
|
||||
|
||||
_velocity = glm::vec3( 0.0, 0.0, 0.0 );
|
||||
_thrust = glm::vec3( 0.0, 0.0, 0.0 );
|
||||
_rotation = glm::quat( 0.0f, 0.0f, 0.0f, 0.0f );
|
||||
_bodyYaw = -90.0;
|
||||
_bodyPitch = 0.0;
|
||||
_bodyRoll = 0.0;
|
||||
_bodyYawDelta = 0.0;
|
||||
_mousePressed = false;
|
||||
_mode = AVATAR_MODE_STANDING;
|
||||
_isMine = isMine;
|
||||
_maxArmLength = 0.0;
|
||||
_transmitterHz = 0.0;
|
||||
_transmitterPackets = 0;
|
||||
_speed = 0.0;
|
||||
_pelvisStandingHeight = 0.0f;
|
||||
_displayingHead = true;
|
||||
_TEST_bigSphereRadius = 0.3f;
|
||||
_TEST_bigSpherePosition = glm::vec3( 0.0f, _TEST_bigSphereRadius, 2.0f );
|
||||
_velocity = glm::vec3( 0.0, 0.0, 0.0 );
|
||||
_thrust = glm::vec3( 0.0, 0.0, 0.0 );
|
||||
_rotation = glm::quat( 0.0f, 0.0f, 0.0f, 0.0f );
|
||||
_bodyYaw = -90.0;
|
||||
_bodyPitch = 0.0;
|
||||
_bodyRoll = 0.0;
|
||||
_bodyPitchDelta = 0.0;
|
||||
_bodyYawDelta = 0.0;
|
||||
_bodyRollDelta = 0.0;
|
||||
_mousePressed = false;
|
||||
_mode = AVATAR_MODE_STANDING;
|
||||
_isMine = isMine;
|
||||
_maxArmLength = 0.0;
|
||||
_transmitterHz = 0.0;
|
||||
_transmitterPackets = 0;
|
||||
_transmitterIsFirstData = true;
|
||||
_transmitterInitialReading = glm::vec3( 0.f, 0.f, 0.f );
|
||||
_speed = 0.0;
|
||||
_pelvisStandingHeight = 0.0f;
|
||||
_displayingHead = true;
|
||||
_TEST_bigSphereRadius = 0.3f;
|
||||
_TEST_bigSpherePosition = glm::vec3( 0.0f, _TEST_bigSphereRadius, 2.0f );
|
||||
|
||||
for (int i = 0; i < MAX_DRIVE_KEYS; i++) _driveKeys[i] = false;
|
||||
|
||||
_head.pupilSize = 0.10;
|
||||
_head.interPupilDistance = 0.6;
|
||||
_head.interBrowDistance = 0.75;
|
||||
_head.nominalPupilSize = 0.10;
|
||||
_head.pitchRate = 0.0;
|
||||
_head.yawRate = 0.0;
|
||||
_head.rollRate = 0.0;
|
||||
_head.eyebrowPitch[0] = -30;
|
||||
_head.eyebrowPitch[1] = -30;
|
||||
_head.eyebrowRoll [0] = 20;
|
||||
_head.eyebrowRoll [1] = -20;
|
||||
_head.mouthPitch = 0;
|
||||
_head.mouthYaw = 0;
|
||||
_head.mouthWidth = 1.0;
|
||||
_head.mouthHeight = 0.2;
|
||||
_head.eyeballPitch[0] = 0;
|
||||
_head.eyeballPitch[1] = 0;
|
||||
_head.eyeballScaleX = 1.2;
|
||||
_head.eyeballScaleY = 1.5;
|
||||
_head.eyeballScaleZ = 1.0;
|
||||
_head.eyeballYaw[0] = 0;
|
||||
_head.eyeballYaw[1] = 0;
|
||||
_head.pitchTarget = 0;
|
||||
_head.yawTarget = 0;
|
||||
_head.noiseEnvelope = 1.0;
|
||||
_head.pupilConverge = 10.0;
|
||||
_head.leanForward = 0.0;
|
||||
_head.leanSideways = 0.0;
|
||||
_head.eyeContact = 1;
|
||||
_head.eyeContactTarget = LEFT_EYE;
|
||||
_head.scale = 1.0;
|
||||
_head.audioAttack = 0.0;
|
||||
_head.averageLoudness = 0.0;
|
||||
_head.lastLoudness = 0.0;
|
||||
_head.browAudioLift = 0.0;
|
||||
_head.noise = 0;
|
||||
_movedHandOffset = glm::vec3( 0.0, 0.0, 0.0 );
|
||||
_usingBodySprings = true;
|
||||
_renderYaw = 0.0;
|
||||
_renderPitch = 0.0;
|
||||
_sphere = NULL;
|
||||
_interactingOther = NULL;
|
||||
_interactingOtherIsNearby = false;
|
||||
_handHoldingPosition = glm::vec3( 0.0, 0.0, 0.0 );
|
||||
|
||||
_head.pupilSize = 0.10;
|
||||
_head.interPupilDistance = 0.6;
|
||||
_head.interBrowDistance = 0.75;
|
||||
_head.nominalPupilSize = 0.10;
|
||||
_head.pitchRate = 0.0;
|
||||
_head.yawRate = 0.0;
|
||||
_head.rollRate = 0.0;
|
||||
_head.eyebrowPitch[0] = -30;
|
||||
_head.eyebrowPitch[1] = -30;
|
||||
_head.eyebrowRoll [0] = 20;
|
||||
_head.eyebrowRoll [1] = -20;
|
||||
_head.mouthPitch = 0;
|
||||
_head.mouthYaw = 0;
|
||||
_head.mouthWidth = 1.0;
|
||||
_head.mouthHeight = 0.2;
|
||||
_head.eyeballPitch[0] = 0;
|
||||
_head.eyeballPitch[1] = 0;
|
||||
_head.eyeballScaleX = 1.2;
|
||||
_head.eyeballScaleY = 1.5;
|
||||
_head.eyeballScaleZ = 1.0;
|
||||
_head.eyeballYaw[0] = 0;
|
||||
_head.eyeballYaw[1] = 0;
|
||||
_head.pitchTarget = 0;
|
||||
_head.yawTarget = 0;
|
||||
_head.noiseEnvelope = 1.0;
|
||||
_head.pupilConverge = 10.0;
|
||||
_head.leanForward = 0.0;
|
||||
_head.leanSideways = 0.0;
|
||||
_head.eyeContact = 1;
|
||||
_head.eyeContactTarget = LEFT_EYE;
|
||||
_head.scale = 1.0;
|
||||
_head.audioAttack = 0.0;
|
||||
_head.averageLoudness = 0.0;
|
||||
_head.lastLoudness = 0.0;
|
||||
_head.browAudioLift = 0.0;
|
||||
_head.noise = 0;
|
||||
_head.returnSpringScale = 1.0;
|
||||
_movedHandOffset = glm::vec3( 0.0, 0.0, 0.0 );
|
||||
_usingBodySprings = true;
|
||||
_renderYaw = 0.0;
|
||||
_renderPitch = 0.0;
|
||||
_sphere = NULL;
|
||||
_interactingOther = NULL;
|
||||
//_canReachToOtherAvatar = false;
|
||||
_handHoldingPosition = glm::vec3( 0.0, 0.0, 0.0 );
|
||||
|
||||
initializeSkeleton();
|
||||
|
||||
if (iris_texture.size() == 0) {
|
||||
|
@ -130,30 +157,35 @@ Avatar::Avatar(bool isMine) {
|
|||
else { _balls = NULL; }
|
||||
}
|
||||
|
||||
|
||||
Avatar::Avatar(const Avatar &otherAvatar) {
|
||||
|
||||
_velocity = otherAvatar._velocity;
|
||||
_thrust = otherAvatar._thrust;
|
||||
_rotation = otherAvatar._rotation;
|
||||
_interactingOtherIsNearby = otherAvatar._interactingOtherIsNearby;
|
||||
_bodyYaw = otherAvatar._bodyYaw;
|
||||
_bodyPitch = otherAvatar._bodyPitch;
|
||||
_bodyRoll = otherAvatar._bodyRoll;
|
||||
_bodyYawDelta = otherAvatar._bodyYawDelta;
|
||||
_mousePressed = otherAvatar._mousePressed;
|
||||
_mode = otherAvatar._mode;
|
||||
_isMine = otherAvatar._isMine;
|
||||
_renderYaw = otherAvatar._renderYaw;
|
||||
_renderPitch = otherAvatar._renderPitch;
|
||||
_maxArmLength = otherAvatar._maxArmLength;
|
||||
_transmitterTimer = otherAvatar._transmitterTimer;
|
||||
_transmitterHz = otherAvatar._transmitterHz;
|
||||
_transmitterPackets = otherAvatar._transmitterPackets;
|
||||
_TEST_bigSphereRadius = otherAvatar._TEST_bigSphereRadius;
|
||||
_TEST_bigSpherePosition = otherAvatar._TEST_bigSpherePosition;
|
||||
_movedHandOffset = otherAvatar._movedHandOffset;
|
||||
_usingBodySprings = otherAvatar._usingBodySprings;
|
||||
_velocity = otherAvatar._velocity;
|
||||
_thrust = otherAvatar._thrust;
|
||||
_rotation = otherAvatar._rotation;
|
||||
//_canReachToOtherAvatar = otherAvatar._canReachToOtherAvatar;
|
||||
_bodyYaw = otherAvatar._bodyYaw;
|
||||
_bodyPitch = otherAvatar._bodyPitch;
|
||||
_bodyRoll = otherAvatar._bodyRoll;
|
||||
_bodyPitchDelta = otherAvatar._bodyPitchDelta;
|
||||
_bodyYawDelta = otherAvatar._bodyYawDelta;
|
||||
_bodyRollDelta = otherAvatar._bodyRollDelta;
|
||||
_mousePressed = otherAvatar._mousePressed;
|
||||
_mode = otherAvatar._mode;
|
||||
_isMine = otherAvatar._isMine;
|
||||
_renderYaw = otherAvatar._renderYaw;
|
||||
_renderPitch = otherAvatar._renderPitch;
|
||||
_maxArmLength = otherAvatar._maxArmLength;
|
||||
_transmitterTimer = otherAvatar._transmitterTimer;
|
||||
_transmitterIsFirstData = otherAvatar._transmitterIsFirstData;
|
||||
_transmitterTimeLastReceived = otherAvatar._transmitterTimeLastReceived;
|
||||
_transmitterHz = otherAvatar._transmitterHz;
|
||||
_transmitterInitialReading = otherAvatar._transmitterInitialReading;
|
||||
_transmitterPackets = otherAvatar._transmitterPackets;
|
||||
_TEST_bigSphereRadius = otherAvatar._TEST_bigSphereRadius;
|
||||
_TEST_bigSpherePosition = otherAvatar._TEST_bigSpherePosition;
|
||||
_movedHandOffset = otherAvatar._movedHandOffset;
|
||||
_usingBodySprings = otherAvatar._usingBodySprings;
|
||||
|
||||
_orientation.set( otherAvatar._orientation );
|
||||
|
||||
_sphere = NULL;
|
||||
|
@ -199,7 +231,6 @@ Avatar::Avatar(const Avatar &otherAvatar) {
|
|||
_head.browAudioLift = otherAvatar._head.browAudioLift;
|
||||
_head.noise = otherAvatar._head.noise;
|
||||
|
||||
|
||||
initializeSkeleton();
|
||||
|
||||
if (iris_texture.size() == 0) {
|
||||
|
@ -284,8 +315,22 @@ void Avatar::setMousePressed( bool d ) {
|
|||
}
|
||||
|
||||
|
||||
bool Avatar::getIsNearInteractingOther() {
|
||||
return _avatarTouch.getAbleToReachOtherAvatar();
|
||||
}
|
||||
|
||||
|
||||
void Avatar::simulate(float deltaTime) {
|
||||
|
||||
|
||||
//keep this - I'm still using it to test things....
|
||||
/*
|
||||
//TEST
|
||||
static float tt = 0.0f;
|
||||
tt += deltaTime * 2.0f;
|
||||
//_head.leanSideways = 0.01 * sin( tt );
|
||||
_head.leanForward = 0.02 * sin( tt * 0.8 );
|
||||
*/
|
||||
|
||||
// update balls
|
||||
if (_balls) { _balls->simulate(deltaTime); }
|
||||
|
||||
|
@ -295,19 +340,19 @@ void Avatar::simulate(float deltaTime) {
|
|||
// reset hand and arm positions according to hand movement
|
||||
updateHandMovement( deltaTime );
|
||||
|
||||
if ( !_interactingOtherIsNearby ) {
|
||||
if ( !_avatarTouch.getAbleToReachOtherAvatar() ) {
|
||||
//initialize _handHolding
|
||||
_handHoldingPosition = _bone[ AVATAR_BONE_RIGHT_HAND ].position;
|
||||
}
|
||||
|
||||
_interactingOtherIsNearby = false;
|
||||
//reset these for the next go-round
|
||||
_avatarTouch.setAbleToReachOtherAvatar (false);
|
||||
_avatarTouch.setHandsCloseEnoughToGrasp(false);
|
||||
|
||||
// if the avatar being simulated is mine, then loop through
|
||||
// all the other avatars for potential interactions...
|
||||
if ( _isMine )
|
||||
{
|
||||
float closestDistance = 10000.0f;
|
||||
|
||||
AgentList* agentList = AgentList::getInstance();
|
||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) {
|
||||
|
@ -318,25 +363,42 @@ void Avatar::simulate(float deltaTime) {
|
|||
|
||||
// test other avatar hand position for proximity
|
||||
glm::vec3 v( _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position );
|
||||
v -= otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND );
|
||||
v -= otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_SHOULDER );
|
||||
|
||||
float distance = glm::length( v );
|
||||
if ( distance < _maxArmLength + _maxArmLength ) {
|
||||
|
||||
closestDistance = distance;
|
||||
_interactingOther = otherAvatar;
|
||||
_interactingOtherIsNearby = true;
|
||||
_avatarTouch.setAbleToReachOtherAvatar(true);
|
||||
|
||||
glm::vec3 vectorBetweenHands( _bone[ AVATAR_BONE_RIGHT_HAND ].position );
|
||||
vectorBetweenHands -= otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND );
|
||||
float distanceBetweenHands = glm::length(vectorBetweenHands);
|
||||
|
||||
if (distanceBetweenHands < _avatarTouch.HANDS_CLOSE_ENOUGH_TO_GRASP) {
|
||||
_avatarTouch.setHandsCloseEnoughToGrasp(true);
|
||||
}
|
||||
|
||||
// if I am holding hands with another avatar, a force is applied
|
||||
if (( _handState == 1 ) || ( _interactingOther->_handState == 1 )) {
|
||||
glm::vec3 vectorToOtherHand = _interactingOther->_handPosition - _handHoldingPosition;
|
||||
glm::vec3 vectorToMyHand = _bone[ AVATAR_BONE_RIGHT_HAND ].position - _handHoldingPosition;
|
||||
_handHoldingPosition += vectorToOtherHand * YOUR_HAND_HOLDING_PULL;
|
||||
_handHoldingPosition += vectorToMyHand * MY_HAND_HOLDING_PULL;
|
||||
_bone[ AVATAR_BONE_RIGHT_HAND ].position = _handHoldingPosition;
|
||||
|
||||
// if the hands are close enough to grasp...
|
||||
if (distanceBetweenHands < _avatarTouch.HANDS_CLOSE_ENOUGH_TO_GRASP)
|
||||
{
|
||||
// apply the forces...
|
||||
glm::vec3 vectorToOtherHand = _interactingOther->_handPosition - _handHoldingPosition;
|
||||
glm::vec3 vectorToMyHand = _bone[ AVATAR_BONE_RIGHT_HAND ].position - _handHoldingPosition;
|
||||
|
||||
_handHoldingPosition += vectorToOtherHand * YOUR_HAND_HOLDING_PULL;
|
||||
_handHoldingPosition += vectorToMyHand * MY_HAND_HOLDING_PULL;
|
||||
_bone[ AVATAR_BONE_RIGHT_HAND ].position = _handHoldingPosition;
|
||||
|
||||
// apply a force to the avatar body
|
||||
if ( glm::length(vectorToOtherHand) > _maxArmLength * 0.9 ) {
|
||||
_velocity += vectorToOtherHand;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_avatarTouch.setYourHandPosition( _interactingOther->_handPosition );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -344,19 +406,23 @@ void Avatar::simulate(float deltaTime) {
|
|||
// Set the vector we send for hand position to other people to be our right hand
|
||||
setHandPosition(_bone[ AVATAR_BONE_RIGHT_HAND ].position);
|
||||
|
||||
//update the effects of touching another avatar
|
||||
_avatarTouch.simulate(deltaTime);
|
||||
|
||||
}//if ( _isMine )
|
||||
|
||||
//constrain right arm length and re-adjust elbow position as it bends
|
||||
updateArmIKAndConstraints( deltaTime );
|
||||
|
||||
if (_isMine) {
|
||||
_avatarTouch.setMyHandPosition( _bone[ AVATAR_BONE_RIGHT_HAND ].position );
|
||||
|
||||
// set hand positions for _avatarTouch.setMyHandPosition AFTER calling updateArmIKAndConstraints
|
||||
if ( _interactingOther ) {
|
||||
if (_isMine) {
|
||||
_avatarTouch.setMyHandPosition ( _bone[ AVATAR_BONE_RIGHT_HAND ].position );
|
||||
_avatarTouch.setYourHandPosition( _interactingOther->_bone[ AVATAR_BONE_RIGHT_HAND ].position );
|
||||
_avatarTouch.setMyHandState ( _handState );
|
||||
_avatarTouch.setYourHandState ( _interactingOther->_handState );
|
||||
_avatarTouch.simulate(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_interactingOtherIsNearby) {
|
||||
if (!_avatarTouch.getAbleToReachOtherAvatar() ) {
|
||||
_interactingOther = NULL;
|
||||
}
|
||||
|
||||
|
@ -397,8 +463,10 @@ void Avatar::simulate(float deltaTime) {
|
|||
_bodyYaw += _bodyYawDelta * deltaTime;
|
||||
}
|
||||
|
||||
// decay body yaw delta
|
||||
_bodyYawDelta *= (1.0 - TEST_YAW_DECAY * deltaTime);
|
||||
// decay body rotation deltas
|
||||
_bodyPitchDelta *= (1.0 - BODY_PITCH_DECAY * deltaTime);
|
||||
_bodyYawDelta *= (1.0 - BODY_YAW_DECAY * deltaTime);
|
||||
_bodyRollDelta *= (1.0 - BODY_ROLL_DECAY * deltaTime);
|
||||
|
||||
// add thrust to velocity
|
||||
_velocity += _thrust * deltaTime;
|
||||
|
@ -423,17 +491,25 @@ void Avatar::simulate(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Avatar::updateHead(float deltaTime) {
|
||||
if (!_head.noise) {
|
||||
// Decay back toward center
|
||||
_headPitch *= (1.0f - DECAY * 2 * deltaTime);
|
||||
_headYaw *= (1.0f - DECAY * 2 * deltaTime);
|
||||
_headRoll *= (1.0f - DECAY * 2 * deltaTime);
|
||||
|
||||
//apply the head lean values to the springy position...
|
||||
if ( fabs( _head.leanSideways + _head.leanForward ) > 0.0f ) {
|
||||
glm::vec3 headLean =
|
||||
_orientation.getRight() * _head.leanSideways +
|
||||
_orientation.getFront() * _head.leanForward;
|
||||
_bone[ AVATAR_BONE_HEAD ].springyPosition += headLean;
|
||||
}
|
||||
else {
|
||||
|
||||
// Decay head back to center if turned on
|
||||
if (_returnHeadToCenter) {
|
||||
// Decay back toward center
|
||||
_headPitch *= (1.0f - DECAY * _head.returnSpringScale * 2 * deltaTime);
|
||||
_headYaw *= (1.0f - DECAY * _head.returnSpringScale * 2 * deltaTime);
|
||||
_headRoll *= (1.0f - DECAY * _head.returnSpringScale * 2 * deltaTime);
|
||||
}
|
||||
|
||||
if (_head.noise) {
|
||||
// Move toward new target
|
||||
_headPitch += (_head.pitchTarget - _headPitch) * 10 * deltaTime; // (1.f - DECAY*deltaTime)*Pitch + ;
|
||||
_headYaw += (_head.yawTarget - _headYaw ) * 10 * deltaTime; // (1.f - DECAY*deltaTime);
|
||||
|
@ -442,7 +518,7 @@ void Avatar::updateHead(float deltaTime) {
|
|||
|
||||
_head.leanForward *= (1.f - DECAY * 30 * deltaTime);
|
||||
_head.leanSideways *= (1.f - DECAY * 30 * deltaTime);
|
||||
|
||||
|
||||
// Update where the avatar's eyes are
|
||||
//
|
||||
// First, decide if we are making eye contact or not
|
||||
|
@ -482,7 +558,6 @@ void Avatar::updateHead(float deltaTime) {
|
|||
_head.eyeballPitch[0] = _head.eyeballPitch[1] = -_headPitch + eye_target_pitch_adjust;
|
||||
_head.eyeballYaw[0] = _head.eyeballYaw[1] = -_headYaw + eye_target_yaw_adjust;
|
||||
}
|
||||
|
||||
|
||||
if (_head.noise)
|
||||
{
|
||||
|
@ -597,18 +672,16 @@ void Avatar::updateCollisionWithOtherAvatar( Avatar * otherAvatar, float deltaTi
|
|||
// push balls away from each other and apply friction
|
||||
glm::vec3 ballPushForce = directionVector * COLLISION_BALL_FORCE * deltaTime;
|
||||
|
||||
|
||||
float ballMomentum = COLLISION_BALL_FRICTION * deltaTime;
|
||||
float ballMomentum = 1.0 - COLLISION_BALL_FRICTION * deltaTime;
|
||||
if ( ballMomentum < 0.0 ) { ballMomentum = 0.0;}
|
||||
|
||||
|
||||
_bone[b].springyVelocity += ballPushForce;
|
||||
otherAvatar->_bone[o].springyVelocity -= ballPushForce;
|
||||
|
||||
_bone[b].springyVelocity *= 0.9;
|
||||
otherAvatar->_bone[o].springyVelocity *= 0.9;
|
||||
_bone[b].springyVelocity *= ballMomentum;
|
||||
otherAvatar->_bone[o].springyVelocity *= ballMomentum;
|
||||
|
||||
// accumulate forces and frictions to the velocities of avatar bodies
|
||||
// accumulate forces and frictions to apply to the velocities of avatar bodies
|
||||
bodyPushForce += directionVector * COLLISION_BODY_FORCE * deltaTime;
|
||||
bodyMomentum -= COLLISION_BODY_FRICTION * deltaTime;
|
||||
if ( bodyMomentum < 0.0 ) { bodyMomentum = 0.0;}
|
||||
|
@ -631,13 +704,16 @@ void Avatar::updateCollisionWithOtherAvatar( Avatar * otherAvatar, float deltaTi
|
|||
} //method
|
||||
|
||||
|
||||
|
||||
|
||||
void Avatar::setDisplayingHead( bool displayingHead ) {
|
||||
_displayingHead = displayingHead;
|
||||
}
|
||||
|
||||
|
||||
static TextRenderer* textRenderer() {
|
||||
static TextRenderer* renderer = new TextRenderer(SANS_FONT_FAMILY, 24);
|
||||
return renderer;
|
||||
}
|
||||
|
||||
void Avatar::render(bool lookingInMirror) {
|
||||
|
||||
/*
|
||||
|
@ -651,7 +727,6 @@ void Avatar::render(bool lookingInMirror) {
|
|||
*/
|
||||
|
||||
if ( usingBigSphereCollisionTest ) {
|
||||
|
||||
// show TEST big sphere
|
||||
glColor4f( 0.5f, 0.6f, 0.8f, 0.7 );
|
||||
glPushMatrix();
|
||||
|
@ -661,7 +736,7 @@ void Avatar::render(bool lookingInMirror) {
|
|||
glPopMatrix();
|
||||
}
|
||||
|
||||
// render body
|
||||
//render body
|
||||
renderBody();
|
||||
|
||||
// render head
|
||||
|
@ -670,15 +745,11 @@ void Avatar::render(bool lookingInMirror) {
|
|||
}
|
||||
|
||||
// if this is my avatar, then render my interactions with the other avatar
|
||||
if ( _isMine )
|
||||
{
|
||||
if ( _interactingOtherIsNearby ) {
|
||||
_avatarTouch.render();
|
||||
}
|
||||
if ( _isMine ) {
|
||||
_avatarTouch.render();
|
||||
}
|
||||
|
||||
// Render the balls
|
||||
|
||||
if (_balls) {
|
||||
glPushMatrix();
|
||||
glTranslatef(_position.x, _position.y, _position.z);
|
||||
|
@ -687,10 +758,10 @@ void Avatar::render(bool lookingInMirror) {
|
|||
}
|
||||
|
||||
if (!_chatMessage.empty()) {
|
||||
float width = 0;
|
||||
float lastWidth;
|
||||
int width = 0;
|
||||
int lastWidth;
|
||||
for (string::iterator it = _chatMessage.begin(); it != _chatMessage.end(); it++) {
|
||||
width += (lastWidth = glutStrokeWidth(GLUT_STROKE_ROMAN, *it)*chatMessageScale);
|
||||
width += (lastWidth = textRenderer()->computeWidth(*it));
|
||||
}
|
||||
glPushMatrix();
|
||||
|
||||
|
@ -702,11 +773,14 @@ void Avatar::render(bool lookingInMirror) {
|
|||
|
||||
glTranslatef(_position.x, _position.y + chatMessageHeight, _position.z);
|
||||
glRotatef(atan2(-modelview[2], -modelview[10]) * 180 / PI, 0, 1, 0);
|
||||
glTranslatef(width * 0.5, 0, 0);
|
||||
|
||||
glColor3f(0, 0.8, 0);
|
||||
glRotatef(180, 0, 0, 1);
|
||||
glScalef(chatMessageScale, chatMessageScale, 1.0f);
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
if (_keyState == NO_KEY_DOWN) {
|
||||
drawtext(0, 0, chatMessageScale, 180, 1.0, 0, _chatMessage.c_str(), 0, 1, 0);
|
||||
textRenderer()->draw(-width/2, 0, _chatMessage.c_str());
|
||||
|
||||
} else {
|
||||
// rather than using substr and allocating a new string, just replace the last
|
||||
|
@ -714,11 +788,10 @@ void Avatar::render(bool lookingInMirror) {
|
|||
int lastIndex = _chatMessage.size() - 1;
|
||||
char lastChar = _chatMessage[lastIndex];
|
||||
_chatMessage[lastIndex] = '\0';
|
||||
drawtext(0, 0, chatMessageScale, 180, 1.0, 0, _chatMessage.c_str(), 0, 1, 0);
|
||||
textRenderer()->draw(-width/2, 0, _chatMessage.c_str());
|
||||
_chatMessage[lastIndex] = lastChar;
|
||||
glTranslatef(lastWidth - width, 0, 0);
|
||||
drawtext(0, 0, chatMessageScale, 180, 3.0,
|
||||
0, _chatMessage.c_str() + lastIndex, 0, 1, 0);
|
||||
glColor3f(0, 1, 0);
|
||||
textRenderer()->draw(width/2 - lastWidth, 0, _chatMessage.c_str() + lastIndex);
|
||||
}
|
||||
glEnable(GL_LIGHTING);
|
||||
|
||||
|
@ -733,7 +806,7 @@ void Avatar::renderHead(bool lookingInMirror) {
|
|||
glEnable(GL_RESCALE_NORMAL);
|
||||
|
||||
// show head orientation
|
||||
//renderOrientationDirections( _bone[ AVATAR_BONE_HEAD ].position, _bone[ AVATAR_BONE_HEAD ].orientation, 0.2f );
|
||||
//renderOrientationDirections( _bone[ AVATAR_BONE_HEAD ].springyPosition, _bone[ AVATAR_BONE_HEAD ].orientation, 0.2f );
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
|
@ -751,13 +824,13 @@ void Avatar::renderHead(bool lookingInMirror) {
|
|||
glScalef( 0.03, 0.03, 0.03 );
|
||||
|
||||
if (lookingInMirror) {
|
||||
glRotatef(_bodyYaw - _headYaw, 0, 1, 0);
|
||||
glRotatef(_bodyYaw - _headYaw, 0, 1, 0);
|
||||
glRotatef(_bodyPitch + _headPitch, 1, 0, 0);
|
||||
glRotatef(_bodyRoll - _headRoll, 0, 0, 1);
|
||||
glRotatef(_bodyRoll - _headRoll, 0, 0, 1);
|
||||
} else {
|
||||
glRotatef(_bodyYaw + _headYaw, 0, 1, 0);
|
||||
glRotatef(_bodyYaw + _headYaw, 0, 1, 0);
|
||||
glRotatef(_bodyPitch + _headPitch, 1, 0, 0);
|
||||
glRotatef(_bodyRoll + _headRoll, 0, 0, 1);
|
||||
glRotatef(_bodyRoll + _headRoll, 0, 0, 1);
|
||||
}
|
||||
|
||||
glScalef(2.0, 2.0, 2.0);
|
||||
|
@ -806,9 +879,7 @@ void Avatar::renderHead(bool lookingInMirror) {
|
|||
}
|
||||
glPopMatrix();
|
||||
|
||||
|
||||
// Mouth
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(0,-0.35,0.75);
|
||||
glColor3f(0,0,0);
|
||||
|
@ -911,7 +982,7 @@ void Avatar::initializeSkeleton() {
|
|||
_bone[b].roll = 0.0;
|
||||
_bone[b].length = 0.0;
|
||||
_bone[b].radius = 0.0;
|
||||
_bone[b].springBodyTightness = 4.0;
|
||||
_bone[b].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
|
||||
_bone[b].orientation.setToIdentity();
|
||||
}
|
||||
|
||||
|
@ -989,7 +1060,35 @@ void Avatar::initializeSkeleton() {
|
|||
_bone[ AVATAR_BONE_RIGHT_THIGH ].radius = 0.02;
|
||||
_bone[ AVATAR_BONE_RIGHT_SHIN ].radius = 0.015;
|
||||
_bone[ AVATAR_BONE_RIGHT_FOOT ].radius = 0.02;
|
||||
|
||||
|
||||
// specify the tightness of the springy positions as far as attraction to rigid body
|
||||
_bone[ AVATAR_BONE_PELVIS_SPINE ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 1.0;
|
||||
_bone[ AVATAR_BONE_MID_SPINE ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.8;
|
||||
_bone[ AVATAR_BONE_CHEST_SPINE ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5;
|
||||
_bone[ AVATAR_BONE_NECK ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.4;
|
||||
_bone[ AVATAR_BONE_HEAD ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.3;
|
||||
|
||||
_bone[ AVATAR_BONE_LEFT_CHEST ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5;
|
||||
_bone[ AVATAR_BONE_LEFT_SHOULDER ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5;
|
||||
_bone[ AVATAR_BONE_LEFT_UPPER_ARM ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5;
|
||||
_bone[ AVATAR_BONE_LEFT_FOREARM ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.3;
|
||||
_bone[ AVATAR_BONE_LEFT_HAND ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.3;
|
||||
|
||||
_bone[ AVATAR_BONE_RIGHT_CHEST ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5;
|
||||
_bone[ AVATAR_BONE_RIGHT_SHOULDER ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5;
|
||||
_bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5;
|
||||
_bone[ AVATAR_BONE_RIGHT_FOREARM ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.3;
|
||||
_bone[ AVATAR_BONE_RIGHT_HAND ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.3;
|
||||
|
||||
_bone[ AVATAR_BONE_LEFT_PELVIS ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
|
||||
_bone[ AVATAR_BONE_LEFT_THIGH ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
|
||||
_bone[ AVATAR_BONE_LEFT_SHIN ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
|
||||
_bone[ AVATAR_BONE_LEFT_FOOT ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
|
||||
_bone[ AVATAR_BONE_RIGHT_PELVIS ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
|
||||
_bone[ AVATAR_BONE_RIGHT_THIGH ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
|
||||
_bone[ AVATAR_BONE_RIGHT_SHIN ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
|
||||
_bone[ AVATAR_BONE_RIGHT_FOOT ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
|
||||
|
||||
// to aid in hand-shaking and hand-holding, the right hand is not collidable
|
||||
_bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].isCollidable = false;
|
||||
_bone[ AVATAR_BONE_RIGHT_FOREARM ].isCollidable = false;
|
||||
|
@ -1051,7 +1150,7 @@ void Avatar::updateSkeleton() {
|
|||
_bone[ AVATAR_BONE_RIGHT_HAND ].position = _handPosition;
|
||||
}
|
||||
|
||||
// the following will be replaced by a proper rotation...
|
||||
// the following will be replaced by a proper rotation...close
|
||||
float xx = glm::dot( _bone[b].defaultPosePosition, _bone[b].orientation.getRight() );
|
||||
float yy = glm::dot( _bone[b].defaultPosePosition, _bone[b].orientation.getUp () );
|
||||
float zz = glm::dot( _bone[b].defaultPosePosition, _bone[b].orientation.getFront() );
|
||||
|
@ -1115,20 +1214,22 @@ void Avatar::updateBodySprings( float deltaTime ) {
|
|||
|
||||
const glm::vec3& Avatar::getHeadPosition() const {
|
||||
|
||||
if (_usingBodySprings) {
|
||||
return _bone[ AVATAR_BONE_HEAD ].springyPosition;
|
||||
}
|
||||
|
||||
//if (_usingBodySprings) {
|
||||
// return _bone[ AVATAR_BONE_HEAD ].springyPosition;
|
||||
//}
|
||||
|
||||
return _bone[ AVATAR_BONE_HEAD ].position;
|
||||
}
|
||||
|
||||
|
||||
void Avatar::updateHandMovement( float deltaTime ) {
|
||||
glm::vec3 transformedHandMovement;
|
||||
|
||||
transformedHandMovement
|
||||
= _orientation.getRight() * _movedHandOffset.x
|
||||
+ _orientation.getUp() * -_movedHandOffset.y * 0.5f
|
||||
+ _orientation.getFront() * -_movedHandOffset.y;
|
||||
= _orientation.getRight() * _movedHandOffset.x * 2.0f
|
||||
+ _orientation.getUp() * -_movedHandOffset.y * 1.0f
|
||||
+ _orientation.getFront() * -_movedHandOffset.y * 1.0f;
|
||||
|
||||
_bone[ AVATAR_BONE_RIGHT_HAND ].position += transformedHandMovement;
|
||||
|
||||
|
@ -1162,7 +1263,9 @@ void Avatar::updateArmIKAndConstraints( float deltaTime ) {
|
|||
// set elbow position
|
||||
glm::vec3 newElbowPosition = _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position;
|
||||
newElbowPosition += armVector * ONE_HALF;
|
||||
|
||||
glm::vec3 perpendicular = glm::cross( _orientation.getFront(), armVector );
|
||||
|
||||
newElbowPosition += perpendicular * ( 1.0f - ( _maxArmLength / distance ) ) * ONE_HALF;
|
||||
_bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].position = newElbowPosition;
|
||||
|
||||
|
@ -1232,6 +1335,7 @@ void Avatar::renderBody() {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// if the hand is grasping, show it...
|
||||
if (( _usingBodySprings ) && ( _handState == 1 )) {
|
||||
glPushMatrix();
|
||||
|
@ -1244,6 +1348,7 @@ void Avatar::renderBody() {
|
|||
|
||||
glPopMatrix();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void Avatar::SetNewHeadTarget(float pitch, float yaw) {
|
||||
|
@ -1251,14 +1356,21 @@ void Avatar::SetNewHeadTarget(float pitch, float yaw) {
|
|||
_head.yawTarget = yaw;
|
||||
}
|
||||
|
||||
// getting data from Android transmitte app
|
||||
// Process UDP interface data from Android transmitter or Google Glass
|
||||
void Avatar::processTransmitterData(unsigned char* packetData, int numBytes) {
|
||||
// Read a packet from a transmitter app, process the data
|
||||
float accX, accY, accZ,
|
||||
graX, graY, graZ,
|
||||
gyrX, gyrY, gyrZ,
|
||||
linX, linY, linZ,
|
||||
rot1, rot2, rot3, rot4;
|
||||
float
|
||||
accX, accY, accZ, // Measured acceleration
|
||||
graX, graY, graZ, // Gravity
|
||||
gyrX, gyrY, gyrZ, // Gyro velocity in radians/sec as (pitch, roll, yaw)
|
||||
linX, linY, linZ, // Linear Acceleration (less gravity)
|
||||
rot1, rot2, rot3, rot4; // Rotation of device:
|
||||
// rot1 = roll, ranges from -1 to 1, 0 = flat on table
|
||||
// rot2 = pitch, ranges from -1 to 1, 0 = flat on table
|
||||
// rot3 = yaw, ranges from -1 to 1
|
||||
|
||||
const bool IS_GLASS = false; // Whether to assume this is a Google glass transmitting
|
||||
|
||||
sscanf((char *)packetData, "tacc %f %f %f gra %f %f %f gyr %f %f %f lin %f %f %f rot %f %f %f %f",
|
||||
&accX, &accY, &accZ,
|
||||
&graX, &graY, &graZ,
|
||||
|
@ -1267,7 +1379,21 @@ void Avatar::processTransmitterData(unsigned char* packetData, int numBytes) {
|
|||
&rot1, &rot2, &rot3, &rot4);
|
||||
|
||||
if (_transmitterPackets++ == 0) {
|
||||
// If first packet received, note time, turn head spring return OFF, get start rotation
|
||||
gettimeofday(&_transmitterTimer, NULL);
|
||||
if (IS_GLASS) {
|
||||
setHeadReturnToCenter(true);
|
||||
setHeadSpringScale(10.f);
|
||||
printLog("Using Google Glass to drive head, springs ON.\n");
|
||||
|
||||
} else {
|
||||
setHeadReturnToCenter(false);
|
||||
printLog("Using Transmitter to drive head, springs OFF.\n");
|
||||
|
||||
}
|
||||
_transmitterInitialReading = glm::vec3( rot3,
|
||||
rot2,
|
||||
rot1 );
|
||||
}
|
||||
const int TRANSMITTER_COUNT = 100;
|
||||
if (_transmitterPackets % TRANSMITTER_COUNT == 0) {
|
||||
|
@ -1275,27 +1401,71 @@ void Avatar::processTransmitterData(unsigned char* packetData, int numBytes) {
|
|||
timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
double msecsElapsed = diffclock(&_transmitterTimer, &now);
|
||||
_transmitterHz = static_cast<float>( (double)TRANSMITTER_COUNT/(msecsElapsed/1000.0) );
|
||||
_transmitterHz = static_cast<float>( (double)TRANSMITTER_COUNT / (msecsElapsed / 1000.0) );
|
||||
_transmitterTimer = now;
|
||||
printLog("Transmitter Hz: %3.1f\n", _transmitterHz);
|
||||
}
|
||||
//printLog("Gyr: %3.1f, %3.1f, %3.1f\n", glm::degrees(gyrZ), glm::degrees(-gyrX), glm::degrees(gyrY));
|
||||
//printLog("Rot: %3.1f, %3.1f, %3.1f, %3.1f\n", rot1, rot2, rot3, rot4);
|
||||
|
||||
// Update the head with the transmitter data
|
||||
glm::vec3 eulerAngles((rot3 - _transmitterInitialReading.x) * 180.f,
|
||||
-(rot2 - _transmitterInitialReading.y) * 180.f,
|
||||
(rot1 - _transmitterInitialReading.z) * 180.f);
|
||||
if (eulerAngles.x > 180.f) { eulerAngles.x -= 360.f; }
|
||||
if (eulerAngles.x < -180.f) { eulerAngles.x += 360.f; }
|
||||
|
||||
glm::vec3 angularVelocity;
|
||||
if (!IS_GLASS) {
|
||||
angularVelocity = glm::vec3(glm::degrees(gyrZ), glm::degrees(-gyrX), glm::degrees(gyrY));
|
||||
setHeadFromGyros( &eulerAngles, &angularVelocity,
|
||||
(_transmitterHz == 0.f) ? 0.f : 1.f / _transmitterHz, 1.0);
|
||||
|
||||
} else {
|
||||
angularVelocity = glm::vec3(glm::degrees(gyrY), glm::degrees(-gyrX), glm::degrees(-gyrZ));
|
||||
setHeadFromGyros( &eulerAngles, &angularVelocity,
|
||||
(_transmitterHz == 0.f) ? 0.f : 1.f / _transmitterHz, 1000.0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Avatar::setHeadFromGyros(glm::vec3* eulerAngles, glm::vec3* angularVelocity, float deltaTime, float smoothingTime) {
|
||||
//
|
||||
// Given absolute position and angular velocity information, update the avatar's head angles
|
||||
// with the goal of fast instantaneous updates that gradually follow the absolute data.
|
||||
//
|
||||
// Euler Angle format is (Yaw, Pitch, Roll) in degrees
|
||||
//
|
||||
// Angular Velocity is (Yaw, Pitch, Roll) in degrees per second
|
||||
//
|
||||
// SMOOTHING_TIME is the time is seconds over which the head should average to the
|
||||
// absolute eulerAngles passed.
|
||||
//
|
||||
//
|
||||
float const MAX_YAW = 90.f;
|
||||
float const MIN_YAW = -90.f;
|
||||
float const MAX_PITCH = 85.f;
|
||||
float const MIN_PITCH = -85.f;
|
||||
float const MAX_ROLL = 90.f;
|
||||
float const MIN_ROLL = -90.f;
|
||||
|
||||
if (deltaTime == 0.f) {
|
||||
// On first sample, set head to absolute position
|
||||
setHeadYaw(eulerAngles->x);
|
||||
setHeadPitch(eulerAngles->y);
|
||||
setHeadRoll(eulerAngles->z);
|
||||
} else {
|
||||
glm::vec3 angles(getHeadYaw(), getHeadPitch(), getHeadRoll());
|
||||
// Increment by detected velocity
|
||||
angles += (*angularVelocity) * deltaTime;
|
||||
// Smooth to slowly follow absolute values
|
||||
angles = ((1.f - deltaTime / smoothingTime) * angles) + (deltaTime / smoothingTime) * (*eulerAngles);
|
||||
setHeadYaw(fmin(fmax(angles.x, MIN_YAW), MAX_YAW));
|
||||
setHeadPitch(fmin(fmax(angles.y, MIN_PITCH), MAX_PITCH));
|
||||
setHeadRoll(fmin(fmax(angles.z, MIN_ROLL), MAX_ROLL));
|
||||
//printLog("Y/P/R: %3.1f, %3.1f, %3.1f\n", angles.x, angles.y, angles.z);
|
||||
}
|
||||
/* NOTE: PR: Will add back in when ready to animate avatar hand
|
||||
|
||||
// Add rotational forces to the hand
|
||||
const float ANG_VEL_SENSITIVITY = 4.0;
|
||||
const float ANG_VEL_THRESHOLD = 0.0;
|
||||
float angVelScale = ANG_VEL_SENSITIVITY*(1.0f/getTransmitterHz());
|
||||
|
||||
addAngularVelocity(fabs(gyrX*angVelScale)>ANG_VEL_THRESHOLD?gyrX*angVelScale:0,
|
||||
fabs(gyrZ*angVelScale)>ANG_VEL_THRESHOLD?gyrZ*angVelScale:0,
|
||||
fabs(-gyrY*angVelScale)>ANG_VEL_THRESHOLD?-gyrY*angVelScale:0);
|
||||
|
||||
// Add linear forces to the hand
|
||||
//const float LINEAR_VEL_SENSITIVITY = 50.0;
|
||||
const float LINEAR_VEL_SENSITIVITY = 5.0;
|
||||
float linVelScale = LINEAR_VEL_SENSITIVITY*(1.0f/getTransmitterHz());
|
||||
glm::vec3 linVel(linX*linVelScale, linZ*linVelScale, -linY*linVelScale);
|
||||
addVelocity(linVel);
|
||||
*/
|
||||
}
|
||||
|
||||
// Find and return the gravity vector at my location
|
||||
|
|
|
@ -72,7 +72,6 @@ enum AvatarBoneID
|
|||
NUM_AVATAR_BONES
|
||||
};
|
||||
|
||||
|
||||
class Avatar : public AvatarData {
|
||||
public:
|
||||
Avatar(bool isMine);
|
||||
|
@ -93,8 +92,8 @@ public:
|
|||
float getBodyYaw() {return _bodyYaw;};
|
||||
void addBodyYaw(float y) {_bodyYaw += y;};
|
||||
|
||||
bool getIsNearInteractingOther() { return _interactingOtherIsNearby; }
|
||||
|
||||
bool getIsNearInteractingOther();
|
||||
|
||||
float getAbsoluteHeadYaw() const;
|
||||
void setLeanForward(float dist);
|
||||
void setLeanSideways(float dist);
|
||||
|
@ -123,7 +122,7 @@ public:
|
|||
void setDisplayingHead( bool displayingHead );
|
||||
|
||||
float getAverageLoudness() {return _head.averageLoudness;};
|
||||
void setAverageLoudness(float al) {_head.averageLoudness = al;};
|
||||
void setAverageLoudness(float al) {_head.averageLoudness = al;};
|
||||
|
||||
void SetNewHeadTarget(float, float);
|
||||
|
||||
|
@ -145,27 +144,29 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
const bool AVATAR_GRAVITY = true;
|
||||
const float DECAY = 0.1;
|
||||
const float THRUST_MAG = 1200.0;
|
||||
const float YAW_MAG = 500.0; //JJV - changed from 300.0;
|
||||
const float TEST_YAW_DECAY = 5.0;
|
||||
const float LIN_VEL_DECAY = 5.0;
|
||||
const float MY_HAND_HOLDING_PULL = 0.2;
|
||||
const float YOUR_HAND_HOLDING_PULL = 1.0;
|
||||
const float BODY_SPRING_FORCE = 6.0f;
|
||||
const float BODY_SPRING_DECAY = 16.0f;
|
||||
const bool BALLS_ON = false;
|
||||
const bool AVATAR_GRAVITY = true;
|
||||
const float DECAY = 0.1;
|
||||
const float THRUST_MAG = 1200.0;
|
||||
const float YAW_MAG = 500.0;
|
||||
const float BODY_PITCH_DECAY = 5.0;
|
||||
const float BODY_YAW_DECAY = 5.0;
|
||||
const float BODY_ROLL_DECAY = 5.0;
|
||||
const float LIN_VEL_DECAY = 5.0;
|
||||
const float MY_HAND_HOLDING_PULL = 0.2;
|
||||
const float YOUR_HAND_HOLDING_PULL = 1.0;
|
||||
const float BODY_SPRING_FORCE = 6.0f;
|
||||
const float BODY_SPRING_DECAY = 16.0f;
|
||||
const float BODY_SPRING_DEFAULT_TIGHTNESS = 10.0f;
|
||||
const float COLLISION_RADIUS_SCALAR = 1.8;
|
||||
const float COLLISION_BALL_FORCE = 1.0;
|
||||
const float COLLISION_BODY_FORCE = 6.0;
|
||||
const float COLLISION_BALL_FRICTION = 60.0;
|
||||
const float COLLISION_BODY_FRICTION = 0.5;
|
||||
|
||||
//const float COLLISION_FRICTION = 0.5;
|
||||
//const float COLLISION_RADIUS_SCALAR = 1.8;
|
||||
//const float COLLISION_BALL_FORCE = 0.1;
|
||||
//const float COLLISION_BODY_FORCE = 3.0;
|
||||
|
||||
const float COLLISION_RADIUS_SCALAR = 1.8;
|
||||
const float COLLISION_BALL_FORCE = 0.6;
|
||||
const float COLLISION_BODY_FORCE = 6.0;
|
||||
const float COLLISION_BALL_FRICTION = 200.0;
|
||||
const float COLLISION_BODY_FRICTION = 0.5;
|
||||
// Do you want head to try to return to center (depends on interface detected)
|
||||
void setHeadReturnToCenter(bool r) { _returnHeadToCenter = r; };
|
||||
const bool getHeadReturnToCenter() const { return _returnHeadToCenter; };
|
||||
|
||||
struct AvatarBone
|
||||
{
|
||||
|
@ -221,40 +222,48 @@ private:
|
|||
float lastLoudness;
|
||||
float averageLoudness;
|
||||
float audioAttack;
|
||||
|
||||
// Strength of return springs
|
||||
float returnSpringScale;
|
||||
};
|
||||
|
||||
AvatarHead _head;
|
||||
bool _isMine;
|
||||
glm::vec3 _TEST_bigSpherePosition;
|
||||
float _TEST_bigSphereRadius;
|
||||
bool _mousePressed;
|
||||
float _bodyYawDelta;
|
||||
bool _usingBodySprings;
|
||||
glm::vec3 _movedHandOffset;
|
||||
glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion
|
||||
AvatarBone _bone[ NUM_AVATAR_BONES ];
|
||||
AvatarMode _mode;
|
||||
glm::vec3 _handHoldingPosition;
|
||||
glm::vec3 _velocity;
|
||||
glm::vec3 _thrust;
|
||||
float _speed;
|
||||
float _maxArmLength;
|
||||
Orientation _orientation;
|
||||
int _driveKeys[MAX_DRIVE_KEYS];
|
||||
GLUquadric* _sphere;
|
||||
float _renderYaw;
|
||||
float _renderPitch; // Pitch from view frustum when this is own head
|
||||
timeval _transmitterTimer;
|
||||
float _transmitterHz;
|
||||
int _transmitterPackets;
|
||||
Avatar* _interactingOther;
|
||||
bool _interactingOtherIsNearby;
|
||||
float _pelvisStandingHeight;
|
||||
float _height;
|
||||
Balls* _balls;
|
||||
AvatarTouch _avatarTouch;
|
||||
bool _displayingHead; // should be false if in first-person view
|
||||
|
||||
AvatarHead _head;
|
||||
bool _isMine;
|
||||
glm::vec3 _TEST_bigSpherePosition;
|
||||
float _TEST_bigSphereRadius;
|
||||
bool _mousePressed;
|
||||
float _bodyPitchDelta;
|
||||
float _bodyYawDelta;
|
||||
float _bodyRollDelta;
|
||||
bool _usingBodySprings;
|
||||
glm::vec3 _movedHandOffset;
|
||||
glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion
|
||||
AvatarBone _bone[ NUM_AVATAR_BONES ];
|
||||
AvatarMode _mode;
|
||||
glm::vec3 _handHoldingPosition;
|
||||
glm::vec3 _velocity;
|
||||
glm::vec3 _thrust;
|
||||
float _speed;
|
||||
float _maxArmLength;
|
||||
Orientation _orientation;
|
||||
int _driveKeys[MAX_DRIVE_KEYS];
|
||||
GLUquadric* _sphere;
|
||||
float _renderYaw;
|
||||
float _renderPitch; // Pitch from view frustum when this is own head
|
||||
bool _transmitterIsFirstData;
|
||||
timeval _transmitterTimeLastReceived;
|
||||
timeval _transmitterTimer;
|
||||
float _transmitterHz;
|
||||
int _transmitterPackets;
|
||||
glm::vec3 _transmitterInitialReading;
|
||||
Avatar* _interactingOther;
|
||||
float _pelvisStandingHeight;
|
||||
float _height;
|
||||
Balls* _balls;
|
||||
AvatarTouch _avatarTouch;
|
||||
bool _displayingHead; // should be false if in first-person view
|
||||
bool _returnHeadToCenter;
|
||||
|
||||
// private methods...
|
||||
void initializeSkeleton();
|
||||
void updateSkeleton();
|
||||
|
@ -265,6 +274,8 @@ private:
|
|||
void updateHead( float deltaTime );
|
||||
void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime );
|
||||
void updateCollisionWithOtherAvatar( Avatar * other, float deltaTime );
|
||||
void setHeadFromGyros(glm::vec3 * eulerAngles, glm::vec3 * angularVelocity, float deltaTime, float smoothingTime);
|
||||
void setHeadSpringScale(float s) { _head.returnSpringScale = s; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,12 +11,18 @@
|
|||
#include "AvatarTouch.h"
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
const float THREAD_RADIUS = 0.012;
|
||||
|
||||
AvatarTouch::AvatarTouch() {
|
||||
|
||||
_myHandPosition = glm::vec3( 0.0f, 0.0f, 0.0f );
|
||||
_yourHandPosition = glm::vec3( 0.0f, 0.0f, 0.0f );
|
||||
_myHandState = 0;
|
||||
_yourHandState = 0;
|
||||
|
||||
_canReachToOtherAvatar = false;
|
||||
_handsCloseEnoughToGrasp = false;
|
||||
|
||||
for (int p=0; p<NUM_POINTS; p++) {
|
||||
_point[p] = glm::vec3( 0.0, 0.0, 0.0 );
|
||||
}
|
||||
|
@ -30,27 +36,61 @@ void AvatarTouch::setYourHandPosition( glm::vec3 position ) {
|
|||
_yourHandPosition = position;
|
||||
}
|
||||
|
||||
void AvatarTouch::setMyHandState( int state ) {
|
||||
_myHandState = state;
|
||||
}
|
||||
|
||||
void AvatarTouch::setYourHandState( int state ) {
|
||||
_yourHandState = state;
|
||||
}
|
||||
|
||||
void AvatarTouch::render() {
|
||||
|
||||
glm::vec3 v1( _myHandPosition );
|
||||
glm::vec3 v2( _yourHandPosition );
|
||||
|
||||
if (_canReachToOtherAvatar) {
|
||||
// if my hand is grasping, show it...
|
||||
if ( _myHandState == 1 ) {
|
||||
glPushMatrix();
|
||||
glTranslatef(_myHandPosition.x, _myHandPosition.y, _myHandPosition.z);
|
||||
glColor4f( 1.0, 1.0, 0.8, 0.3 ); glutSolidSphere( 0.020f, 10.0f, 10.0f );
|
||||
glColor4f( 1.0, 1.0, 0.4, 0.2 ); glutSolidSphere( 0.025f, 10.0f, 10.0f );
|
||||
glColor4f( 1.0, 1.0, 0.2, 0.1 ); glutSolidSphere( 0.030f, 10.0f, 10.0f );
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
// if your hand is grasping, show it...
|
||||
if ( _yourHandState == 1 ) {
|
||||
glPushMatrix();
|
||||
glTranslatef(_yourHandPosition.x, _yourHandPosition.y, _yourHandPosition.z);
|
||||
glColor4f( 1.0, 1.0, 0.8, 0.3 ); glutSolidSphere( 0.020f, 10.0f, 10.0f );
|
||||
glColor4f( 1.0, 1.0, 0.4, 0.2 ); glutSolidSphere( 0.025f, 10.0f, 10.0f );
|
||||
glColor4f( 1.0, 1.0, 0.2, 0.1 ); glutSolidSphere( 0.030f, 10.0f, 10.0f );
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
glLineWidth( 2.0 );
|
||||
glColor4f( 0.7f, 0.4f, 0.1f, 0.3 );
|
||||
glBegin( GL_LINE_STRIP );
|
||||
glVertex3f( v1.x, v1.y, v1.z );
|
||||
glVertex3f( v2.x, v2.y, v2.z );
|
||||
glEnd();
|
||||
|
||||
glColor4f( 1.0f, 1.0f, 0.0f, 0.8 );
|
||||
|
||||
for (int p=0; p<NUM_POINTS; p++) {
|
||||
glBegin(GL_POINTS);
|
||||
glVertex3f(_point[p].x, _point[p].y, _point[p].z);
|
||||
//show beam
|
||||
if (_handsCloseEnoughToGrasp) {
|
||||
glLineWidth( 2.0 );
|
||||
glColor4f( 0.7f, 0.4f, 0.1f, 0.3 );
|
||||
glBegin( GL_LINE_STRIP );
|
||||
glVertex3f( v1.x, v1.y, v1.z );
|
||||
glVertex3f( v2.x, v2.y, v2.z );
|
||||
glEnd();
|
||||
}
|
||||
|
||||
glColor4f( 1.0f, 1.0f, 0.0f, 0.8 );
|
||||
|
||||
for (int p=0; p<NUM_POINTS; p++) {
|
||||
glBegin(GL_POINTS);
|
||||
glVertex3f(_point[p].x, _point[p].y, _point[p].z);
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AvatarTouch::simulate (float deltaTime) {
|
||||
|
||||
glm::vec3 v = _yourHandPosition - _myHandPosition;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// interface
|
||||
//
|
||||
// Created by Jeffrey Ventrella
|
||||
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__AvatarTouch__
|
||||
|
@ -13,15 +13,25 @@
|
|||
|
||||
class AvatarTouch {
|
||||
public:
|
||||
|
||||
const float HANDS_CLOSE_ENOUGH_TO_GRASP = 0.1;
|
||||
|
||||
AvatarTouch();
|
||||
|
||||
void simulate(float deltaTime);
|
||||
void render();
|
||||
|
||||
void setMyHandPosition ( glm::vec3 position );
|
||||
void setYourHandPosition( glm::vec3 position );
|
||||
void simulate(float deltaTime);
|
||||
void render();
|
||||
|
||||
const float THREAD_RADIUS = 0.007;
|
||||
void setMyHandState ( int state );
|
||||
void setYourHandState ( int state );
|
||||
|
||||
void setAbleToReachOtherAvatar ( bool a ) { _canReachToOtherAvatar = a; }
|
||||
void setHandsCloseEnoughToGrasp( bool h ) { _handsCloseEnoughToGrasp = h; }
|
||||
|
||||
bool getAbleToReachOtherAvatar () { return _canReachToOtherAvatar; }
|
||||
bool getHandsCloseEnoughToGrasp() { return _handsCloseEnoughToGrasp; }
|
||||
|
||||
private:
|
||||
|
||||
static const int NUM_POINTS = 100;
|
||||
|
@ -29,6 +39,10 @@ private:
|
|||
glm::vec3 _point [NUM_POINTS];
|
||||
glm::vec3 _myHandPosition;
|
||||
glm::vec3 _yourHandPosition;
|
||||
int _myHandState;
|
||||
int _yourHandState;
|
||||
bool _canReachToOtherAvatar;
|
||||
bool _handsCloseEnoughToGrasp;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -34,12 +34,6 @@ Camera::Camera() {
|
|||
|
||||
void Camera::update( float deltaTime ) {
|
||||
|
||||
// generate the ortho-normals for the orientation based on the Euler angles
|
||||
_orientation.setToIdentity();
|
||||
_orientation.yaw ( _yaw );
|
||||
_orientation.pitch( _pitch );
|
||||
_orientation.roll ( _roll );
|
||||
|
||||
if ( _mode == CAMERA_MODE_NULL ) {
|
||||
_modeShift = 0.0;
|
||||
} else {
|
||||
|
@ -53,6 +47,19 @@ void Camera::update( float deltaTime ) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// do this AFTER making any changes to yaw pitch and roll....
|
||||
generateOrientation();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// generate the ortho-normals for the orientation based on the three Euler angles
|
||||
void Camera::generateOrientation() {
|
||||
_orientation.setToIdentity();
|
||||
_orientation.pitch( _pitch );
|
||||
_orientation.yaw ( _yaw );
|
||||
_orientation.roll ( _roll );
|
||||
}
|
||||
|
||||
|
||||
|
@ -71,9 +78,8 @@ void Camera::updateFollowMode( float deltaTime ) {
|
|||
float radian = (_yaw / 180.0) * PIE;
|
||||
|
||||
// update _position
|
||||
//these need to be checked to make sure they correspond to the correct coordinate system.
|
||||
double x = _distance * -sin(radian);
|
||||
double z = _distance * cos(radian);
|
||||
double x = -_distance * sin(radian);
|
||||
double z = -_distance * cos(radian);
|
||||
double y = _upShift;
|
||||
|
||||
_idealPosition = _targetPosition + glm::vec3(x, y, z);
|
||||
|
|
|
@ -38,7 +38,6 @@ public:
|
|||
void setTargetPosition( glm::vec3 t ) { _targetPosition = t; }
|
||||
void setTargetYaw ( float y ) { _idealYaw = y; }
|
||||
void setPosition ( glm::vec3 p ) { _position = p; }
|
||||
void setOrientation ( Orientation o ) { _orientation.set(o); }
|
||||
void setTightness ( float t ) { _tightness = t; }
|
||||
|
||||
void setMode ( CameraMode m );
|
||||
|
@ -83,6 +82,7 @@ private:
|
|||
float _tightness;
|
||||
Orientation _orientation;
|
||||
|
||||
void generateOrientation();
|
||||
void updateFollowMode( float deltaTime );
|
||||
};
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <stdarg.h>
|
||||
|
||||
#include "Util.h"
|
||||
#include "ui/TextRenderer.h"
|
||||
|
||||
namespace {
|
||||
// anonymous namespace - everything in here only exists within this very .cpp file
|
||||
|
@ -23,6 +24,8 @@ namespace {
|
|||
unsigned const LINE_BUFFER_SIZE = 256; // number of lines that are buffered
|
||||
unsigned const MAX_MESSAGE_LENGTH = 512; // maximum number of characters for a message
|
||||
|
||||
const char* FONT_FAMILY = SANS_FONT_FAMILY;
|
||||
|
||||
bool const TEXT_MONOSPACED = true;
|
||||
|
||||
float const TEXT_RED = 0.7f;
|
||||
|
@ -194,6 +197,11 @@ void Log::setCharacterSize(unsigned width, unsigned height) {
|
|||
pthread_mutex_unlock(& _mtx);
|
||||
}
|
||||
|
||||
static TextRenderer* textRenderer() {
|
||||
static TextRenderer* renderer = new TextRenderer(FONT_FAMILY);
|
||||
return renderer;
|
||||
}
|
||||
|
||||
void Log::render(unsigned screenWidth, unsigned screenHeight) {
|
||||
|
||||
// rendering might take some time, so create a local copy of the portion we need
|
||||
|
@ -261,10 +269,8 @@ void Log::render(unsigned screenWidth, unsigned screenHeight) {
|
|||
}
|
||||
|
||||
// get values for rendering
|
||||
float scaleFactor = _valCharScale;
|
||||
int yStart = int((screenHeight - _valCharYoffset) / _valCharAspect);
|
||||
int yStep = int(_valCharHeight / _valCharAspect);
|
||||
float yScale = _valCharAspect;
|
||||
int yStep = textRenderer()->metrics().lineSpacing();
|
||||
int yStart = screenHeight - textRenderer()->metrics().descent();
|
||||
|
||||
// render text
|
||||
char** line = _ptrLinesEnd + showLines;
|
||||
|
@ -273,11 +279,6 @@ void Log::render(unsigned screenWidth, unsigned screenHeight) {
|
|||
pthread_mutex_unlock(& _mtx);
|
||||
// ok, we got all we need
|
||||
|
||||
GLint matrixMode;
|
||||
glGetIntegerv(GL_MATRIX_MODE, & matrixMode);
|
||||
glPushMatrix();
|
||||
glScalef(1.0f, yScale, 1.0f);
|
||||
|
||||
for (int y = yStart; y > 0; y -= yStep) {
|
||||
|
||||
// debug mode: check line pointer is valid
|
||||
|
@ -299,14 +300,11 @@ void Log::render(unsigned screenWidth, unsigned screenHeight) {
|
|||
assert(! (chars < _ptrCharsEnd || chars >= _ptrCharsEnd + (_ptrCharsEnd - _arrChars)));
|
||||
|
||||
// render the string
|
||||
drawtext(x, y, scaleFactor, 0.0f, 1.0f, int(TEXT_MONOSPACED),
|
||||
chars, TEXT_RED, TEXT_GREEN, TEXT_BLUE);
|
||||
glColor3f(TEXT_RED, TEXT_GREEN, TEXT_BLUE);
|
||||
textRenderer()->draw(x, y, chars);
|
||||
|
||||
//fprintf(stderr, "Log::render, message = \"%s\"\n", chars);
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
glMatrixMode(matrixMode);
|
||||
}
|
||||
|
||||
Log logger;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <SharedUtil.h>
|
||||
|
||||
#include "Log.h"
|
||||
#include "ui/TextRenderer.h"
|
||||
#include "world.h"
|
||||
#include "Util.h"
|
||||
|
||||
|
@ -25,7 +26,6 @@ using namespace std;
|
|||
// see http://www.opengl.org/resources/libraries/glut/spec3/node78.html
|
||||
static float MONO_STROKE_WIDTH_GLUT = 104.76;
|
||||
|
||||
|
||||
void eulerToOrthonormals(glm::vec3 * angles, glm::vec3 * front, glm::vec3 * right, glm::vec3 * up) {
|
||||
//
|
||||
// Converts from three euler angles to the associated orthonormal vectors
|
||||
|
@ -152,19 +152,18 @@ double diffclock(timeval *clock1,timeval *clock2)
|
|||
return diffms;
|
||||
}
|
||||
|
||||
static TextRenderer* textRenderer(int mono) {
|
||||
static TextRenderer* monoRenderer = new TextRenderer(MONO_FONT_FAMILY);
|
||||
static TextRenderer* proportionalRenderer = new TextRenderer(SANS_FONT_FAMILY);
|
||||
return mono ? monoRenderer : proportionalRenderer;
|
||||
}
|
||||
|
||||
int widthText(float scale, int mono, char const* string) {
|
||||
int width = 0;
|
||||
if (!mono) {
|
||||
width = scale * glutStrokeLength(GLUT_STROKE_ROMAN, (const unsigned char *) string);
|
||||
} else {
|
||||
#ifndef WORKAROUND_BROKEN_GLUT_STROKES
|
||||
width = scale * glutStrokeLength(GLUT_STROKE_MONO_ROMAN, (const unsigned char *) string);
|
||||
#else
|
||||
// return value is unreliable, so just calculate it
|
||||
width = scale * float(strlen(string)) * MONO_STROKE_WIDTH_GLUT;
|
||||
#endif
|
||||
}
|
||||
return width;
|
||||
return textRenderer(mono)->computeWidth(string) * (scale / 0.10);
|
||||
}
|
||||
|
||||
float widthChar(float scale, int mono, char ch) {
|
||||
return textRenderer(mono)->computeWidth(ch) * (scale / 0.10);
|
||||
}
|
||||
|
||||
void drawtext(int x, int y, float scale, float rotate, float thick, int mono,
|
||||
|
@ -177,35 +176,12 @@ void drawtext(int x, int y, float scale, float rotate, float thick, int mono,
|
|||
glPushMatrix();
|
||||
glTranslatef( static_cast<float>(x), static_cast<float>(y), 0.0f);
|
||||
glColor3f(r,g,b);
|
||||
glRotated(180+rotate,0,0,1);
|
||||
glRotated(180,0,1,0);
|
||||
glLineWidth(thick);
|
||||
glScalef(scale, scale, 1.0);
|
||||
len = (int) strlen(string);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if (!mono) {
|
||||
glutStrokeCharacter(GLUT_STROKE_ROMAN, int(string[i]));
|
||||
} else {
|
||||
#ifdef WORKAROUND_BROKEN_GLUT_STROKES
|
||||
if (string[i] != 'm') {
|
||||
#endif
|
||||
glutStrokeCharacter(GLUT_STROKE_MONO_ROMAN, int(string[i]));
|
||||
#ifdef WORKAROUND_BROKEN_GLUT_STROKES
|
||||
} else {
|
||||
// some glut implementations have a broken 'm'...
|
||||
unsigned char tmpStr[2];
|
||||
tmpStr[0] = string[i];
|
||||
tmpStr[1] = '\0';
|
||||
float scale = MONO_STROKE_WIDTH_GLUT / glutStrokeLength(GLUT_STROKE_ROMAN, tmpStr);
|
||||
glScalef(scale, 1.0f, 1.0f);
|
||||
glutStrokeCharacter(GLUT_STROKE_ROMAN, int(string[i]));
|
||||
// staying humble on the stack - might be in projection mode
|
||||
glScalef(1.0f / scale, 1.0f, 1.0f);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
glRotated(rotate,0,0,1);
|
||||
// glLineWidth(thick);
|
||||
glScalef(scale / 0.10, scale / 0.10, 1.0);
|
||||
|
||||
textRenderer(mono)->draw(0, 0, string);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
}
|
||||
|
|
|
@ -19,6 +19,13 @@
|
|||
|
||||
#include <Orientation.h>
|
||||
|
||||
// the standard sans serif font family
|
||||
#define SANS_FONT_FAMILY "Helvetica"
|
||||
|
||||
// the standard mono font family
|
||||
#define MONO_FONT_FAMILY "Courier"
|
||||
|
||||
|
||||
void eulerToOrthonormals(glm::vec3 * angles, glm::vec3 * fwd, glm::vec3 * left, glm::vec3 * up);
|
||||
|
||||
float azimuth_to(glm::vec3 head_pos, glm::vec3 source_pos);
|
||||
|
@ -28,6 +35,7 @@ float randFloat();
|
|||
void render_world_box();
|
||||
void render_vector(glm::vec3 * vec);
|
||||
int widthText(float scale, int mono, char const* string);
|
||||
float widthChar(float scale, int mono, char ch);
|
||||
void drawtext(int x, int y, float scale, float rotate, float thick, int mono,
|
||||
char const* string, float r=1.0, float g=1.0, float b=1.0);
|
||||
void drawvec3(int x, int y, float scale, float rotate, float thick, int mono, glm::vec3 vec,
|
||||
|
|
|
@ -41,69 +41,53 @@ GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z- .
|
|||
4,5,6, 4,6,7 }; // Z+ .
|
||||
|
||||
VoxelSystem::VoxelSystem() {
|
||||
voxelsRendered = 0;
|
||||
tree = new VoxelTree();
|
||||
pthread_mutex_init(&bufferWriteLock, NULL);
|
||||
_voxelsInArrays = _voxelsUpdated = 0;
|
||||
_tree = new VoxelTree();
|
||||
pthread_mutex_init(&_bufferWriteLock, NULL);
|
||||
}
|
||||
|
||||
VoxelSystem::~VoxelSystem() {
|
||||
delete[] readVerticesArray;
|
||||
delete[] writeVerticesArray;
|
||||
delete[] readColorsArray;
|
||||
delete[] writeColorsArray;
|
||||
delete tree;
|
||||
pthread_mutex_destroy(&bufferWriteLock);
|
||||
delete[] _readVerticesArray;
|
||||
delete[] _writeVerticesArray;
|
||||
delete[] _readColorsArray;
|
||||
delete[] _writeColorsArray;
|
||||
delete[] _voxelDirtyArray;
|
||||
delete _tree;
|
||||
pthread_mutex_destroy(&_bufferWriteLock);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Method: VoxelSystem::loadVoxelsFile()
|
||||
// Description: Loads HiFidelity encoded Voxels from a binary file. The current file
|
||||
// format is a stream of single voxels with NO color data. Currently
|
||||
// colors are set randomly
|
||||
// Complaints: Brad :)
|
||||
// To Do: Need to add color data to the file.
|
||||
void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) {
|
||||
|
||||
tree->loadVoxelsFile(fileName,wantColorRandomizer);
|
||||
|
||||
_tree->loadVoxelsFile(fileName, wantColorRandomizer);
|
||||
copyWrittenDataToReadArrays();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Method: VoxelSystem::createSphere()
|
||||
// Description: Creates a sphere of voxels in the local system at a given location/radius
|
||||
// To Do: Move this function someplace better? I put it here because we need a
|
||||
// mechanism to tell the system to redraw it's arrays after voxels are done
|
||||
// being added. This is a concept mostly only understood by VoxelSystem.
|
||||
// Complaints: Brad :)
|
||||
void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer) {
|
||||
|
||||
tree->createSphere(r,xc,yc,zc,s,solid,wantColorRandomizer);
|
||||
_tree->createSphere(r, xc, yc, zc, s, solid, wantColorRandomizer);
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
long int VoxelSystem::getVoxelsCreated() {
|
||||
return tree->voxelsCreated;
|
||||
return _tree->voxelsCreated;
|
||||
}
|
||||
|
||||
float VoxelSystem::getVoxelsCreatedPerSecondAverage() {
|
||||
return (1 / tree->voxelsCreatedStats.getEventDeltaAverage());
|
||||
return (1 / _tree->voxelsCreatedStats.getEventDeltaAverage());
|
||||
}
|
||||
|
||||
long int VoxelSystem::getVoxelsColored() {
|
||||
return tree->voxelsColored;
|
||||
return _tree->voxelsColored;
|
||||
}
|
||||
|
||||
float VoxelSystem::getVoxelsColoredPerSecondAverage() {
|
||||
return (1 / tree->voxelsColoredStats.getEventDeltaAverage());
|
||||
return (1 / _tree->voxelsColoredStats.getEventDeltaAverage());
|
||||
}
|
||||
|
||||
long int VoxelSystem::getVoxelsBytesRead() {
|
||||
return tree->voxelsBytesRead;
|
||||
return _tree->voxelsBytesRead;
|
||||
}
|
||||
|
||||
float VoxelSystem::getVoxelsBytesReadPerSecondAverage() {
|
||||
return tree->voxelsBytesReadStats.getAverageSampleValuePerSecond();
|
||||
return _tree->voxelsBytesReadStats.getAverageSampleValuePerSecond();
|
||||
}
|
||||
|
||||
int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||
|
@ -114,11 +98,11 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
switch(command) {
|
||||
case PACKET_HEADER_VOXEL_DATA:
|
||||
// ask the VoxelTree to read the bitstream into the tree
|
||||
tree->readBitstreamToTree(voxelData, numBytes - 1);
|
||||
_tree->readBitstreamToTree(voxelData, numBytes - 1);
|
||||
break;
|
||||
case PACKET_HEADER_ERASE_VOXEL:
|
||||
// ask the tree to read the "remove" bitstream
|
||||
tree->processRemoveVoxelBitstream(sourceBuffer, numBytes);
|
||||
_tree->processRemoveVoxelBitstream(sourceBuffer, numBytes);
|
||||
break;
|
||||
case PACKET_HEADER_Z_COMMAND:
|
||||
|
||||
|
@ -135,7 +119,8 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
while (totalLength <= numBytes) {
|
||||
if (0==strcmp(command,(char*)"erase all")) {
|
||||
printLog("got Z message == erase all\n");
|
||||
tree->eraseAllVoxels();
|
||||
_tree->eraseAllVoxels();
|
||||
_voxelsInArrays = 0; // better way to do this??
|
||||
}
|
||||
if (0==strcmp(command,(char*)"add scene")) {
|
||||
printLog("got Z message == add scene - NOT SUPPORTED ON INTERFACE\n");
|
||||
|
@ -150,78 +135,87 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
}
|
||||
|
||||
void VoxelSystem::setupNewVoxelsForDrawing() {
|
||||
// reset the verticesEndPointer so we're writing to the beginning of the array
|
||||
writeVerticesEndPointer = writeVerticesArray;
|
||||
// call recursive function to populate in memory arrays
|
||||
// it will return the number of voxels added
|
||||
glm::vec3 treeRoot = glm::vec3(0,0,0);
|
||||
voxelsRendered = treeToArrays(tree->rootNode, treeRoot);
|
||||
_voxelsUpdated = newTreeToArrays(_tree->rootNode);
|
||||
if (_voxelsUpdated) {
|
||||
_voxelsDirty=true;
|
||||
}
|
||||
|
||||
// copy the newly written data to the arrays designated for reading
|
||||
copyWrittenDataToReadArrays();
|
||||
}
|
||||
|
||||
void VoxelSystem::copyWrittenDataToReadArrays() {
|
||||
// lock on the buffer write lock so we can't modify the data when the GPU is reading it
|
||||
pthread_mutex_lock(&bufferWriteLock);
|
||||
// store a pointer to the current end so it doesn't change during copy
|
||||
GLfloat *endOfCurrentVerticesData = writeVerticesEndPointer;
|
||||
// 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);
|
||||
if (_voxelsDirty) {
|
||||
// lock on the buffer write lock so we can't modify the data when the GPU is reading it
|
||||
pthread_mutex_lock(&_bufferWriteLock);
|
||||
int bytesOfVertices = (_voxelsInArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLfloat);
|
||||
int bytesOfColors = (_voxelsInArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLubyte);
|
||||
memcpy(_readVerticesArray, _writeVerticesArray, bytesOfVertices);
|
||||
memcpy(_readColorsArray, _writeColorsArray, bytesOfColors );
|
||||
pthread_mutex_unlock(&_bufferWriteLock);
|
||||
}
|
||||
}
|
||||
|
||||
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 = _camera->getPosition(); //_viewerAvatar->getPosition();
|
||||
int VoxelSystem::newTreeToArrays(VoxelNode* node) {
|
||||
assert(_viewFrustum); // you must set up _viewFrustum before calling this
|
||||
int voxelsUpdated = 0;
|
||||
float distanceToNode = node->distanceToCamera(*_viewFrustum);
|
||||
float boundary = boundaryDistanceForRenderLevel(*node->octalCode + 1);
|
||||
float childBoundary = boundaryDistanceForRenderLevel(*node->octalCode + 2);
|
||||
bool inBoundary = (distanceToNode <= boundary);
|
||||
bool inChildBoundary = (distanceToNode <= childBoundary);
|
||||
bool shouldRender = node->isColored() && ((node->isLeaf() && inChildBoundary) || (inBoundary && !inChildBoundary));
|
||||
|
||||
// debug LOD code
|
||||
glm::vec3 debugNodePosition;
|
||||
copyFirstVertexForCode(currentNode->octalCode,(float*)&debugNodePosition);
|
||||
|
||||
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);
|
||||
bool alwaysDraw = false; // XXXBHG - temporary debug code. Flip this to true to disable LOD blurring
|
||||
|
||||
if (alwaysDraw || distanceToVoxelCenter < boundaryPosition) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// check if there is a child here
|
||||
if (currentNode->children[i] != NULL) {
|
||||
|
||||
glm::vec3 childNodePosition;
|
||||
copyFirstVertexForCode(currentNode->children[i]->octalCode,(float*)&childNodePosition);
|
||||
childNodePosition *= (float)TREE_SCALE; // scale it up
|
||||
voxelsAdded += treeToArrays(currentNode->children[i], childNodePosition);
|
||||
}
|
||||
node->setShouldRender(shouldRender);
|
||||
// let children figure out their renderness
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (node->children[i]) {
|
||||
voxelsUpdated += newTreeToArrays(node->children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Now, if we've changed any attributes (our renderness, our color, etc) then update the Arrays... for us
|
||||
if (node->isDirty() && (shouldRender || node->isKnownBufferIndex())) {
|
||||
glm::vec3 startVertex;
|
||||
float voxelScale = 0;
|
||||
|
||||
// If we're should render, use our legit location and scale,
|
||||
if (node->getShouldRender()) {
|
||||
copyFirstVertexForCode(node->octalCode, (float*)&startVertex);
|
||||
voxelScale = (1 / powf(2, *node->octalCode));
|
||||
} else {
|
||||
// if we shouldn't render then set out location to some infinitely distant location,
|
||||
// and our scale as infinitely small
|
||||
startVertex[0] = startVertex[1] = startVertex[2] = FLT_MAX;
|
||||
voxelScale = 0;
|
||||
}
|
||||
|
||||
// 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->isColored()) {
|
||||
float startVertex[3];
|
||||
copyFirstVertexForCode(currentNode->octalCode,(float*)&startVertex);
|
||||
float voxelScale = 1 / powf(2, *currentNode->octalCode);
|
||||
// If this node has not yet been written to the array, then add it to the end of the array.
|
||||
glBufferIndex nodeIndex;
|
||||
if (node->isKnownBufferIndex()) {
|
||||
nodeIndex = node->getBufferIndex();
|
||||
} else {
|
||||
nodeIndex = _voxelsInArrays;
|
||||
}
|
||||
|
||||
_voxelDirtyArray[nodeIndex] = true;
|
||||
|
||||
// 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->getColor()[j % 3];
|
||||
|
||||
writeVerticesEndPointer++;
|
||||
GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL);
|
||||
GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL);
|
||||
*(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale);
|
||||
*(writeColorsAt +j) = node->getColor()[j % 3];
|
||||
}
|
||||
voxelsAdded++;
|
||||
if (!node->isKnownBufferIndex()) {
|
||||
node->setBufferIndex(nodeIndex);
|
||||
_voxelsInArrays++; // our know vertices in the arrays
|
||||
}
|
||||
voxelsUpdated++;
|
||||
node->clearDirtyBit();
|
||||
}
|
||||
|
||||
return voxelsAdded;
|
||||
return voxelsUpdated;
|
||||
}
|
||||
|
||||
VoxelSystem* VoxelSystem::clone() const {
|
||||
|
@ -230,20 +224,30 @@ VoxelSystem* VoxelSystem::clone() const {
|
|||
}
|
||||
|
||||
void VoxelSystem::init() {
|
||||
// prep the data structures for incoming voxel data
|
||||
writeVerticesEndPointer = writeVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
readVerticesEndPointer = readVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
writeColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
readColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
|
||||
GLuint *indicesArray = new GLuint[INDICES_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
// When we change voxels representations in the arrays, we'll update this
|
||||
_voxelsDirty = false;
|
||||
_voxelsInArrays = 0;
|
||||
|
||||
// we will track individual dirty sections with this array of bools
|
||||
_voxelDirtyArray = new bool[MAX_VOXELS_PER_SYSTEM];
|
||||
memset(_voxelDirtyArray, false, MAX_VOXELS_PER_SYSTEM * sizeof(bool));
|
||||
|
||||
// prep the data structures for incoming voxel data
|
||||
_writeVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
_readVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
|
||||
_writeColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
_readColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
|
||||
GLuint* indicesArray = new GLuint[INDICES_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
|
||||
// populate the indicesArray
|
||||
// this will not change given new voxels, so we can set it all up now
|
||||
for (int n = 0; n < MAX_VOXELS_PER_SYSTEM; n++) {
|
||||
// fill the indices array
|
||||
int voxelIndexOffset = n * INDICES_PER_VOXEL;
|
||||
GLuint *currentIndicesPos = indicesArray + voxelIndexOffset;
|
||||
GLuint* currentIndicesPos = indicesArray + voxelIndexOffset;
|
||||
int startIndex = (n * VERTICES_PER_VOXEL);
|
||||
|
||||
for (int i = 0; i < INDICES_PER_VOXEL; i++) {
|
||||
|
@ -252,8 +256,8 @@ void VoxelSystem::init() {
|
|||
}
|
||||
}
|
||||
|
||||
GLfloat *normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
GLfloat *normalsArrayEndPointer = normalsArray;
|
||||
GLfloat* normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
GLfloat* normalsArrayEndPointer = normalsArray;
|
||||
|
||||
// populate the normalsArray
|
||||
for (int n = 0; n < MAX_VOXELS_PER_SYSTEM; n++) {
|
||||
|
@ -263,25 +267,25 @@ void VoxelSystem::init() {
|
|||
}
|
||||
|
||||
// VBO for the verticesArray
|
||||
glGenBuffers(1, &vboVerticesID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboVerticesID);
|
||||
glGenBuffers(1, &_vboVerticesID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||
glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW);
|
||||
|
||||
// VBO for the normalsArray
|
||||
glGenBuffers(1, &vboNormalsID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboNormalsID);
|
||||
glGenBuffers(1, &_vboNormalsID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID);
|
||||
glBufferData(GL_ARRAY_BUFFER,
|
||||
VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM,
|
||||
normalsArray, GL_STATIC_DRAW);
|
||||
|
||||
// VBO for colorsArray
|
||||
glGenBuffers(1, &vboColorsID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboColorsID);
|
||||
glGenBuffers(1, &_vboColorsID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||
glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW);
|
||||
|
||||
// VBO for the indicesArray
|
||||
glGenBuffers(1, &vboIndicesID);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndicesID);
|
||||
glGenBuffers(1, &_vboIndicesID);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
INDICES_PER_VOXEL * sizeof(GLuint) * MAX_VOXELS_PER_SYSTEM,
|
||||
indicesArray, GL_STATIC_DRAW);
|
||||
|
@ -291,45 +295,61 @@ void VoxelSystem::init() {
|
|||
delete[] normalsArray;
|
||||
}
|
||||
|
||||
void VoxelSystem::render() {
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
if (readVerticesEndPointer != readVerticesArray) {
|
||||
// try to lock on the buffer write
|
||||
// just avoid pulling new data if it is currently being written
|
||||
if (pthread_mutex_trylock(&bufferWriteLock) == 0) {
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboVerticesID);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, (readVerticesEndPointer - readVerticesArray) * sizeof(GLfloat), readVerticesArray);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboColorsID);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, (readVerticesEndPointer - readVerticesArray) * sizeof(GLubyte), readColorsArray);
|
||||
|
||||
readVerticesEndPointer = readVerticesArray;
|
||||
|
||||
pthread_mutex_unlock(&bufferWriteLock);
|
||||
void VoxelSystem::updateVBOs() {
|
||||
if (_voxelsDirty) {
|
||||
glBufferIndex segmentStart = 0;
|
||||
glBufferIndex segmentEnd = 0;
|
||||
bool inSegment = false;
|
||||
for (glBufferIndex i = 0; i < _voxelsInArrays; i++) {
|
||||
if (!inSegment) {
|
||||
if (_voxelDirtyArray[i]) {
|
||||
segmentStart = i;
|
||||
inSegment = true;
|
||||
_voxelDirtyArray[i] = false; // consider us clean!
|
||||
}
|
||||
} else {
|
||||
if (!_voxelDirtyArray[i] || (i == (_voxelsInArrays - 1)) ) {
|
||||
segmentEnd = i;
|
||||
inSegment = false;
|
||||
int segmentLength = (segmentEnd - segmentStart) + 1;
|
||||
GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
|
||||
GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
|
||||
GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);
|
||||
segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
|
||||
segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
|
||||
GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom);
|
||||
}
|
||||
}
|
||||
}
|
||||
_voxelsDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelSystem::render() {
|
||||
glPushMatrix();
|
||||
updateVBOs();
|
||||
// tell OpenGL where to find vertex and color information
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboVerticesID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||
glVertexPointer(3, GL_FLOAT, 0, 0);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboNormalsID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID);
|
||||
glNormalPointer(GL_FLOAT, 0, 0);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboColorsID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||
glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
|
||||
|
||||
// draw the number of voxels we have
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndicesID);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID);
|
||||
glScalef(10, 10, 10);
|
||||
glDrawElements(GL_TRIANGLES, 36 * voxelsRendered, GL_UNSIGNED_INT, 0);
|
||||
glDrawElements(GL_TRIANGLES, 36 * _voxelsInArrays, GL_UNSIGNED_INT, 0);
|
||||
|
||||
// deactivate vertex and color arrays after drawing
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
@ -344,25 +364,12 @@ void VoxelSystem::render() {
|
|||
glPopMatrix();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool VoxelSystem::randomColorOperation(VoxelNode* node, void* extraData) {
|
||||
_nodeCount++;
|
||||
if (node->isColored()) {
|
||||
nodeColor newColor = { 0,0,0,1 };
|
||||
newColor[0] = randomColorValue(150);
|
||||
newColor[1] = randomColorValue(150);
|
||||
newColor[1] = randomColorValue(150);
|
||||
nodeColor newColor = { randomColorValue(150), randomColorValue(150), randomColorValue(150), 1 };
|
||||
node->setColor(newColor);
|
||||
}
|
||||
return true;
|
||||
|
@ -370,43 +377,26 @@ bool VoxelSystem::randomColorOperation(VoxelNode* node, bool down, void* extraDa
|
|||
|
||||
void VoxelSystem::randomizeVoxelColors() {
|
||||
_nodeCount = 0;
|
||||
tree->recurseTreeWithOperation(randomColorOperation);
|
||||
printLog("setting randomized true color for %d nodes\n",_nodeCount);
|
||||
_tree->recurseTreeWithOperation(randomColorOperation);
|
||||
printLog("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;
|
||||
}
|
||||
|
||||
bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, void* extraData) {
|
||||
_nodeCount++;
|
||||
|
||||
// always false colorize
|
||||
unsigned char newR = randomColorValue(150);
|
||||
unsigned char newG = randomColorValue(150);
|
||||
unsigned char newB = randomColorValue(150);
|
||||
node->setFalseColor(newR,newG,newB);
|
||||
|
||||
node->setFalseColor(randomColorValue(150), randomColorValue(150), randomColorValue(150));
|
||||
return true; // keep going!
|
||||
}
|
||||
|
||||
void VoxelSystem::falseColorizeRandom() {
|
||||
_nodeCount = 0;
|
||||
tree->recurseTreeWithOperation(falseColorizeRandomOperation);
|
||||
printLog("setting randomized false color for %d nodes\n",_nodeCount);
|
||||
_tree->recurseTreeWithOperation(falseColorizeRandomOperation);
|
||||
printLog("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;
|
||||
}
|
||||
|
||||
bool VoxelSystem::trueColorizeOperation(VoxelNode* node, void* extraData) {
|
||||
_nodeCount++;
|
||||
node->setFalseColored(false);
|
||||
return true;
|
||||
|
@ -414,90 +404,45 @@ bool VoxelSystem::trueColorizeOperation(VoxelNode* node, bool down, void* extraD
|
|||
|
||||
void VoxelSystem::trueColorize() {
|
||||
_nodeCount = 0;
|
||||
tree->recurseTreeWithOperation(trueColorizeOperation);
|
||||
printLog("setting true color for %d nodes\n",_nodeCount);
|
||||
_tree->recurseTreeWithOperation(trueColorizeOperation);
|
||||
printLog("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;
|
||||
}
|
||||
|
||||
bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, void* extraData) {
|
||||
const ViewFrustum* viewFrustum = (const ViewFrustum*) extraData;
|
||||
|
||||
_nodeCount++;
|
||||
|
||||
// only do this for truely colored voxels...
|
||||
if (node->isColored()) {
|
||||
// If the voxel is outside of the view frustum, then false color it red
|
||||
if (!node->isInView(*viewFrustum)) {
|
||||
// Out of view voxels are colored RED
|
||||
unsigned char newR = 255;
|
||||
unsigned char newG = 0;
|
||||
unsigned char newB = 0;
|
||||
node->setFalseColor(newR,newG,newB);
|
||||
node->setFalseColor(255, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return true; // keep going!
|
||||
}
|
||||
|
||||
void VoxelSystem::falseColorizeInView(ViewFrustum* viewFrustum) {
|
||||
_nodeCount = 0;
|
||||
tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)viewFrustum);
|
||||
printLog("setting in view false color for %d nodes\n",_nodeCount);
|
||||
_tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)viewFrustum);
|
||||
printLog("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) {
|
||||
|
||||
// we do our operations on the way up!
|
||||
if (down) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VoxelSystem::falseColorizeDistanceFromViewOperation(VoxelNode* node, void* extraData) {
|
||||
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));
|
||||
|
||||
// actually colorize
|
||||
float distance = node->distanceToCamera(*viewFrustum);
|
||||
_nodeCount++;
|
||||
|
||||
float distanceRatio = (_minDistance==_maxDistance) ? 1 : (distance - _minDistance)/(_maxDistance - _minDistance);
|
||||
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;
|
||||
node->setFalseColor(newR,newG,newB);
|
||||
unsigned char colorBand = (colorBands * distanceRatio);
|
||||
node->setFalseColor((colorBand * (gradientOver / colorBands)) + (maxColor - gradientOver), 0, 0);
|
||||
}
|
||||
return true; // keep going!
|
||||
}
|
||||
|
@ -508,44 +453,18 @@ 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;
|
||||
}
|
||||
|
||||
bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, void* extraData) {
|
||||
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
|
||||
float distance = node->distanceToCamera(*viewFrustum);
|
||||
// calculate the range of distances
|
||||
if (distance > _maxDistance) {
|
||||
_maxDistance = distance;
|
||||
}
|
||||
if (distance < _minDistance) {
|
||||
_minDistance = distance;
|
||||
}
|
||||
|
||||
_nodeCount++;
|
||||
}
|
||||
return true; // keep going!
|
||||
|
@ -553,15 +472,14 @@ bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, bool down,
|
|||
|
||||
void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) {
|
||||
_nodeCount = 0;
|
||||
|
||||
_maxDistance = 0.0;
|
||||
_minDistance = FLT_MAX;
|
||||
tree->recurseTreeWithOperation(getDistanceFromViewRangeOperation,(void*)viewFrustum);
|
||||
printLog("determining distance range for %d nodes\n",_nodeCount);
|
||||
|
||||
_tree->recurseTreeWithOperation(getDistanceFromViewRangeOperation,(void*)viewFrustum);
|
||||
printLog("determining distance range for %d nodes\n", _nodeCount);
|
||||
_nodeCount = 0;
|
||||
|
||||
tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum);
|
||||
printLog("setting in distance false color for %d nodes\n",_nodeCount);
|
||||
_tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum);
|
||||
printLog("setting in distance false color for %d nodes\n", _nodeCount);
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -29,12 +29,16 @@ public:
|
|||
|
||||
int parseData(unsigned char* sourceBuffer, int numBytes);
|
||||
VoxelSystem* clone() const;
|
||||
|
||||
void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; };
|
||||
|
||||
void init();
|
||||
void simulate(float deltaTime);
|
||||
void simulate(float deltaTime) { };
|
||||
void render();
|
||||
void setVoxelsRendered(int v) {voxelsRendered = v;};
|
||||
int getVoxelsRendered() {return voxelsRendered;};
|
||||
|
||||
unsigned long getVoxelsUpdated() const {return _voxelsUpdated;};
|
||||
unsigned long getVoxelsRendered() const {return _voxelsInArrays;};
|
||||
|
||||
void setViewerAvatar(Avatar *newViewerAvatar) { _viewerAvatar = newViewerAvatar; };
|
||||
void setCamera(Camera* newCamera) { _camera = newCamera; };
|
||||
void loadVoxelsFile(const char* fileName,bool wantColorRandomizer);
|
||||
|
@ -57,36 +61,42 @@ public:
|
|||
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);
|
||||
static bool randomColorOperation(VoxelNode* node, void* extraData);
|
||||
static bool falseColorizeRandomOperation(VoxelNode* node, void* extraData);
|
||||
static bool trueColorizeOperation(VoxelNode* node, void* extraData);
|
||||
static bool falseColorizeInViewOperation(VoxelNode* node, void* extraData);
|
||||
static bool falseColorizeDistanceFromViewOperation(VoxelNode* node, void* extraData);
|
||||
static bool getDistanceFromViewRangeOperation(VoxelNode* node, void* extraData);
|
||||
|
||||
// these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here
|
||||
static float _maxDistance;
|
||||
static float _minDistance;
|
||||
|
||||
int voxelsRendered;
|
||||
Avatar* _viewerAvatar;
|
||||
Camera* _camera;
|
||||
VoxelTree *tree;
|
||||
GLfloat *readVerticesArray;
|
||||
GLubyte *readColorsArray;
|
||||
GLfloat *readVerticesEndPointer;
|
||||
GLfloat *writeVerticesArray;
|
||||
GLubyte *writeColorsArray;
|
||||
GLfloat *writeVerticesEndPointer;
|
||||
GLuint vboVerticesID;
|
||||
GLuint vboNormalsID;
|
||||
GLuint vboColorsID;
|
||||
GLuint vboIndicesID;
|
||||
pthread_mutex_t bufferWriteLock;
|
||||
VoxelTree* _tree;
|
||||
GLfloat* _readVerticesArray;
|
||||
GLubyte* _readColorsArray;
|
||||
GLfloat* _writeVerticesArray;
|
||||
GLubyte* _writeColorsArray;
|
||||
bool* _voxelDirtyArray;
|
||||
unsigned long _voxelsUpdated;
|
||||
unsigned long _voxelsInArrays;
|
||||
|
||||
GLuint _vboVerticesID;
|
||||
GLuint _vboNormalsID;
|
||||
GLuint _vboColorsID;
|
||||
GLuint _vboIndicesID;
|
||||
pthread_mutex_t _bufferWriteLock;
|
||||
|
||||
int treeToArrays(VoxelNode *currentNode, const glm::vec3& nodePosition);
|
||||
ViewFrustum* _viewFrustum;
|
||||
|
||||
int newTreeToArrays(VoxelNode *currentNode);
|
||||
void setupNewVoxelsForDrawing();
|
||||
void copyWrittenDataToReadArrays();
|
||||
void updateVBOs();
|
||||
|
||||
bool _voxelsDirty;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
@ -59,11 +61,13 @@
|
|||
#include "AngleUtil.h"
|
||||
#include "Stars.h"
|
||||
|
||||
#include "MenuRow.h"
|
||||
#include "MenuColumn.h"
|
||||
#include "Menu.h"
|
||||
#include "ui/ChatEntry.h"
|
||||
#include "ui/MenuRow.h"
|
||||
#include "ui/MenuColumn.h"
|
||||
#include "ui/Menu.h"
|
||||
#include "ui/TextRenderer.h"
|
||||
|
||||
#include "Camera.h"
|
||||
#include "ChatEntry.h"
|
||||
#include "Avatar.h"
|
||||
#include "Texture.h"
|
||||
#include <AgentList.h>
|
||||
|
@ -86,6 +90,8 @@ using namespace std;
|
|||
void reshape(int width, int height); // will be defined below
|
||||
void loadViewFrustum(ViewFrustum& viewFrustum); // will be defined below
|
||||
|
||||
QApplication* app;
|
||||
|
||||
bool enableNetworkThread = true;
|
||||
pthread_t networkReceiveThread;
|
||||
bool stopNetworkReceiveThread = false;
|
||||
|
@ -107,11 +113,11 @@ bool wantColorRandomizer = true; // for addSphere and load file
|
|||
|
||||
Oscilloscope audioScope(256,200,true);
|
||||
|
||||
ViewFrustum viewFrustum; // current state of view frustum, perspective, orientation, etc.
|
||||
ViewFrustum viewFrustum; // current state of view frustum, perspective, orientation, etc.
|
||||
|
||||
Avatar myAvatar(true); // The rendered avatar of oneself
|
||||
Camera myCamera; // My view onto the world (sometimes on myself :)
|
||||
Camera viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode
|
||||
Avatar myAvatar(true); // The rendered avatar of oneself
|
||||
Camera myCamera; // My view onto the world (sometimes on myself :)
|
||||
Camera viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode
|
||||
|
||||
// Starfield information
|
||||
char starFile[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt";
|
||||
|
@ -230,7 +236,7 @@ void displayStats(void)
|
|||
drawtext(10, statsVerticalOffset + 49, 0.10f, 0, 1.0, 0, stats);
|
||||
|
||||
std::stringstream voxelStats;
|
||||
voxelStats << "Voxels Rendered: " << voxels.getVoxelsRendered();
|
||||
voxelStats << "Voxels Rendered: " << voxels.getVoxelsRendered() << " Updated: " << voxels.getVoxelsUpdated();
|
||||
drawtext(10, statsVerticalOffset + 70, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||
|
||||
voxelStats.str("");
|
||||
|
@ -496,31 +502,19 @@ void loadViewFrustum(ViewFrustum& viewFrustum) {
|
|||
glm::vec3 up;
|
||||
glm::vec3 right;
|
||||
float fov, nearClip, farClip;
|
||||
float yaw, pitch, roll;
|
||||
|
||||
// Camera or Head?
|
||||
if (::cameraFrustum) {
|
||||
position = ::myCamera.getPosition();
|
||||
position = ::myCamera.getPosition();
|
||||
} else {
|
||||
position = ::myAvatar.getHeadPosition();
|
||||
position = ::myAvatar.getHeadPosition();
|
||||
}
|
||||
|
||||
// This bit of hackery is all because our Cameras report the incorrect yaw.
|
||||
// For whatever reason, the camera has a yaw set to 180.0-trueYaw, so we basically
|
||||
// need to get the "yaw" from the camera and adjust it to be the trueYaw
|
||||
yaw = -(::myCamera.getOrientation().getYaw()-180);
|
||||
pitch = ::myCamera.getOrientation().getPitch();
|
||||
roll = ::myCamera.getOrientation().getRoll();
|
||||
fov = ::myCamera.getFieldOfView();
|
||||
nearClip = ::myCamera.getNearClip();
|
||||
farClip = ::myCamera.getFarClip();
|
||||
|
||||
// We can't use the camera's Orientation because of it's broken yaw. so we make a new
|
||||
// correct orientation to get our vectors
|
||||
Orientation o;
|
||||
o.yaw(yaw);
|
||||
o.pitch(pitch);
|
||||
o.roll(roll);
|
||||
|
||||
Orientation o = ::myCamera.getOrientation();
|
||||
|
||||
direction = o.getFront();
|
||||
up = o.getUp();
|
||||
|
@ -710,16 +704,16 @@ void display(void)
|
|||
glMaterialfv(GL_FRONT, GL_SPECULAR, specular_color);
|
||||
glMateriali(GL_FRONT, GL_SHININESS, 96);
|
||||
|
||||
// camera settings
|
||||
if ( ::lookingInMirror ) {
|
||||
// set the camera to looking at my own face
|
||||
myCamera.setTargetPosition ( myAvatar.getHeadPosition() );
|
||||
myCamera.setTargetYaw ( - myAvatar.getBodyYaw() );
|
||||
myCamera.setPitch ( 0.0 );
|
||||
myCamera.setRoll ( 0.0 );
|
||||
myCamera.setUpShift ( 0.0 );
|
||||
myCamera.setDistance ( 0.2 );
|
||||
myCamera.setTightness ( 100.0f );
|
||||
// camera settings
|
||||
if ( ::lookingInMirror ) {
|
||||
// set the camera to looking at my own face
|
||||
myCamera.setTargetPosition ( myAvatar.getHeadPosition() );
|
||||
myCamera.setTargetYaw ( myAvatar.getBodyYaw() - 180.0f ); // 180 degrees from body yaw
|
||||
myCamera.setPitch ( 0.0 );
|
||||
myCamera.setRoll ( 0.0 );
|
||||
myCamera.setUpShift ( 0.0 );
|
||||
myCamera.setDistance ( 0.2 );
|
||||
myCamera.setTightness ( 100.0f );
|
||||
} else {
|
||||
|
||||
//float firstPersonPitch = 20.0f;
|
||||
|
@ -794,17 +788,17 @@ void display(void)
|
|||
*/
|
||||
|
||||
} else {
|
||||
myCamera.setPitch (thirdPersonPitch );
|
||||
myCamera.setPitch (thirdPersonPitch );
|
||||
myCamera.setUpShift (thirdPersonUpShift );
|
||||
myCamera.setDistance (thirdPersonDistance );
|
||||
myCamera.setTightness(thirdPersonTightness);
|
||||
}
|
||||
|
||||
myCamera.setTargetPosition( myAvatar.getHeadPosition() );
|
||||
myCamera.setTargetYaw ( 180.0 - myAvatar.getBodyYaw() );
|
||||
myCamera.setRoll ( 0.0 );
|
||||
myCamera.setTargetPosition( myAvatar.getHeadPosition() );
|
||||
myCamera.setTargetYaw ( myAvatar.getBodyYaw() );
|
||||
myCamera.setRoll ( 0.0 );
|
||||
}
|
||||
|
||||
|
||||
// important...
|
||||
myCamera.update( 1.f/FPS );
|
||||
|
||||
|
@ -821,23 +815,25 @@ void display(void)
|
|||
|
||||
if (::viewFrustumFromOffset && ::frustumOn) {
|
||||
|
||||
// set the camera to third-person view but offset so we can see the frustum
|
||||
viewFrustumOffsetCamera.setTargetYaw( 180.0 - myAvatar.getBodyYaw() + ::viewFrustumOffsetYaw );
|
||||
viewFrustumOffsetCamera.setPitch ( ::viewFrustumOffsetPitch );
|
||||
viewFrustumOffsetCamera.setRoll ( ::viewFrustumOffsetRoll );
|
||||
viewFrustumOffsetCamera.setUpShift ( ::viewFrustumOffsetUp );
|
||||
viewFrustumOffsetCamera.setDistance ( ::viewFrustumOffsetDistance );
|
||||
viewFrustumOffsetCamera.update(1.f/FPS);
|
||||
whichCamera = viewFrustumOffsetCamera;
|
||||
}
|
||||
// set the camera to third-person view but offset so we can see the frustum
|
||||
viewFrustumOffsetCamera.setTargetYaw( ::viewFrustumOffsetYaw + myAvatar.getBodyYaw() );
|
||||
viewFrustumOffsetCamera.setPitch ( ::viewFrustumOffsetPitch );
|
||||
viewFrustumOffsetCamera.setRoll ( ::viewFrustumOffsetRoll );
|
||||
viewFrustumOffsetCamera.setUpShift ( ::viewFrustumOffsetUp );
|
||||
viewFrustumOffsetCamera.setDistance ( ::viewFrustumOffsetDistance );
|
||||
viewFrustumOffsetCamera.update(1.f/FPS);
|
||||
whichCamera = viewFrustumOffsetCamera;
|
||||
}
|
||||
|
||||
// transform view according to whichCamera
|
||||
// could be myCamera (if in normal mode)
|
||||
// or could be viewFrustumOffsetCamera if in offset mode
|
||||
// I changed the ordering here - roll is FIRST (JJV)
|
||||
glRotatef ( whichCamera.getRoll(), 0, 0, 1 );
|
||||
glRotatef ( whichCamera.getPitch(), 1, 0, 0 );
|
||||
glRotatef ( whichCamera.getYaw(), 0, 1, 0 );
|
||||
|
||||
glRotatef ( whichCamera.getRoll(), IDENTITY_FRONT.x, IDENTITY_FRONT.y, IDENTITY_FRONT.z );
|
||||
glRotatef ( whichCamera.getPitch(), IDENTITY_RIGHT.x, IDENTITY_RIGHT.y, IDENTITY_RIGHT.z );
|
||||
glRotatef ( 180.0 - whichCamera.getYaw(), IDENTITY_UP.x, IDENTITY_UP.y, IDENTITY_UP.z );
|
||||
|
||||
glTranslatef( -whichCamera.getPosition().x, -whichCamera.getPosition().y, -whichCamera.getPosition().z );
|
||||
|
||||
if (::starsOn) {
|
||||
|
@ -853,18 +849,18 @@ void display(void)
|
|||
// draw a red sphere
|
||||
float sphereRadius = 0.25f;
|
||||
glColor3f(1,0,0);
|
||||
glPushMatrix();
|
||||
glutSolidSphere( sphereRadius, 15, 15 );
|
||||
glPopMatrix();
|
||||
glPushMatrix();
|
||||
glutSolidSphere( sphereRadius, 15, 15 );
|
||||
glPopMatrix();
|
||||
|
||||
//draw a grid ground plane....
|
||||
drawGroundPlaneGrid( 5.0f, 9 );
|
||||
//draw a grid ground plane....
|
||||
drawGroundPlaneGrid( 5.0f, 9 );
|
||||
|
||||
// Draw voxels
|
||||
if ( showingVoxels )
|
||||
{
|
||||
voxels.render();
|
||||
}
|
||||
if ( showingVoxels )
|
||||
{
|
||||
voxels.render();
|
||||
}
|
||||
|
||||
// Render avatars of other agents
|
||||
AgentList* agentList = AgentList::getInstance();
|
||||
|
@ -1329,7 +1325,7 @@ void key(unsigned char k, int x, int y)
|
|||
if (chatEntry.key(k)) {
|
||||
myAvatar.setKeyState(k == '\b' || k == 127 ? // backspace or delete
|
||||
DELETE_KEY_DOWN : INSERT_KEY_DOWN);
|
||||
myAvatar.setChatMessage(string(chatEntry.getContents().size(), 'X'));
|
||||
myAvatar.setChatMessage(string(chatEntry.getContents().size(), SOLID_BLOCK_CHAR));
|
||||
|
||||
} else {
|
||||
myAvatar.setChatMessage(chatEntry.getContents());
|
||||
|
@ -1422,6 +1418,7 @@ void* networkReceive(void* args)
|
|||
|
||||
switch (incomingPacket[0]) {
|
||||
case PACKET_HEADER_TRANSMITTER_DATA:
|
||||
// Process UDP packets that are sent to the client from local sensor devices
|
||||
myAvatar.processTransmitterData(incomingPacket, bytesReceived);
|
||||
break;
|
||||
case PACKET_HEADER_VOXEL_DATA:
|
||||
|
@ -1616,6 +1613,8 @@ void audioMixerUpdate(in_addr_t newMixerAddress, in_port_t newMixerPort) {
|
|||
|
||||
int main(int argc, const char * argv[])
|
||||
{
|
||||
voxels.setViewFrustum(&::viewFrustum);
|
||||
|
||||
shared_lib::printLog = & ::printLog;
|
||||
voxels_lib::printLog = & ::printLog;
|
||||
avatars_lib::printLog = & ::printLog;
|
||||
|
@ -1672,7 +1671,10 @@ int main(int argc, const char * argv[])
|
|||
#ifdef _WIN32
|
||||
glewInit();
|
||||
#endif
|
||||
|
||||
|
||||
// we need to create a QApplication instance in order to use Qt's font rendering
|
||||
app = new QApplication(argc, const_cast<char**>(argv));
|
||||
|
||||
// Before we render anything, let's set up our viewFrustumOffsetCamera with a sufficiently large
|
||||
// field of view and near and far clip to make it interesting.
|
||||
//viewFrustumOffsetCamera.setFieldOfView(90.0);
|
||||
|
|
|
@ -14,7 +14,7 @@ using namespace std;
|
|||
|
||||
const int MAX_CONTENT_LENGTH = 140;
|
||||
|
||||
void ChatEntry::clear () {
|
||||
void ChatEntry::clear() {
|
||||
_contents.clear();
|
||||
_cursorPos = 0;
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ void ChatEntry::render(int screenWidth, int screenHeight) {
|
|||
|
||||
float width = 0;
|
||||
for (string::iterator it = _contents.begin(), end = it + _cursorPos; it != end; it++) {
|
||||
width += glutStrokeWidth(GLUT_STROKE_ROMAN, *it)*0.10;
|
||||
width += widthChar(0.10, 0, *it);
|
||||
}
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
glBegin(GL_LINE_STRIP);
|
|
@ -14,9 +14,9 @@
|
|||
class ChatEntry {
|
||||
public:
|
||||
|
||||
const std::string& getContents () const { return _contents; }
|
||||
const std::string& getContents() const { return _contents; }
|
||||
|
||||
void clear ();
|
||||
void clear();
|
||||
|
||||
bool key(unsigned char k);
|
||||
void specialKey(unsigned char k);
|
|
@ -16,6 +16,7 @@
|
|||
#include "MenuColumn.h"
|
||||
#include "Menu.h"
|
||||
|
||||
#include "ui/TextRenderer.h"
|
||||
|
||||
MenuColumn::MenuColumn() {
|
||||
}
|
||||
|
@ -137,9 +138,12 @@ int MenuColumn::getMaxRowWidth() {
|
|||
return maxColumnWidth;
|
||||
}
|
||||
|
||||
static TextRenderer* textRenderer() {
|
||||
static TextRenderer* renderer = new TextRenderer(SANS_FONT_FAMILY, 11);
|
||||
return renderer;
|
||||
}
|
||||
|
||||
void MenuColumn::render(int yOffset, int menuHeight, int lineHeight) {
|
||||
float scale = 0.09;
|
||||
int mono = 0;
|
||||
int numberOfRows = rows.size();
|
||||
if (numberOfRows > 0) {
|
||||
|
||||
|
@ -158,7 +162,8 @@ void MenuColumn::render(int yOffset, int menuHeight, int lineHeight) {
|
|||
char* rowName;
|
||||
for (unsigned int i = 0; i < rows.size(); ++i) {
|
||||
rowName = rows[i].getName();
|
||||
drawtext(leftPosition + SPACE_BEFORE_ROW_NAME, y+5 + yOffset, scale, 0, 1.0, mono, rowName, 0, 0, 0);
|
||||
glColor3f(0, 0, 0);
|
||||
textRenderer()->draw(leftPosition + SPACE_BEFORE_ROW_NAME, y + 5 + yOffset, rowName);
|
||||
y += lineHeight;
|
||||
}
|
||||
renderMouseOver(yOffset);
|
142
interface/src/ui/TextRenderer.cpp
Normal file
142
interface/src/ui/TextRenderer.cpp
Normal file
|
@ -0,0 +1,142 @@
|
|||
//
|
||||
// TextRenderer.cpp
|
||||
// interface
|
||||
//
|
||||
// Created by Andrzej Kapolka on 4/24/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
|
||||
#include <QFont>
|
||||
#include <QPaintEngine>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
#include "TextRenderer.h"
|
||||
|
||||
// the width/height of the cached glyph textures
|
||||
const int IMAGE_SIZE = 256;
|
||||
|
||||
Glyph::Glyph(int textureID, const QPoint& location, const QRect& bounds, int width) :
|
||||
_textureID(textureID), _location(location), _bounds(bounds), _width(width) {
|
||||
}
|
||||
|
||||
TextRenderer::TextRenderer(const char* family, int pointSize, int weight, bool italic)
|
||||
: _font(family, pointSize, weight, italic),
|
||||
_metrics(_font), _x(IMAGE_SIZE), _y(IMAGE_SIZE), _rowHeight(0) {
|
||||
_font.setKerning(false);
|
||||
}
|
||||
|
||||
TextRenderer::~TextRenderer() {
|
||||
glDeleteTextures(_allTextureIDs.size(), _allTextureIDs.constData());
|
||||
}
|
||||
|
||||
void TextRenderer::draw(int x, int y, const char* str) {
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
for (const char* ch = str; *ch != 0; ch++) {
|
||||
const Glyph& glyph = getGlyph(*ch);
|
||||
if (glyph.textureID() == 0) {
|
||||
x += glyph.width();
|
||||
continue;
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, glyph.textureID());
|
||||
|
||||
int left = x + glyph.bounds().x();
|
||||
int right = x + glyph.bounds().x() + glyph.bounds().width();
|
||||
int bottom = y + glyph.bounds().y();
|
||||
int top = y + glyph.bounds().y() + glyph.bounds().height();
|
||||
|
||||
float scale = 1.0 / IMAGE_SIZE;
|
||||
float ls = glyph.location().x() * scale;
|
||||
float rs = (glyph.location().x() + glyph.bounds().width()) * scale;
|
||||
float bt = glyph.location().y() * scale;
|
||||
float tt = (glyph.location().y() + glyph.bounds().height()) * scale;
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(ls, bt);
|
||||
glVertex2f(left, bottom);
|
||||
glTexCoord2f(rs, bt);
|
||||
glVertex2f(right, bottom);
|
||||
glTexCoord2f(rs, tt);
|
||||
glVertex2f(right, top);
|
||||
glTexCoord2f(ls, tt);
|
||||
glVertex2f(left, top);
|
||||
glEnd();
|
||||
|
||||
x += glyph.width();
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
int TextRenderer::computeWidth(char ch)
|
||||
{
|
||||
return getGlyph(ch).width();
|
||||
}
|
||||
|
||||
int TextRenderer::computeWidth(const char* str)
|
||||
{
|
||||
int width = 0;
|
||||
for (const char* ch = str; *ch != 0; ch++) {
|
||||
width += computeWidth(*ch);
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
const Glyph& TextRenderer::getGlyph(char c) {
|
||||
Glyph& glyph = _glyphs[c];
|
||||
if (glyph.isValid()) {
|
||||
return glyph;
|
||||
}
|
||||
// we use 'J' as a representative size for the solid block character
|
||||
QChar ch = (c == SOLID_BLOCK_CHAR) ? QChar('J') : QChar(c);
|
||||
QRect bounds = _metrics.boundingRect(ch);
|
||||
if (bounds.isEmpty()) {
|
||||
glyph = Glyph(0, QPoint(), QRect(), _metrics.width(ch));
|
||||
return glyph;
|
||||
}
|
||||
// grow the bounds to account for antialiasing
|
||||
bounds.adjust(-1, -1, 1, 1);
|
||||
|
||||
if (_x + bounds.width() > IMAGE_SIZE) {
|
||||
// we can't fit it on the current row; move to next
|
||||
_y += _rowHeight;
|
||||
_x = _rowHeight = 0;
|
||||
}
|
||||
if (_y + bounds.height() > IMAGE_SIZE) {
|
||||
// can't fit it on current texture; make a new one
|
||||
glGenTextures(1, &_currentTextureID);
|
||||
_x = _y = _rowHeight = 0;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, _currentTextureID);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, IMAGE_SIZE, IMAGE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
_allTextureIDs.append(_currentTextureID);
|
||||
|
||||
} else {
|
||||
glBindTexture(GL_TEXTURE_2D, _currentTextureID);
|
||||
}
|
||||
// render the glyph into an image and copy it into the texture
|
||||
QImage image(bounds.width(), bounds.height(), QImage::Format_ARGB32);
|
||||
if (c == SOLID_BLOCK_CHAR) {
|
||||
image.fill(QColor(255, 255, 255));
|
||||
|
||||
} else {
|
||||
image.fill(0);
|
||||
QPainter painter(&image);
|
||||
painter.setFont(_font);
|
||||
painter.setPen(QColor(255, 255, 255));
|
||||
painter.drawText(-bounds.x(), -bounds.y(), ch);
|
||||
}
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, _x, _y, bounds.width(), bounds.height(), GL_RGBA, GL_UNSIGNED_BYTE, image.constBits());
|
||||
|
||||
glyph = Glyph(_currentTextureID, QPoint(_x, _y), bounds, _metrics.width(ch));
|
||||
_x += bounds.width();
|
||||
_rowHeight = qMax(_rowHeight, bounds.height());
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
return glyph;
|
||||
}
|
89
interface/src/ui/TextRenderer.h
Normal file
89
interface/src/ui/TextRenderer.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
//
|
||||
// TextRenderer.h
|
||||
// interface
|
||||
//
|
||||
// Created by Andrzej Kapolka on 4/26/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__TextRenderer__
|
||||
#define __interface__TextRenderer__
|
||||
|
||||
#include <QFont>
|
||||
#include <QFontMetrics>
|
||||
#include <QHash>
|
||||
#include <QImage>
|
||||
#include <QVector>
|
||||
|
||||
// a special "character" that renders as a solid block
|
||||
const char SOLID_BLOCK_CHAR = 127;
|
||||
|
||||
class Glyph;
|
||||
|
||||
class TextRenderer {
|
||||
public:
|
||||
|
||||
TextRenderer(const char* family, int pointSize = -1, int weight = -1, bool italic = false);
|
||||
~TextRenderer();
|
||||
|
||||
const QFontMetrics& metrics() const { return _metrics; }
|
||||
|
||||
void draw(int x, int y, const char* str);
|
||||
|
||||
int computeWidth(char ch);
|
||||
int computeWidth(const char* str);
|
||||
|
||||
private:
|
||||
|
||||
const Glyph& getGlyph (char c);
|
||||
|
||||
// the font to render
|
||||
QFont _font;
|
||||
|
||||
// the font metrics
|
||||
QFontMetrics _metrics;
|
||||
|
||||
// maps characters to cached glyph info
|
||||
QHash<char, Glyph> _glyphs;
|
||||
|
||||
// the id of the glyph texture to which we're currently writing
|
||||
GLuint _currentTextureID;
|
||||
|
||||
// the position within the current glyph texture
|
||||
int _x, _y;
|
||||
|
||||
// the height of the current row of characters
|
||||
int _rowHeight;
|
||||
|
||||
// the list of all texture ids for which we're responsible
|
||||
QVector<GLuint> _allTextureIDs;
|
||||
};
|
||||
|
||||
class Glyph {
|
||||
public:
|
||||
|
||||
Glyph(int textureID = 0, const QPoint& location = QPoint(), const QRect& bounds = QRect(), int width = 0);
|
||||
|
||||
GLuint textureID() const { return _textureID; }
|
||||
const QPoint& location () const { return _location; }
|
||||
const QRect& bounds() const { return _bounds; }
|
||||
int width () const { return _width; }
|
||||
|
||||
bool isValid() { return _width != 0; }
|
||||
|
||||
private:
|
||||
|
||||
// the id of the OpenGL texture containing the glyph
|
||||
GLuint _textureID;
|
||||
|
||||
// the location of the character within the texture
|
||||
QPoint _location;
|
||||
|
||||
// the bounds of the character
|
||||
QRect _bounds;
|
||||
|
||||
// the width of the character (distance to next, as opposed to bounds width)
|
||||
int _width;
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__TextRenderer__) */
|
|
@ -9,165 +9,116 @@
|
|||
#include <SharedUtil.h>
|
||||
#include "avatars_Log.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
//#include "Util.h"
|
||||
|
||||
using avatars_lib::printLog;
|
||||
|
||||
// XXXBHG - this test has not yet been reworked to match the correct vector orientation
|
||||
// of the coordinate system, so don't use it for now.
|
||||
//
|
||||
// tosh - yep, I noticed... :-)
|
||||
//
|
||||
|
||||
static bool testingForNormalizationAndOrthogonality = false;
|
||||
static const bool USING_QUATERNIONS = true;
|
||||
|
||||
Orientation::Orientation() {
|
||||
setToIdentity();
|
||||
}
|
||||
|
||||
void Orientation::setToIdentity() {
|
||||
_yaw = 0.0;
|
||||
_pitch = 0.0;
|
||||
_roll = 0.0;
|
||||
right = glm::vec3( -1.0f, 0.0f, 0.0f );
|
||||
up = glm::vec3( 0.0f, 1.0f, 0.0f );
|
||||
front = glm::vec3( 0.0f, 0.0f, 1.0f );
|
||||
|
||||
quat = glm::quat();
|
||||
right = glm::vec3( IDENTITY_RIGHT );
|
||||
up = glm::vec3( IDENTITY_UP );
|
||||
front = glm::vec3( IDENTITY_FRONT );
|
||||
}
|
||||
|
||||
void Orientation::set( Orientation o ) {
|
||||
|
||||
quat = o.quat;
|
||||
right = o.right;
|
||||
up = o.up;
|
||||
front = o.front;
|
||||
}
|
||||
|
||||
void Orientation::update() {
|
||||
void Orientation::yaw( float angle ) {
|
||||
|
||||
float pitchRads = _pitch * PI_OVER_180;
|
||||
float yawRads = _yaw * PI_OVER_180;
|
||||
float rollRads = _roll * PI_OVER_180;
|
||||
float radian = angle * PI_OVER_180;
|
||||
|
||||
glm::quat q(glm::vec3(pitchRads, -(yawRads), rollRads));
|
||||
|
||||
// Next, create a rotation matrix from that quaternion
|
||||
glm::mat4 rotation;
|
||||
rotation = glm::mat4_cast(q);
|
||||
|
||||
// Transform the original vectors by the rotation matrix to get the new vectors
|
||||
glm::vec4 qup(0,1,0,0);
|
||||
glm::vec4 qright(-1,0,0,0);
|
||||
glm::vec4 qfront(0,0,1,0);
|
||||
glm::vec4 upNew = qup*rotation;
|
||||
glm::vec4 rightNew = qright*rotation;
|
||||
glm::vec4 frontNew = qfront*rotation;
|
||||
|
||||
// Copy the answers to output vectors
|
||||
up.x = upNew.x;
|
||||
up.y = upNew.y;
|
||||
up.z = upNew.z;
|
||||
|
||||
right.x = rightNew.x;
|
||||
right.y = rightNew.y;
|
||||
right.z = rightNew.z;
|
||||
|
||||
front.x = frontNew.x;
|
||||
front.y = frontNew.y;
|
||||
front.z = frontNew.z;
|
||||
|
||||
if ( testingForNormalizationAndOrthogonality ) { testForOrthogonalAndNormalizedVectors( EPSILON ); }
|
||||
}
|
||||
|
||||
void Orientation::yaw(float angle) {
|
||||
// remember the value for any future changes to other angles
|
||||
_yaw = angle;
|
||||
update();
|
||||
if ( USING_QUATERNIONS ) {
|
||||
rotateAndGenerateDirections( glm::quat( glm::vec3( 0.0f, -radian, 0.0f )) );
|
||||
} else {
|
||||
float s = sin(radian);
|
||||
float c = cos(radian);
|
||||
|
||||
glm::vec3 cosineFront = front * c;
|
||||
glm::vec3 cosineRight = right * c;
|
||||
glm::vec3 sineFront = front * s;
|
||||
glm::vec3 sineRight = right * s;
|
||||
|
||||
front = cosineFront - sineRight;
|
||||
right = cosineRight + sineFront;
|
||||
}
|
||||
}
|
||||
|
||||
void Orientation::pitch( float angle ) {
|
||||
// remember the value for any future changes to other angles
|
||||
_pitch = angle;
|
||||
update();
|
||||
}
|
||||
|
||||
float radian = angle * PI_OVER_180;
|
||||
|
||||
if ( USING_QUATERNIONS ) {
|
||||
rotateAndGenerateDirections( glm::quat( glm::vec3( radian, 0.0f, 0.0f ) ) );
|
||||
} else {
|
||||
float s = sin(radian);
|
||||
float c = cos(radian);
|
||||
|
||||
glm::vec3 cosineUp = up * c;
|
||||
glm::vec3 cosineFront = front * c;
|
||||
glm::vec3 sineUp = up * s;
|
||||
glm::vec3 sineFront = front * s;
|
||||
|
||||
up = cosineUp - sineFront;
|
||||
front = cosineFront + sineUp;
|
||||
}
|
||||
}
|
||||
|
||||
void Orientation::roll( float angle ) {
|
||||
_roll = angle;
|
||||
update();
|
||||
|
||||
float radian = angle * PI_OVER_180;
|
||||
|
||||
if ( USING_QUATERNIONS ) {
|
||||
rotateAndGenerateDirections( glm::quat( glm::vec3( 0.0f, 0.0f, radian )) );
|
||||
} else {
|
||||
float s = sin(radian);
|
||||
float c = cos(radian);
|
||||
|
||||
glm::vec3 cosineUp = up * c;
|
||||
glm::vec3 cosineRight = right * c;
|
||||
glm::vec3 sineUp = up * s;
|
||||
glm::vec3 sineRight = right * s;
|
||||
|
||||
up = cosineUp - sineRight;
|
||||
right = cosineRight + sineUp;
|
||||
}
|
||||
}
|
||||
|
||||
void Orientation::rotate( float p, float y, float r ) {
|
||||
pitch(p);
|
||||
yaw (y);
|
||||
roll (r);
|
||||
}
|
||||
|
||||
void Orientation::rotate( glm::vec3 eulerAngles ) {
|
||||
|
||||
//this needs to be optimized!
|
||||
pitch(eulerAngles.x);
|
||||
yaw (eulerAngles.y);
|
||||
roll (eulerAngles.z);
|
||||
}
|
||||
|
||||
void Orientation::rotate( glm::quat rotation ) {
|
||||
rotateAndGenerateDirections(rotation);
|
||||
}
|
||||
|
||||
|
||||
void Orientation::setRightUpFront( const glm::vec3 &r, const glm::vec3 &u, const glm::vec3 &f ) {
|
||||
right = r;
|
||||
up = u;
|
||||
front = f;
|
||||
void Orientation::rotateAndGenerateDirections( glm::quat rotation ) {
|
||||
|
||||
quat = quat * rotation;
|
||||
|
||||
glm::mat4 rotationMatrix = glm::mat4_cast(quat);
|
||||
|
||||
right = glm::vec3( glm::vec4( IDENTITY_RIGHT, 0.0f ) * rotationMatrix );
|
||||
up = glm::vec3( glm::vec4( IDENTITY_UP, 0.0f ) * rotationMatrix );
|
||||
front = glm::vec3( glm::vec4( IDENTITY_FRONT, 0.0f ) * rotationMatrix );
|
||||
}
|
||||
|
||||
void Orientation::testForOrthogonalAndNormalizedVectors( float epsilon ) {
|
||||
|
||||
// XXXBHG - this test has not yet been reworked to match the correct vector orientation
|
||||
// of the coordinate system
|
||||
// bail for now, assume all is good
|
||||
return;
|
||||
|
||||
// make sure vectors are normalized (or close enough to length 1.0)
|
||||
float rightLength = glm::length( right );
|
||||
float upLength = glm::length( up );
|
||||
float frontLength = glm::length( front );
|
||||
|
||||
if (( rightLength > 1.0f + epsilon )
|
||||
|| ( rightLength < 1.0f - epsilon )) {
|
||||
printLog( "Error in Orientation class: right direction length is %f \n", rightLength );
|
||||
}
|
||||
assert ( rightLength > 1.0f - epsilon );
|
||||
assert ( rightLength < 1.0f + epsilon );
|
||||
|
||||
|
||||
if (( upLength > 1.0f + epsilon )
|
||||
|| ( upLength < 1.0f - epsilon )) {
|
||||
printLog( "Error in Orientation class: up direction length is %f \n", upLength );
|
||||
}
|
||||
assert ( upLength > 1.0f - epsilon );
|
||||
assert ( upLength < 1.0f + epsilon );
|
||||
|
||||
|
||||
if (( frontLength > 1.0f + epsilon )
|
||||
|| ( frontLength < 1.0f - epsilon )) {
|
||||
printLog( "Error in Orientation class: front direction length is %f \n", frontLength );
|
||||
}
|
||||
assert ( frontLength > 1.0f - epsilon );
|
||||
assert ( frontLength < 1.0f + epsilon );
|
||||
|
||||
|
||||
// make sure vectors are orthogonal (or close enough)
|
||||
glm::vec3 rightCross = glm::cross( up, front );
|
||||
glm::vec3 upCross = glm::cross( front, right );
|
||||
glm::vec3 frontCross = glm::cross( right, up );
|
||||
|
||||
float rightDiff = glm::length( rightCross - right );
|
||||
float upDiff = glm::length( upCross - up );
|
||||
float frontDiff = glm::length( frontCross - front );
|
||||
|
||||
|
||||
if ( rightDiff > epsilon ) {
|
||||
printLog( "Error in Orientation class: right direction not orthogonal to up and/or front. " );
|
||||
printLog( "The tested cross of up and front is off by %f \n", rightDiff );
|
||||
}
|
||||
assert ( rightDiff < epsilon );
|
||||
|
||||
|
||||
if ( upDiff > epsilon ) {
|
||||
printLog( "Error in Orientation class: up direction not orthogonal to front and/or right. " );
|
||||
printLog( "The tested cross of front and right is off by %f \n", upDiff );
|
||||
}
|
||||
assert ( upDiff < epsilon );
|
||||
|
||||
|
||||
if ( frontDiff > epsilon ) {
|
||||
printLog( "Error in Orientation class: front direction not orthogonal to right and/or up. " );
|
||||
printLog( "The tested cross of right and up is off by %f \n", frontDiff );
|
||||
}
|
||||
assert ( frontDiff < epsilon );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
//-----------------------------------------------------------
|
||||
//
|
||||
// Created by Jeffrey Ventrella
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
//-----------------------------------------------------------
|
||||
|
@ -8,52 +7,47 @@
|
|||
#ifndef __interface__orientation__
|
||||
#define __interface__orientation__
|
||||
|
||||
#include <cmath> // with this work? "Math.h"
|
||||
#include <cmath>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
enum Axis
|
||||
{
|
||||
ORIENTATION_RIGHT_AXIS,
|
||||
ORIENTATION_UP_AXIS,
|
||||
ORIENTATION_FRONT_AXIS
|
||||
};
|
||||
// this is where the coordinate system is represented
|
||||
const glm::vec3 IDENTITY_RIGHT = glm::vec3( -1.0f, 0.0f, 0.0f );
|
||||
const glm::vec3 IDENTITY_UP = glm::vec3( 0.0f, 1.0f, 0.0f );
|
||||
const glm::vec3 IDENTITY_FRONT = glm::vec3( 0.0f, 0.0f, 1.0f );
|
||||
|
||||
class Orientation
|
||||
{
|
||||
private:
|
||||
float _yaw;
|
||||
float _pitch;
|
||||
float _roll;
|
||||
public:
|
||||
Orientation();
|
||||
|
||||
void set( Orientation );
|
||||
void setToIdentity();
|
||||
|
||||
void pitch( float p );
|
||||
void yaw ( float y );
|
||||
void roll ( float r );
|
||||
|
||||
void rotate( float pitch, float yaw, float roll );
|
||||
void rotate( glm::vec3 EulerAngles );
|
||||
void rotate( glm::quat quaternion );
|
||||
|
||||
const glm::vec3 & getRight() const { return right; }
|
||||
const glm::vec3 & getUp () const { return up; }
|
||||
const glm::vec3 & getFront() const { return front; }
|
||||
|
||||
const glm::vec3 & getIdentityRight() const { return IDENTITY_RIGHT; }
|
||||
const glm::vec3 & getIdentityUp () const { return IDENTITY_UP; }
|
||||
const glm::vec3 & getIdentityFront() const { return IDENTITY_FRONT; }
|
||||
|
||||
private:
|
||||
|
||||
glm::quat quat;
|
||||
glm::vec3 right;
|
||||
glm::vec3 up;
|
||||
glm::vec3 front;
|
||||
|
||||
void update(); // actually updates the vectors from yaw, pitch, roll
|
||||
|
||||
public:
|
||||
Orientation();
|
||||
|
||||
void yaw ( float );
|
||||
void pitch ( float );
|
||||
void roll ( float );
|
||||
|
||||
float getYaw() { return _yaw; };
|
||||
float getPitch(){ return _pitch; };
|
||||
float getRoll(){ return _roll; };
|
||||
|
||||
void set( Orientation );
|
||||
void setToIdentity();
|
||||
|
||||
const glm::vec3& getRight() const { return right; }
|
||||
const glm::vec3& getUp() const { return up; }
|
||||
const glm::vec3& getFront() const { return front; }
|
||||
|
||||
void setRightUpFront( const glm::vec3 &, const glm::vec3 &, const glm::vec3 & );
|
||||
|
||||
private:
|
||||
void testForOrthogonalAndNormalizedVectors( float epsilon );
|
||||
void rotateAndGenerateDirections( glm::quat rotation );
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,7 +14,7 @@ AudioRingBuffer::AudioRingBuffer(int ringSamples, int bufferSamples) {
|
|||
bufferLengthSamples = bufferSamples;
|
||||
|
||||
started = false;
|
||||
addedToMix = false;
|
||||
_shouldBeAddedToMix = false;
|
||||
|
||||
endOfLastWrite = NULL;
|
||||
|
||||
|
@ -26,7 +26,7 @@ AudioRingBuffer::AudioRingBuffer(const AudioRingBuffer &otherRingBuffer) {
|
|||
ringBufferLengthSamples = otherRingBuffer.ringBufferLengthSamples;
|
||||
bufferLengthSamples = otherRingBuffer.bufferLengthSamples;
|
||||
started = otherRingBuffer.started;
|
||||
addedToMix = otherRingBuffer.addedToMix;
|
||||
_shouldBeAddedToMix = otherRingBuffer._shouldBeAddedToMix;
|
||||
|
||||
buffer = new int16_t[ringBufferLengthSamples];
|
||||
memcpy(buffer, otherRingBuffer.buffer, sizeof(int16_t) * ringBufferLengthSamples);
|
||||
|
@ -71,14 +71,6 @@ void AudioRingBuffer::setStarted(bool status) {
|
|||
started = status;
|
||||
}
|
||||
|
||||
bool AudioRingBuffer::wasAddedToMix() {
|
||||
return addedToMix;
|
||||
}
|
||||
|
||||
void AudioRingBuffer::setAddedToMix(bool added) {
|
||||
addedToMix = added;
|
||||
}
|
||||
|
||||
float* AudioRingBuffer::getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
@ -136,8 +128,6 @@ int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
|
||||
endOfLastWrite += bufferLengthSamples;
|
||||
|
||||
addedToMix = false;
|
||||
|
||||
if (endOfLastWrite >= buffer + ringBufferLengthSamples) {
|
||||
endOfLastWrite = buffer;
|
||||
}
|
||||
|
|
|
@ -13,42 +13,42 @@
|
|||
#include "AgentData.h"
|
||||
|
||||
class AudioRingBuffer : public AgentData {
|
||||
public:
|
||||
AudioRingBuffer(int ringSamples, int bufferSamples);
|
||||
~AudioRingBuffer();
|
||||
AudioRingBuffer(const AudioRingBuffer &otherRingBuffer);
|
||||
|
||||
int parseData(unsigned char* sourceBuffer, int numBytes);
|
||||
AudioRingBuffer* clone() const;
|
||||
public:
|
||||
AudioRingBuffer(int ringSamples, int bufferSamples);
|
||||
~AudioRingBuffer();
|
||||
AudioRingBuffer(const AudioRingBuffer &otherRingBuffer);
|
||||
|
||||
int16_t* getNextOutput();
|
||||
void setNextOutput(int16_t *newPointer);
|
||||
int16_t* getEndOfLastWrite();
|
||||
void setEndOfLastWrite(int16_t *newPointer);
|
||||
int16_t* getBuffer();
|
||||
bool isStarted();
|
||||
void setStarted(bool status);
|
||||
bool wasAddedToMix();
|
||||
void setAddedToMix(bool added);
|
||||
float* getPosition();
|
||||
void setPosition(float newPosition[]);
|
||||
float getAttenuationRatio();
|
||||
void setAttenuationRatio(float newAttenuation);
|
||||
float getBearing();
|
||||
void setBearing(float newBearing);
|
||||
|
||||
short diffLastWriteNextOutput();
|
||||
private:
|
||||
int ringBufferLengthSamples;
|
||||
int bufferLengthSamples;
|
||||
float position[3];
|
||||
float attenuationRatio;
|
||||
float bearing;
|
||||
int16_t *nextOutput;
|
||||
int16_t *endOfLastWrite;
|
||||
int16_t *buffer;
|
||||
bool started;
|
||||
bool addedToMix;
|
||||
int parseData(unsigned char* sourceBuffer, int numBytes);
|
||||
AudioRingBuffer* clone() const;
|
||||
|
||||
int16_t* getNextOutput();
|
||||
void setNextOutput(int16_t *newPointer);
|
||||
int16_t* getEndOfLastWrite();
|
||||
void setEndOfLastWrite(int16_t *newPointer);
|
||||
int16_t* getBuffer();
|
||||
bool isStarted();
|
||||
void setStarted(bool status);
|
||||
bool shouldBeAddedToMix() const { return _shouldBeAddedToMix; }
|
||||
void setShouldBeAddedToMix(bool shouldBeAddedToMix) { _shouldBeAddedToMix = shouldBeAddedToMix; }
|
||||
float* getPosition();
|
||||
void setPosition(float newPosition[]);
|
||||
float getAttenuationRatio();
|
||||
void setAttenuationRatio(float newAttenuation);
|
||||
float getBearing();
|
||||
void setBearing(float newBearing);
|
||||
|
||||
short diffLastWriteNextOutput();
|
||||
private:
|
||||
int ringBufferLengthSamples;
|
||||
int bufferLengthSamples;
|
||||
float position[3];
|
||||
float attenuationRatio;
|
||||
float bearing;
|
||||
int16_t *nextOutput;
|
||||
int16_t *endOfLastWrite;
|
||||
int16_t *buffer;
|
||||
bool started;
|
||||
bool _shouldBeAddedToMix;
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__AudioRingBuffer__) */
|
||||
|
|
|
@ -21,4 +21,7 @@ const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL;
|
|||
const int INDICES_PER_VOXEL = 3 * 12;
|
||||
const int COLOR_VALUES_PER_VOXEL = 3 * VERTICES_PER_VOXEL;
|
||||
|
||||
typedef unsigned long int glBufferIndex;
|
||||
const glBufferIndex GLBUFFER_INDEX_UNKNOWN = ULONG_MAX;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -30,6 +30,10 @@ VoxelNode::VoxelNode() {
|
|||
for (int i = 0; i < 8; i++) {
|
||||
children[i] = NULL;
|
||||
}
|
||||
|
||||
_glBufferIndex = GLBUFFER_INDEX_UNKNOWN;
|
||||
_isDirty = true;
|
||||
_shouldRender = false;
|
||||
}
|
||||
|
||||
VoxelNode::~VoxelNode() {
|
||||
|
@ -43,6 +47,14 @@ VoxelNode::~VoxelNode() {
|
|||
}
|
||||
}
|
||||
|
||||
void VoxelNode::setShouldRender(bool shouldRender) {
|
||||
// if shouldRender is changing, then consider ourselves dirty
|
||||
if (shouldRender != _shouldRender) {
|
||||
_shouldRender = shouldRender;
|
||||
_isDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelNode::getAABox(AABox& box) const {
|
||||
|
||||
glm::vec3 corner;
|
||||
|
@ -59,16 +71,19 @@ void VoxelNode::getAABox(AABox& box) const {
|
|||
}
|
||||
|
||||
void VoxelNode::addChildAtIndex(int childIndex) {
|
||||
children[childIndex] = new VoxelNode();
|
||||
if (!children[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);
|
||||
// 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);
|
||||
// give this child its octal code
|
||||
children[childIndex]->octalCode = childOctalCode(octalCode, childIndex);
|
||||
_isDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
// will average the child colors...
|
||||
|
@ -104,26 +119,35 @@ void VoxelNode::setColorFromAverageOfChildren() {
|
|||
// 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
|
||||
if (_falseColored != true || _currentColor[0] != red || _currentColor[1] != green || _currentColor[2] != blue) {
|
||||
_falseColored=true;
|
||||
_currentColor[0] = red;
|
||||
_currentColor[1] = green;
|
||||
_currentColor[2] = blue;
|
||||
_currentColor[3] = 1; // XXXBHG - False colors are always considered set
|
||||
_isDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
if (_falseColored != 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;
|
||||
_isDirty = true;
|
||||
}
|
||||
_falseColored = isFalseColored;
|
||||
};
|
||||
|
||||
|
||||
void VoxelNode::setColor(const nodeColor& color) {
|
||||
memcpy(&_trueColor,&color,sizeof(nodeColor));
|
||||
if (!_falseColored) {
|
||||
memcpy(&_currentColor,&color,sizeof(nodeColor));
|
||||
if (_trueColor[0] != color[0] || _trueColor[1] != color[1] || _trueColor[2] != color[2]) {
|
||||
memcpy(&_trueColor,&color,sizeof(nodeColor));
|
||||
if (!_falseColored) {
|
||||
memcpy(&_currentColor,&color,sizeof(nodeColor));
|
||||
}
|
||||
_isDirty = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -199,7 +223,6 @@ void VoxelNode::printDebugDetails(const char* label) const {
|
|||
printOctalCode(octalCode);
|
||||
}
|
||||
|
||||
|
||||
bool VoxelNode::isInView(const ViewFrustum& viewFrustum) const {
|
||||
AABox box;
|
||||
getAABox(box);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "AABox.h"
|
||||
#include "ViewFrustum.h"
|
||||
#include "VoxelConstants.h"
|
||||
|
||||
typedef unsigned char colorPart;
|
||||
typedef unsigned char nodeColor[4];
|
||||
|
@ -22,6 +23,9 @@ private:
|
|||
nodeColor _currentColor;
|
||||
bool _falseColored;
|
||||
#endif
|
||||
glBufferIndex _glBufferIndex;
|
||||
bool _isDirty;
|
||||
bool _shouldRender;
|
||||
public:
|
||||
VoxelNode();
|
||||
~VoxelNode();
|
||||
|
@ -40,7 +44,14 @@ public:
|
|||
bool isLeaf() const;
|
||||
void getAABox(AABox& box) const;
|
||||
void printDebugDetails(const char* label) const;
|
||||
|
||||
bool isDirty() const { return _isDirty; };
|
||||
void clearDirtyBit() { _isDirty = false; };
|
||||
glBufferIndex getBufferIndex() const { return _glBufferIndex; };
|
||||
bool isKnownBufferIndex() const { return (_glBufferIndex != GLBUFFER_INDEX_UNKNOWN); };
|
||||
void setBufferIndex(glBufferIndex index) { _glBufferIndex = index; };
|
||||
void setShouldRender(bool shouldRender);
|
||||
bool getShouldRender() const { return _shouldRender; }
|
||||
|
||||
#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color
|
||||
void setFalseColor(colorPart red, colorPart green, colorPart blue);
|
||||
void setFalseColored(bool isFalseColored);
|
||||
|
|
|
@ -58,16 +58,13 @@ void VoxelTree::recurseTreeWithOperation(RecurseVoxelTreeOperation operation, vo
|
|||
|
||||
// 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++) {
|
||||
if (operation(node, 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);
|
||||
recurseNodeWithOperation(child, operation, extraData);
|
||||
}
|
||||
}
|
||||
// call operation on way back up
|
||||
operation(node,false,extraData);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "VoxelNodeBag.h"
|
||||
|
||||
// Callback function, for recuseTreeWithOperation
|
||||
typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, bool down, void* extraData);
|
||||
typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, void* extraData);
|
||||
|
||||
class VoxelTree {
|
||||
public:
|
||||
|
|
|
@ -38,7 +38,7 @@ const float DEATH_STAR_RADIUS = 4.0;
|
|||
const float MAX_CUBE = 0.05f;
|
||||
|
||||
const int VOXEL_SEND_INTERVAL_USECS = 100 * 1000;
|
||||
const int PACKETS_PER_CLIENT_PER_INTERVAL = 2;
|
||||
const int PACKETS_PER_CLIENT_PER_INTERVAL = 20;
|
||||
|
||||
const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4;
|
||||
|
||||
|
@ -68,11 +68,9 @@ void addSphere(VoxelTree * tree,bool random, bool wantColorRandomizer) {
|
|||
}
|
||||
|
||||
int _nodeCount=0;
|
||||
bool countVoxelsOperation(VoxelNode* node, bool down, void* extraData) {
|
||||
if (down) {
|
||||
if (node->isColored()){
|
||||
_nodeCount++;
|
||||
}
|
||||
bool countVoxelsOperation(VoxelNode* node, void* extraData) {
|
||||
if (node->isColored()){
|
||||
_nodeCount++;
|
||||
}
|
||||
return true; // keep going
|
||||
}
|
||||
|
@ -80,7 +78,7 @@ bool countVoxelsOperation(VoxelNode* node, bool down, void* extraData) {
|
|||
void addSphereScene(VoxelTree * tree, bool wantColorRandomizer) {
|
||||
printf("adding scene of spheres...\n");
|
||||
|
||||
int sphereBaseSize = 256;
|
||||
int sphereBaseSize = 512;
|
||||
|
||||
tree->createSphere(0.25, 0.5, 0.5, 0.5, (1.0 / sphereBaseSize), true, wantColorRandomizer);
|
||||
printf("one sphere added...\n");
|
||||
|
|
Loading…
Reference in a new issue