Merge branch 'master' of https://github.com/worklist/hifi into view_frustum_work

This commit is contained in:
ZappoMan 2013-04-24 23:50:57 -07:00
commit 0bec7156aa
31 changed files with 982 additions and 839 deletions

View file

@ -133,7 +133,7 @@ int main(int argc, const char * argv[])
if (DEBUG_TO_SELF ||
!agent->matches((sockaddr *)&agentPublicAddress, (sockaddr *)&agentLocalAddress, agentType)) {
if (memchr(SOLO_AGENT_TYPES_STRING, agent->getType(), 1) == NULL) {
if (memchr(SOLO_AGENT_TYPES, agent->getType(), sizeof(SOLO_AGENT_TYPES)) == NULL) {
// this is an agent of which there can be multiple, just add them to the packet
// don't send avatar agents to other avatars, that will come from avatar mixer
if (agentType != AGENT_TYPE_AVATAR || agent->getType() != AGENT_TYPE_AVATAR) {

View file

@ -13,20 +13,31 @@
#include <PacketHeaders.h>
#include <AgentList.h>
#include <AvatarData.h>
#include <AudioInjector.h>
const int EVE_AGENT_LIST_PORT = 55441;
const float DATA_SEND_INTERVAL_MSECS = 10;
const int EVE_AGENT_LISTEN_PORT = 55441;
const float RANDOM_POSITION_MAX_DIMENSION = 5.0f;
const float DATA_SEND_INTERVAL_MSECS = 15;
const float MIN_AUDIO_SEND_INTERVAL_SECS = 10;
const int MIN_ITERATIONS_BETWEEN_AUDIO_SENDS = (MIN_AUDIO_SEND_INTERVAL_SECS * 1000) / DATA_SEND_INTERVAL_MSECS;
const int MAX_AUDIO_SEND_INTERVAL_SECS = 15;
const float MAX_ITERATIONS_BETWEEN_AUDIO_SENDS = (MAX_AUDIO_SEND_INTERVAL_SECS * 1000) / DATA_SEND_INTERVAL_MSECS;
bool stopReceiveAgentDataThread;
bool injectAudioThreadRunning = false;
void *receiveAgentData(void *args)
{
int TEMP_AUDIO_LISTEN_PORT = 55439;
// UDPSocket audioSocket(TEMP_AUDIO_LISTEN_PORT);
void *receiveAgentData(void *args) {
sockaddr senderAddress;
ssize_t bytesReceived;
unsigned char incomingPacket[MAX_PACKET_SIZE];
AgentList *agentList = AgentList::getInstance();
Agent *avatarMixer = NULL;
AgentList* agentList = AgentList::getInstance();
Agent* avatarMixer = NULL;
while (!::stopReceiveAgentDataThread) {
if (agentList->getAgentSocket().receive(&senderAddress, incomingPacket, &bytesReceived)) {
@ -54,9 +65,35 @@ void *receiveAgentData(void *args)
return NULL;
}
int main(int argc, char* argv[]) {
void *injectAudio(void *args) {
::injectAudioThreadRunning = true;
AudioInjector* eveAudioInjector = (AudioInjector *)args;
// look for an audio mixer in our agent list
Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER);
if (audioMixer != NULL) {
// until the audio mixer is setup for ping-reply, activate the public socket if it's not active
if (audioMixer->getActiveSocket() == NULL) {
audioMixer->activatePublicSocket();
}
// we have an active audio mixer we can send data to
// eveAudioInjector->injectAudio(&::audioSocket, audioMixer->getActiveSocket());
}
::injectAudioThreadRunning = false;
pthread_exit(0);
return NULL;
}
int main(int argc, const char* argv[]) {
// new seed for random audio sleep times
srand(time(0));
// create an AgentList instance to handle communication with other agents
AgentList *agentList = AgentList::createInstance(AGENT_TYPE_AVATAR, EVE_AGENT_LIST_PORT);
AgentList* agentList = AgentList::createInstance(AGENT_TYPE_AVATAR, EVE_AGENT_LISTEN_PORT);
// start telling the domain server that we are alive
agentList->startDomainServerCheckInThread();
@ -74,15 +111,21 @@ int main(int argc, char* argv[]) {
AvatarData eve = AvatarData();
// move eve away from the origin
eve.setBodyPosition(glm::vec3(3, 0, -3));
// pick a random point inside a 10x10 grid
// turn her back towards the origin
eve.setBodyYaw(-45);
eve.setPosition(glm::vec3(randFloatInRange(-RANDOM_POSITION_MAX_DIMENSION, RANDOM_POSITION_MAX_DIMENSION),
0,
randFloatInRange(-RANDOM_POSITION_MAX_DIMENSION, RANDOM_POSITION_MAX_DIMENSION)));
// face any instance of eve down the z-axis
eve.setBodyYaw(0);
// put her hand out so somebody can shake it
eve.setHandPosition(glm::vec3(eve.getBodyPosition()[0] - 0.2,
eve.setHandPosition(glm::vec3(eve.getPosition()[0] - 0.2,
0.25,
eve.getBodyPosition()[2] + 0.1));
eve.getPosition()[2] + 0.1));
// read eve's audio data
AudioInjector eveAudioInjector("eve.raw");
unsigned char broadcastPacket[MAX_PACKET_SIZE];
broadcastPacket[0] = PACKET_HEADER_HEAD_DATA;
@ -92,6 +135,11 @@ int main(int argc, char* argv[]) {
timeval thisSend;
double numMicrosecondsSleep = 0;
// int numIterationsLeftBeforeAudioSend = 0;
// pthread_t injectAudioThread;
int handStateTimer = 0;
while (true) {
// update the thisSend timeval to the current time
gettimeofday(&thisSend, NULL);
@ -104,15 +152,38 @@ int main(int argc, char* argv[]) {
// use the getBroadcastData method in the AvatarData class to populate the broadcastPacket buffer
numBytesToSend = eve.getBroadcastData((broadcastPacket + 1));
// use the UDPSocket instance attached to our agent list to send avatar data to mixer
agentList->getAgentSocket().send(avatarMixer->getActiveSocket(), broadcastPacket, numBytesToSend);
}
// 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--;
// }
// sleep for the correct amount of time to have data send be consistently timed
if ((numMicrosecondsSleep = (DATA_SEND_INTERVAL_MSECS * 1000) - (usecTimestampNow() - usecTimestamp(&thisSend))) > 0) {
usleep(numMicrosecondsSleep);
}
}
// simulate the effect of pressing and un-pressing the mouse button/pad
handStateTimer++;
if ( handStateTimer == 100 ) {
eve.setHandState(1);
}
if ( handStateTimer == 150 ) {
eve.setHandState(0);
}
if ( handStateTimer >= 200 ) {
handStateTimer = 0;
}
}
// stop the receive agent data thread

View file

@ -14,4 +14,4 @@ link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
# link the threads library
find_package(Threads REQUIRED)
target_link_libraries(injector ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT})

View file

@ -1,5 +1,5 @@
//
// injector.cpp
// main.cpp
// Audio Injector
//
// Created by Leonardo Murillo on 3/5/13.
@ -11,39 +11,27 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <vector>
#include <fstream>
#include <algorithm>
#include <arpa/inet.h>
#include <string.h>
#include <sstream>
#include "UDPSocket.h"
#include "UDPSocket.cpp"
#include <SharedUtil.h>
#include <PacketHeaders.h>
#include <UDPSocket.h>
#include <AudioInjector.h>
char EC2_WEST_AUDIO_SERVER[] = "54.241.92.53";
const int AUDIO_UDP_LISTEN_PORT = 55443;
const int BUFFER_LENGTH_BYTES = 512;
const int BUFFER_LENGTH_SAMPLES = BUFFER_LENGTH_BYTES / sizeof(int16_t);
const float SAMPLE_RATE = 22050.0;
const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES / SAMPLE_RATE) * 1000000;
// Command line parameter defaults
bool loopAudio = true;
float sleepIntervalMin = 1.00;
float sleepIntervalMax = 2.00;
float positionInUniverse[] = {0, 0, 0, 0};
unsigned char attenuationModifier = 255;
char *sourceAudioFile;
char *sourceAudioFile = NULL;
const char *allowedParameters = ":rb::t::c::a::f:";
char *charBuffer;
int16_t *buffer;
long length;
UDPSocket *streamSocket;
float floatArguments[4] = {0.0f, 0.0f, 0.0f, 0.0f};
unsigned char attenuationModifier = 255;
void usage(void)
{
@ -54,7 +42,7 @@ void usage(void)
std::cout << " -c FLOAT,FLOAT,FLOAT,FLOAT X,Y,Z,YAW position in universe where audio will be originating from and direction. Defaults to 0,0,0,0" << std::endl;
std::cout << " -a 0-255 Attenuation curve modifier, defaults to 255" << std::endl;
std::cout << " -f FILENAME Name of audio source file. Required - RAW format, 22050hz 16bit signed mono" << std::endl;
};
}
bool processParameters(int parameterCount, char* parameterData[])
{
@ -62,19 +50,19 @@ bool processParameters(int parameterCount, char* parameterData[])
while ((p = getopt(parameterCount, parameterData, allowedParameters)) != -1) {
switch (p) {
case 'r':
loopAudio = false;
::loopAudio = false;
std::cout << "[DEBUG] Random sleep mode enabled" << std::endl;
break;
case 'b':
sleepIntervalMin = atof(optarg);
::sleepIntervalMin = atof(optarg);
std::cout << "[DEBUG] Min delay between plays " << sleepIntervalMin << "sec" << std::endl;
break;
case 't':
sleepIntervalMax = atof(optarg);
::sleepIntervalMax = atof(optarg);
std::cout << "[DEBUG] Max delay between plays " << sleepIntervalMax << "sec" << std::endl;
break;
case 'f':
sourceAudioFile = optarg;
::sourceAudioFile = optarg;
std::cout << "[DEBUG] Opening file: " << sourceAudioFile << std::endl;
break;
case 'c':
@ -84,7 +72,7 @@ bool processParameters(int parameterCount, char* parameterData[])
int i = 0;
while (std::getline(ss, token, ',')) {
positionInUniverse[i] = atof(token.c_str());
::floatArguments[i] = atof(token.c_str());
++i;
if (i == 4) {
break;
@ -94,7 +82,7 @@ bool processParameters(int parameterCount, char* parameterData[])
break;
}
case 'a':
attenuationModifier = atoi(optarg);
::attenuationModifier = atoi(optarg);
std::cout << "[DEBUG] Attenuation modifier: " << optarg << std::endl;
break;
default:
@ -105,77 +93,42 @@ bool processParameters(int parameterCount, char* parameterData[])
return true;
};
void loadFile(void) {
std::fstream sourceFile;
sourceFile.open(sourceAudioFile, std::ios::in | std::ios::binary);
sourceFile.seekg(0, std::ios::end);
length = sourceFile.tellg();
sourceFile.seekg(0, std::ios::beg);
long sizeOfShortArray = length / 2;
buffer = new int16_t[sizeOfShortArray];
sourceFile.read((char *)buffer, length);
}
void stream(void)
{
timeval startTime;
int leadingBytes = 1 + (sizeof(float) * 4);
unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes];
dataPacket[0] = PACKET_HEADER_INJECT_AUDIO;
unsigned char *currentPacketPtr = dataPacket + 1;
for (int p = 0; p < 4; p++) {
memcpy(currentPacketPtr, &positionInUniverse[p], sizeof(float));
currentPacketPtr += sizeof(float);
}
*currentPacketPtr = attenuationModifier;
currentPacketPtr++;
for (int i = 0; i < length; i += BUFFER_LENGTH_SAMPLES) {
gettimeofday(&startTime, NULL);
memcpy(currentPacketPtr, &buffer[i], BUFFER_LENGTH_BYTES);
streamSocket->send(EC2_WEST_AUDIO_SERVER, AUDIO_UDP_LISTEN_PORT, dataPacket, sizeof(dataPacket));
double usecToSleep = usecTimestamp(&startTime) + BUFFER_SEND_INTERVAL_USECS - usecTimestampNow();
usleep(usecToSleep);
}
};
int main(int argc, char* argv[])
{
int main(int argc, char* argv[]) {
srand(time(0));
int AUDIO_UDP_SEND_PORT = 1500 + (rand() % (int)(1500 - 2000 + 1));
streamSocket = new UDPSocket(AUDIO_UDP_SEND_PORT);
UDPSocket streamSocket(AUDIO_UDP_SEND_PORT);
if (processParameters(argc, argv)) {
if (sourceAudioFile) {
loadFile();
} else {
sockaddr_in mixerSocket;
mixerSocket.sin_family = AF_INET;
mixerSocket.sin_addr.s_addr = inet_addr(EC2_WEST_AUDIO_SERVER);
mixerSocket.sin_port = htons((uint16_t)AUDIO_UDP_LISTEN_PORT);
if (processParameters(argc, argv)) {
if (::sourceAudioFile == NULL) {
std::cout << "[FATAL] Source audio file not specified" << std::endl;
exit(-1);
}
for (int i = 0; i < sizeof(positionInUniverse)/sizeof(positionInUniverse[0]); ++i) {
std::cout << "Position " << positionInUniverse[i] << std::endl;
}
float delay;
int usecDelay;
while (true) {
stream();
} else {
AudioInjector injector(sourceAudioFile);
if (loopAudio) {
delay = 0;
} else {
delay = randFloatInRange(sleepIntervalMin, sleepIntervalMax);
injector.setPosition(::floatArguments);
injector.setBearing(*(::floatArguments + 3));
injector.setAttenuationModifier(::attenuationModifier);
float delay = 0;
int usecDelay = 0;
while (true) {
injector.injectAudio(&streamSocket, (sockaddr*) &mixerSocket);
if (!::loopAudio) {
delay = randFloatInRange(::sleepIntervalMin, ::sleepIntervalMax);
usecDelay = delay * 1000 * 1000;
usleep(usecDelay);
}
}
usecDelay = delay * 1000 * 1000;
usleep(usecDelay);
}
}
}
return 0;
}

View file

@ -130,7 +130,7 @@ int audioCallback (const void *inputBuffer,
loudness /= BUFFER_LENGTH_SAMPLES;
data->lastInputLoudness = loudness;
data->averagedInputLoudness = 0.66*data->averagedInputLoudness + 0.33*loudness;
//
// If scope is turned on, copy input buffer to scope
//
@ -157,7 +157,7 @@ int audioCallback (const void *inputBuffer,
// memcpy the three float positions
for (int p = 0; p < 3; p++) {
memcpy(currentPacketPtr, &data->linkedHead->getBodyPosition()[p], sizeof(float));
memcpy(currentPacketPtr, &data->linkedAvatar->getPosition()[p], sizeof(float));
currentPacketPtr += sizeof(float);
}
@ -165,7 +165,7 @@ int audioCallback (const void *inputBuffer,
*(currentPacketPtr++) = 255;
// memcpy the corrected render yaw
float correctedYaw = fmodf(data->linkedHead->getRenderYaw(), 360);
float correctedYaw = fmodf(data->linkedAvatar->getRenderYaw(), 360);
if (correctedYaw > 180) {
correctedYaw -= 360;
@ -259,7 +259,7 @@ int audioCallback (const void *inputBuffer,
// rotation of the head relative to body, this may effect flange effect!
//
//
int lastYawMeasured = fabsf(data->linkedHead->getLastMeasuredHeadYaw());
int lastYawMeasured = fabsf(data->linkedAvatar->getLastMeasuredHeadYaw());
if (!samplesLeftForFlange && lastYawMeasured > MIN_FLANGE_EFFECT_THRESHOLD) {
// we should flange for one second
@ -448,7 +448,7 @@ void Audio::setWalkingState(bool newWalkState) {
* @return Returns true if successful or false if an error occurred.
Use Audio::getError() to retrieve the error code.
*/
Audio::Audio(Oscilloscope *s, Head *linkedHead)
Audio::Audio(Oscilloscope *s, Avatar *linkedAvatar)
{
// read the walking sound from the raw file and store it
// in the in memory array
@ -472,7 +472,7 @@ Audio::Audio(Oscilloscope *s, Head *linkedHead)
audioData = new AudioData();
audioData->linkedHead = linkedHead;
audioData->linkedAvatar = linkedAvatar;
// setup a UDPSocket
audioData->audioSocket = new UDPSocket(AUDIO_UDP_LISTEN_PORT);
@ -510,9 +510,8 @@ error:
}
void Audio::getInputLoudness(float * lastLoudness, float * averageLoudness) {
*lastLoudness = audioData->lastInputLoudness;
*averageLoudness = audioData->averagedInputLoudness;
float Audio::getInputLoudness() const {
return audioData->lastInputLoudness;
}
void Audio::render(int screenWidth, int screenHeight)

View file

@ -12,12 +12,12 @@
#include <portaudio.h>
#include "AudioData.h"
#include "Oscilloscope.h"
#include "Head.h"
#include "Avatar.h"
class Audio {
public:
// initializes audio I/O
Audio(Oscilloscope *s, Head *linkedHead);
Audio(Oscilloscope *s, Avatar *linkedAvatar);
void render();
void render(int screenWidth, int screenHeight);
@ -25,7 +25,7 @@ public:
bool getMixerLoopbackFlag();
void setMixerLoopbackFlag(bool newMixerLoopbackFlag);
void getInputLoudness(float * lastLoudness, float * averageLoudness);
float getInputLoudness() const;
void updateMixerParams(in_addr_t mixerAddress, in_port_t mixerPort);
void setWalkingState(bool newWalkState);

View file

@ -13,7 +13,7 @@
#include <glm/glm.hpp>
#include "AudioRingBuffer.h"
#include "UDPSocket.h"
#include "Head.h"
#include "Avatar.h"
class AudioData {
public:
@ -23,7 +23,7 @@ class AudioData {
UDPSocket *audioSocket;
Head *linkedHead;
Avatar *linkedAvatar;
// store current mixer address and port
in_addr_t mixerAddress;
@ -36,7 +36,6 @@ class AudioData {
int wasStarved;
float lastInputLoudness;
float averagedInputLoudness;
bool mixerLoopbackFlag;
bool playWalkSound;

File diff suppressed because it is too large Load diff

View file

@ -1,13 +1,13 @@
//
// Head.h
// Avatar.h
// interface
//
// Created by Philip Rosedale on 9/11/12.
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__head__
#define __interface__head__
#ifndef __interface__avatar__
#define __interface__avatar__
#include <AvatarData.h>
#include <Orientation.h>
@ -29,6 +29,9 @@ const float YAW_MAG = 300.0;
const float TEST_YAW_DECAY = 5.0;
const float LIN_VEL_DECAY = 5.0;
const float COLLISION_BODY_RADIUS = 0.1;
const float COLLISION_HEIGHT = 1.5;
enum eyeContactTargets {LEFT_EYE, RIGHT_EYE, MOUTH};
#define FWD 0
@ -41,7 +44,7 @@ enum eyeContactTargets {LEFT_EYE, RIGHT_EYE, MOUTH};
#define ROT_RIGHT 7
#define MAX_DRIVE_KEYS 8
#define MAX_OTHER_AVATARS 50 // temporary - for testing purposes!
#define MAX_OTHER_AVATARS 10 // temporary - for testing purposes!
enum AvatarMode
{
@ -81,6 +84,22 @@ enum AvatarBoneID
NUM_AVATAR_BONES
};
struct AvatarCollisionElipsoid
{
bool colliding;
glm::vec3 position;
float girth;
float height;
glm::vec3 upVector;
};
struct AvatarHandHolding
{
glm::vec3 position;
glm::vec3 velocity;
float force;
};
struct AvatarBone
{
AvatarBoneID parent; // which bone is this bone connected to?
@ -137,12 +156,12 @@ struct AvatarHead
};
class Head : public AvatarData {
class Avatar : public AvatarData {
public:
Head(bool isMine);
~Head();
Head(const Head &otherHead);
Head* clone() const;
Avatar(bool isMine);
~Avatar();
Avatar(const Avatar &otherAvatar);
Avatar* clone() const;
void reset();
void UpdateGyros(float frametime, SerialInterface * serialInterface, glm::vec3 * gravity);
@ -163,8 +182,11 @@ class Head : public AvatarData {
glm::vec3 getHeadLookatDirectionUp();
glm::vec3 getHeadLookatDirectionRight();
glm::vec3 getHeadPosition();
glm::vec3 getBonePosition( AvatarBoneID b );
glm::vec3 getBonePosition( AvatarBoneID b );
glm::vec3 getBodyUpDirection();
float getGirth();
float getHeight();
AvatarMode getMode();
void setMousePressed( bool pressed );
@ -175,11 +197,12 @@ class Head : public AvatarData {
void startHandMovement();
void stopHandMovement();
void setHandMovementValues( glm::vec3 movement );
void updateHandMovement();
void updateHandMovement( float deltaTime );
void updateArmIKAndConstraints( float deltaTime );
float getAverageLoudness() {return _head.averageLoudness;};
void setAverageLoudness(float al) {_head.averageLoudness = al;};
void SetNewHeadTarget(float, float);
// Set what driving keys are being pressed to control thrust levels
@ -191,58 +214,55 @@ class Head : public AvatarData {
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };
glm::vec3 getThrust() { return _thrust; };
//
// Related to getting transmitter UDP data used to animate the avatar hand
//
void processTransmitterData(unsigned char * packetData, int numBytes);
float getTransmitterHz() { return _transmitterHz; };
private:
AvatarHead _head;
bool _isMine;
glm::vec3 _TEST_bigSpherePosition;
float _TEST_bigSphereRadius;
glm::vec3 _otherAvatarHandPosition[ MAX_OTHER_AVATARS ];
bool _mousePressed;
float _bodyYawDelta;
int _closestOtherAvatar;
bool _usingBodySprings;
glm::vec3 _movedHandOffset;
float _springVelocityDecay;
float _springForce;
glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion
AvatarBone _bone[ NUM_AVATAR_BONES ];
AvatarMode _mode;
glm::dvec3 _velocity;
glm::vec3 _thrust;
float _maxArmLength;
Orientation _orientation;
int _numOtherAvatarsInView;
int _driveKeys[MAX_DRIVE_KEYS];
GLUquadric* _sphere;
float _renderYaw;
float _renderPitch; // Pitch from view frustum when this is own head.
//
// Related to getting transmitter UDP data used to animate the avatar hand
//
timeval _transmitterTimer;
float _transmitterHz;
int _transmitterPackets;
AvatarHead _head;
bool _isMine;
glm::vec3 _TEST_bigSpherePosition;
float _TEST_bigSphereRadius;
bool _mousePressed;
float _bodyYawDelta;
bool _usingBodySprings;
glm::vec3 _movedHandOffset;
float _springVelocityDecay;
float _springForce;
glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion
AvatarBone _bone[ NUM_AVATAR_BONES ];
AvatarMode _mode;
AvatarHandHolding _handHolding;
glm::dvec3 _velocity;
glm::vec3 _thrust;
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;
//-----------------------------
// private methods...
//-----------------------------
void initializeSkeleton();
void updateSkeleton();
void initializeBodySprings();
void updateBodySprings( float deltaTime );
void calculateBoneLengths();
void updateBigSphereCollisionTest( float deltaTime );
void readSensors();
void renderBoneAsBlock( AvatarBoneID b );
void updateAvatarCollisionDetectionAndResponse
(
glm::vec3 collisionPosition,
float collisionGirth,
float collisionHeight,
glm::vec3 collisionUpVector,
float deltaTime
);
};
#endif

View file

@ -46,6 +46,7 @@ Cloud::Cloud(int num,
void Cloud::render() {
float particleAttenuationQuadratic[] = { 0.0f, 0.0f, 2.0f };
float particleAttenuationConstant[] = { 1.0f, 0.0f, 0.0f };
glEnable( GL_TEXTURE_2D );
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
@ -73,6 +74,10 @@ void Cloud::render() {
glEnd();
glDisable( GL_POINT_SPRITE_ARB );
glDisable( GL_TEXTURE_2D );
glPointParameterfvARB( GL_POINT_DISTANCE_ATTENUATION_ARB, particleAttenuationConstant );
glPointParameterfARB( GL_POINT_SIZE_MAX_ARB, 1.0f );
glPointParameterfARB( GL_POINT_SIZE_MIN_ARB, 0.0f );
}
void Cloud::simulate (float deltaTime) {

View file

@ -55,7 +55,7 @@ class Log {
public:
explicit Log(FILE* tPipeTo = stdout, unsigned bufferedLines = 1024,
unsigned defaultLogWidth = 240, unsigned defaultCharWidth = 6, unsigned defaultCharHeight = 20);
unsigned defaultLogWidth = 400, unsigned defaultCharWidth = 6, unsigned defaultCharHeight = 20);
~Log();
void setLogWidth(unsigned pixels);

View file

@ -34,7 +34,17 @@ float Stars::changeLOD(float fraction, float overalloc, float realloc) {
return float(_ptrController->changeLOD(fraction, overalloc, realloc));
}
void Stars::render(float fovDiagonal, float aspect, glm::mat4 const& view) {
void Stars::render(float fovY, float aspect, float nearZ) {
// determine length of screen diagonal from quadrant height and aspect ratio
float quadrantHeight = nearZ * tan(angleConvert<Degrees,Radians>(fovY) * 0.5f);
float halfDiagonal = sqrt(quadrantHeight * quadrantHeight * (1.0f + aspect * aspect));
// determine fov angle in respect to the diagonal
float fovDiagonal = atan(halfDiagonal / nearZ) * 2.0f;
// pull the modelview matrix off the GL stack
glm::mat4 view; glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(view));
_ptrController->render(fovDiagonal, aspect, glm::affineInverse(view));
}

View file

@ -13,9 +13,9 @@
namespace starfield { class Controller; }
/**
* Starfield rendering component.
*/
//
// Starfield rendering component.
//
class Stars {
starfield::Controller* _ptrController;
@ -25,49 +25,49 @@ class Stars {
Stars();
~Stars();
/**
* Reads input file from URL. Returns true upon success.
*
* The limit parameter allows to reduce the number of stars
* that are loaded, keeping the brightest ones.
*/
//
// Reads input file from URL. Returns true upon success.
//
// The limit parameter allows to reduce the number of stars
// that are loaded, keeping the brightest ones.
//
bool readInput(const char* url, const char* cacheFile = 0l, unsigned limit = 200000);
/**
* Renders the starfield from a local viewer's perspective.
* The parameter specifies the field of view.
*/
void render(float fovDiagonal, float aspect, glm::mat4 const& view);
//
// Renders the starfield from a local viewer's perspective.
// The parameters specifiy the field of view.
//
void render(float fovY, float aspect, float nearZ);
/**
* Sets the resolution for FOV culling.
*
* The parameter determines the number of tiles in azimuthal
* and altitudinal directions.
*
* GPU resources are updated upon change in which case 'true'
* is returned.
*/
//
// Sets the resolution for FOV culling.
//
// The parameter determines the number of tiles in azimuthal
// and altitudinal directions.
//
// GPU resources are updated upon change in which case 'true'
// is returned.
//
bool setResolution(unsigned k);
/**
* Allows to alter the number of stars to be rendered given a
* factor. The least brightest ones are omitted first.
*
* The further parameters determine when GPU resources should
* be reallocated. Its value is fractional in respect to the
* last number of stars 'n' that caused 'n * (1+overalloc)' to
* be allocated. When the next call to setLOD causes the total
* number of stars that could be rendered to drop below 'n *
* (1-realloc)' or rises above 'n * (1+realloc)' GPU resources
* are updated. Note that all parameters must be fractions,
* that is within the range [0;1] and that 'overalloc' must be
* greater than or equal to 'realloc'.
*
* The current level of detail is returned as a float in [0;1].
*/
//
// Allows to alter the number of stars to be rendered given a
// factor. The least brightest ones are omitted first.
//
// The further parameters determine when GPU resources should
// be reallocated. Its value is fractional in respect to the
// last number of stars 'n' that caused 'n * (1+overalloc)' to
// be allocated. When the next call to setLOD causes the total
// number of stars that could be rendered to drop below 'n *
// (1-realloc)' or rises above 'n * (1+realloc)' GPU resources
// are updated. Note that all parameters must be fractions,
// that is within the range [0;1] and that 'overalloc' must be
// greater than or equal to 'realloc'.
//
// The current level of detail is returned as a float in [0;1].
//
float changeLOD(float factor,
float overalloc = 0.25, float realloc = 0.15);
float overalloc = 0.25, float realloc = 0.15);
private:
// don't copy/assign

View file

@ -90,6 +90,7 @@ void render_vector(glm::vec3 * vec)
// Draw marker dots for magnitude
glEnd();
float particleAttenuationQuadratic[] = { 0.0f, 0.0f, 2.0f }; // larger Z = smaller particles
float particleAttenuationConstant[] = { 1.0f, 0.0f, 0.0f };
glPointParameterfvARB( GL_POINT_DISTANCE_ATTENUATION_ARB, particleAttenuationQuadratic );
@ -104,6 +105,7 @@ void render_vector(glm::vec3 * vec)
glVertex3f(0,0,vec->z);
glEnd();
glPointParameterfvARB( GL_POINT_DISTANCE_ATTENUATION_ARB, particleAttenuationConstant );
}
void render_world_box()

View file

@ -23,25 +23,27 @@
const int MAX_VOXELS_PER_SYSTEM = 250000;
const int VERTICES_PER_VOXEL = 8;
const int VERTICES_PER_VOXEL = 24;
const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL;
const int INDICES_PER_VOXEL = 3 * 12;
float identityVertices[] = { 0, 0, 0,
1, 0, 0,
1, 1, 0,
0, 1, 0,
0, 0, 1,
1, 0, 1,
1, 1, 1,
0, 1, 1 };
float identityVertices[] = { 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1,
0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1,
0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1 };
GLubyte identityIndices[] = { 0,1,2, 0,2,3,
0,1,5, 0,4,5,
0,3,7, 0,4,7,
1,2,6, 1,5,6,
2,3,7, 2,6,7,
4,5,6, 4,6,7 };
GLfloat identityNormals[] = { 0,0,-1, 0,0,-1, 0,0,-1, 0,0,-1,
0,0,+1, 0,0,+1, 0,0,+1, 0,0,+1,
0,-1,0, 0,-1,0, 0,+1,0, 0,+1,0,
0,-1,0, 0,-1,0, 0,+1,0, 0,+1,0,
-1,0,0, +1,0,0, +1,0,0, -1,0,0,
-1,0,0, +1,0,0, +1,0,0, -1,0,0 };
GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z- .
8,9,13, 8,13,12, // Y-
16,23,19, 16,20,23, // X-
17,18,22, 17,22,21, // X+
10,11,15, 10,15,14, // Y+
4,5,6, 4,6,7 }; // Z+ .
VoxelSystem::VoxelSystem() {
voxelsRendered = 0;
@ -49,7 +51,7 @@ VoxelSystem::VoxelSystem() {
pthread_mutex_init(&bufferWriteLock, NULL);
}
VoxelSystem::~VoxelSystem() {
VoxelSystem::~VoxelSystem() {
delete[] readVerticesArray;
delete[] writeVerticesArray;
delete[] readColorsArray;
@ -58,8 +60,8 @@ VoxelSystem::~VoxelSystem() {
pthread_mutex_destroy(&bufferWriteLock);
}
void VoxelSystem::setViewerHead(Head *newViewerHead) {
viewerHead = newViewerHead;
void VoxelSystem::setViewerAvatar(Avatar *newViewerAvatar) {
viewerAvatar = newViewerAvatar;
}
//////////////////////////////////////////////////////////////////////////////////////////
@ -70,9 +72,9 @@ void VoxelSystem::setViewerHead(Head *newViewerHead) {
// Complaints: Brad :)
// To Do: Need to add color data to the file.
void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) {
tree->loadVoxelsFile(fileName,wantColorRandomizer);
copyWrittenDataToReadArrays();
}
@ -119,7 +121,7 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
unsigned char command = *sourceBuffer;
unsigned char *voxelData = sourceBuffer + 1;
switch(command) {
case PACKET_HEADER_VOXEL_DATA:
{
@ -204,7 +206,7 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
case PACKET_HEADER_Z_COMMAND:
// the Z command is a special command that allows the sender to send high level semantic
// requests, like erase all, or add sphere scene, different receivers may handle these
// requests, like erase all, or add sphere scene, different receivers may handle these
// messages differently
char* packetData = (char *)sourceBuffer;
char* command = &packetData[1]; // start of the command
@ -225,7 +227,7 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
}
break;
}
setupNewVoxelsForDrawing();
return numBytes;
}
@ -258,7 +260,7 @@ int VoxelSystem::treeToArrays(VoxelNode *currentNode, const glm::vec3& nodePosi
int voxelsAdded = 0;
float halfUnitForVoxel = powf(0.5, *currentNode->octalCode) * (0.5 * TREE_SCALE);
glm::vec3 viewerPosition = viewerHead->getBodyPosition();
glm::vec3 viewerPosition = viewerAvatar->getPosition();
// debug LOD code
glm::vec3 debugNodePosition;
@ -285,11 +287,11 @@ int VoxelSystem::treeToArrays(VoxelNode *currentNode, const glm::vec3& nodePosi
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
/**** disabled ************************************************************************************************
// Note: Stephen, I intentionally left this in so you would talk to me about it. Here's the deal, this code
// doesn't seem to work correctly. It returns X and Z flipped and the values are negative. Since we use the
@ -299,7 +301,7 @@ int VoxelSystem::treeToArrays(VoxelNode *currentNode, const glm::vec3& nodePosi
// calculate the child's position based on the parent position
for (int j = 0; j < 3; j++) {
childNodePosition[j] = nodePosition[j];
if (oneAtBit(branchIndexWithDescendant(currentNode->octalCode,currentNode->children[i]->octalCode),(7 - j))) {
childNodePosition[j] -= (powf(0.5, *currentNode->children[i]->octalCode) * TREE_SCALE);
}
@ -316,13 +318,13 @@ int VoxelSystem::treeToArrays(VoxelNode *currentNode, const glm::vec3& nodePosi
float startVertex[3];
copyFirstVertexForCode(currentNode->octalCode,(float*)&startVertex);
float voxelScale = 1 / powf(2, *currentNode->octalCode);
// populate the array with points for the 8 vertices
// and RGB color for each added vertex
for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) {
*writeVerticesEndPointer = startVertex[j % 3] + (identityVertices[j] * voxelScale);
*(writeColorsArray + (writeVerticesEndPointer - writeVerticesArray)) = currentNode->getColor()[j % 3];
writeVerticesEndPointer++;
}
voxelsAdded++;
@ -344,7 +346,7 @@ void VoxelSystem::init() {
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++) {
@ -352,84 +354,107 @@ void VoxelSystem::init() {
int voxelIndexOffset = n * INDICES_PER_VOXEL;
GLuint *currentIndicesPos = indicesArray + voxelIndexOffset;
int startIndex = (n * VERTICES_PER_VOXEL);
for (int i = 0; i < INDICES_PER_VOXEL; i++) {
// add indices for this side of the cube
currentIndicesPos[i] = startIndex + identityIndices[i];
}
}
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++) {
for (int i = 0; i < VERTEX_POINTS_PER_VOXEL; i++) {
*(normalsArrayEndPointer++) = identityNormals[i];
}
}
// VBO for the verticesArray
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);
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);
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);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
INDICES_PER_VOXEL * sizeof(GLuint) * MAX_VOXELS_PER_SYSTEM,
indicesArray, GL_STATIC_DRAW);
// delete the indices array that is no longer needed
// delete the indices and normals arrays that are no longer needed
delete[] indicesArray;
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);
}
}
// 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);
glVertexPointer(3, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vboNormalsID);
glNormalPointer(GL_FLOAT, 0, 0);
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);
glScalef(10, 10, 10);
glDrawElements(GL_TRIANGLES, 36 * voxelsRendered, GL_UNSIGNED_INT, 0);
// deactivate vertex and color arrays after drawing
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
// bind with 0 to switch back to normal operation
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// scale back down to 1 so heads aren't massive
glPopMatrix();
}
void VoxelSystem::simulate(float deltaTime) {
}
int VoxelSystem::_nodeCount = 0;
@ -440,7 +465,7 @@ bool VoxelSystem::randomColorOperation(VoxelNode* node, bool down, void* extraDa
if (down) {
return true;
}
_nodeCount++;
if (node->isColored()) {
nodeColor newColor = { 0,0,0,1 };
@ -471,9 +496,9 @@ bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, bool down, void*
if (down) {
return true;
}
_nodeCount++;
// always false colorize
unsigned char newR = randomColorValue(150);
unsigned char newG = randomColorValue(150);
@ -500,7 +525,7 @@ bool VoxelSystem::trueColorizeOperation(VoxelNode* node, bool down, void* extraD
if (down) {
return true;
}
_nodeCount++;
node->setFalseColored(false);
//printf("setting true color for node %d\n",_nodeCount);
@ -521,23 +546,23 @@ bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, bool down, void*
if (down) {
return true;
}
ViewFrustum* viewFrustum = (ViewFrustum*) extraData;
_nodeCount++;
// only do this for truely colored voxels...
if (node->isColored()) {
// first calculate the AAbox for the voxel
AABox voxelBox;
node->getAABox(voxelBox);
voxelBox.scale(TREE_SCALE);
printf("voxelBox corner=(%f,%f,%f) x=%f\n",
voxelBox.getCorner().x, voxelBox.getCorner().y, voxelBox.getCorner().z,
voxelBox.getSize().x);
// If the voxel is outside of the view frustum, then false color it red
if (ViewFrustum::OUTSIDE == viewFrustum->boxInFrustum(voxelBox)) {
// Out of view voxels are colored RED
@ -554,7 +579,7 @@ bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, bool down, void*
} else {
printf("voxel not colored, don't consider it\n");
}
return true; // keep going!
}
@ -576,7 +601,7 @@ bool VoxelSystem::falseColorizeDistanceFromViewOperation(VoxelNode* node, bool d
}
ViewFrustum* viewFrustum = (ViewFrustum*) extraData;
// only do this for truly colored voxels...
if (node->isColored()) {
@ -590,10 +615,10 @@ bool VoxelSystem::falseColorizeDistanceFromViewOperation(VoxelNode* node, bool d
// scale up the node position
nodePosition = nodePosition*(float)TREE_SCALE;
float halfUnitForVoxel = powf(0.5, *node->octalCode) * (0.5 * TREE_SCALE);
glm::vec3 viewerPosition = viewFrustum->getPosition();
//printf("halfUnitForVoxel=%f\n",halfUnitForVoxel);
//printf("viewer.x=%f y=%f z=%f \n", viewerPosition.x, viewerPosition.y, viewerPosition.z);
//printf("node.x=%f y=%f z=%f \n", nodePosition.x, nodePosition.y, nodePosition.z);
@ -606,7 +631,7 @@ bool VoxelSystem::falseColorizeDistanceFromViewOperation(VoxelNode* node, bool d
_nodeCount++;
float distanceRatio = (_minDistance==_maxDistance) ? 1 : (distance - _minDistance)/(_maxDistance - _minDistance);
// We want to colorize this in 16 bug chunks of color
const unsigned char maxColor = 255;
const unsigned char colorBands = 16;
@ -615,7 +640,7 @@ bool VoxelSystem::falseColorizeDistanceFromViewOperation(VoxelNode* node, bool d
unsigned char newR = (colorBand*(gradientOver/colorBands))+(maxColor-gradientOver);
unsigned char newG = 0;
unsigned char newB = 0;
//printf("Setting color down=%s distance=%f min=%f max=%f distanceRatio=%f color=%d \n",
//printf("Setting color down=%s distance=%f min=%f max=%f distanceRatio=%f color=%d \n",
// (down ? "TRUE" : "FALSE"), distance, _minDistance, _maxDistance, distanceRatio, (int)newR);
node->setFalseColor(newR,newG,newB);
@ -641,7 +666,7 @@ bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, bool down,
//printf("getDistanceFromViewRangeOperation() down=%s\n",(down ? "TRUE" : "FALSE"));
ViewFrustum* viewFrustum = (ViewFrustum*) extraData;
// only do this for truly colored voxels...
if (node->isColored()) {
@ -687,7 +712,7 @@ void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) {
printf("determining distance range for %d nodes\n",_nodeCount);
_nodeCount = 0;
tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum);
printf("setting in distance false color for %d nodes\n",_nodeCount);
setupNewVoxelsForDrawing();

View file

@ -15,7 +15,7 @@
#include <AgentData.h>
#include <VoxelTree.h>
#include <ViewFrustum.h>
#include "Head.h"
#include "Avatar.h"
#include "Util.h"
#include "world.h"
@ -25,16 +25,16 @@ class VoxelSystem : public AgentData {
public:
VoxelSystem();
~VoxelSystem();
int parseData(unsigned char* sourceBuffer, int numBytes);
VoxelSystem* clone() const;
void init();
void simulate(float deltaTime);
void render();
void setVoxelsRendered(int v) {voxelsRendered = v;};
int getVoxelsRendered() {return voxelsRendered;};
void setViewerHead(Head *newViewerHead);
void setViewerAvatar(Avatar *newViewerAvatar);
void loadVoxelsFile(const char* fileName,bool wantColorRandomizer);
void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer);
@ -67,7 +67,7 @@ private:
static float _minDistance;
int voxelsRendered;
Head *viewerHead;
Avatar *viewerAvatar;
VoxelTree *tree;
GLfloat *readVerticesArray;
GLubyte *readColorsArray;
@ -76,6 +76,7 @@ private:
GLubyte *writeColorsArray;
GLfloat *writeVerticesEndPointer;
GLuint vboVerticesID;
GLuint vboNormalsID;
GLuint vboColorsID;
GLuint vboIndicesID;
pthread_mutex_t bufferWriteLock;

View file

@ -64,7 +64,7 @@
#include "MenuColumn.h"
#include "Menu.h"
#include "Camera.h"
#include "Head.h"
#include "Avatar.h"
#include "Particle.h"
#include "Texture.h"
#include "Cloud.h"
@ -107,7 +107,7 @@ Oscilloscope audioScope(256,200,true);
ViewFrustum viewFrustum; // current state of view frustum, perspective, orientation, etc.
Head myAvatar(true); // The rendered avatar of oneself
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
@ -157,11 +157,15 @@ VoxelDetail paintingVoxel; // The voxel we're painting if we're paintin
unsigned char dominantColor = 0; // The dominant color of the voxel we're painting
bool perfStatsOn = false; // Do we want to display perfStats?
bool logOn = true; // Whether to show on-screen log
int noiseOn = 0; // Whether to add random noise
float noise = 1.0; // Overall magnitude scaling for random noise levels
bool gyroLook = false; // Whether to allow the gyro data from head to move your view
int displayLevels = 0;
bool lookingInMirror = 0; // Are we currently rendering one's own head as if in mirror?
bool lookingInMirror = 0; // Are we currently rendering one's own head as if in mirror?
int displayField = 0;
int displayHeadMouse = 1; // Display sample mouse pointer controlled by head movement
@ -304,7 +308,7 @@ void displayStats(void)
char legend2[] = "* - toggle stars, & - toggle paint mode, '-' - send erase all, '%' - send add scene";
drawtext(10, statsVerticalOffset + 32, 0.10f, 0, 1.0, 0, legend2);
glm::vec3 avatarPos = myAvatar.getBodyPosition();
glm::vec3 avatarPos = myAvatar.getPosition();
char stats[200];
sprintf(stats, "FPS = %3.0f Pkts/s = %d Bytes/s = %d Head(x,y,z)= %4.2f, %4.2f, %4.2f ",
@ -380,7 +384,7 @@ void initDisplay(void)
void init(void)
{
voxels.init();
voxels.setViewerHead(&myAvatar);
voxels.setViewerAvatar(&myAvatar);
myAvatar.setRenderYaw(startYaw);
initializeHandController();
@ -396,8 +400,8 @@ void init(void)
if (noiseOn) {
myAvatar.setNoise(noise);
}
myAvatar.setBodyPosition(start_location);
myCamera.setPosition( start_location );
myAvatar.setPosition(start_location);
myCamera.setPosition(start_location);
#ifdef MARKER_CAPTURE
@ -438,7 +442,7 @@ void reset_sensors()
renderYawRate = 0;
renderPitchRate = 0;
myAvatar.setBodyPosition(start_location);
myAvatar.setPosition(start_location);
headMouseX = WIDTH/2;
headMouseY = HEIGHT/2;
@ -476,31 +480,16 @@ void updateAvatar(float frametime)
headMouseY = min(headMouseY, HEIGHT);
// Update render direction (pitch/yaw) based on measured gyro rates
const int MIN_YAW_RATE = 100;
const int MIN_PITCH_RATE = 100;
const float YAW_SENSITIVITY = 0.02;
const float PITCH_SENSITIVITY = 0.05;
const float MIN_YAW_RATE = 5;
const float YAW_SENSITIVITY = 1.0;
// Update render pitch and yaw rates based on keyPositions
const float KEY_YAW_SENSITIVITY = 2.0;
if (myAvatar.getDriveKeys(ROT_LEFT)) renderYawRate -= KEY_YAW_SENSITIVITY*frametime;
if (myAvatar.getDriveKeys(ROT_RIGHT)) renderYawRate += KEY_YAW_SENSITIVITY*frametime;
// If enabled, Update render pitch and yaw based on gyro data
if (::gyroLook) {
if (fabs(gyroYawRate) > MIN_YAW_RATE) {
myAvatar.addBodyYaw(-gyroYawRate * YAW_SENSITIVITY * frametime);
}
}
if (fabs(gyroYawRate) > MIN_YAW_RATE)
{
if (gyroYawRate > 0)
renderYawRate += (gyroYawRate - MIN_YAW_RATE) * YAW_SENSITIVITY * frametime;
else
renderYawRate += (gyroYawRate + MIN_YAW_RATE) * YAW_SENSITIVITY * frametime;
}
if (fabs(gyroPitchRate) > MIN_PITCH_RATE)
{
if (gyroPitchRate > 0)
renderPitchRate += (gyroPitchRate - MIN_PITCH_RATE) * PITCH_SENSITIVITY * frametime;
else
renderPitchRate += (gyroPitchRate + MIN_PITCH_RATE) * PITCH_SENSITIVITY * frametime;
}
float renderPitch = myAvatar.getRenderPitch();
// Decay renderPitch toward zero because we never look constantly up/down
renderPitch *= (1.f - 2.0*frametime);
@ -514,11 +503,8 @@ void updateAvatar(float frametime)
myAvatar.setRenderPitch(renderPitch + renderPitchRate);
// Get audio loudness data from audio input device
float loudness, averageLoudness;
#ifndef _WIN32
audio.getInputLoudness(&loudness, &averageLoudness);
myAvatar.setLoudness(loudness);
myAvatar.setAverageLoudness(averageLoudness);
myAvatar.setLoudness(audio.getInputLoudness());
#endif
// Update Avatar with latest camera and view frustum data...
@ -551,7 +537,7 @@ void updateAvatar(float frametime)
// If I'm in paint mode, send a voxel out to VOXEL server agents.
if (::paintOn) {
glm::vec3 avatarPos = myAvatar.getBodyPosition();
glm::vec3 avatarPos = myAvatar.getPosition();
// For some reason, we don't want to flip X and Z here.
::paintingVoxel.x = avatarPos.x/10.0;
@ -833,7 +819,7 @@ void display(void)
//----------------------------------------------------
// set the camera to third-person view behind my av
//----------------------------------------------------
myCamera.setTargetPosition ( myAvatar.getBodyPosition() );
myCamera.setTargetPosition ( myAvatar.getPosition() );
myCamera.setYaw ( 180.0 - myAvatar.getBodyYaw() );
myCamera.setPitch ( 0.0 ); // temporarily, this must be 0.0 or else bad juju
myCamera.setRoll ( 0.0 );
@ -878,9 +864,10 @@ void display(void)
if (::starsOn) {
// should be the first rendering pass - w/o depth buffer / lighting
glm::mat4 view;
glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(view));
stars.render(angleConvert<Degrees,Radians>(whichCamera.getFieldOfView()), aspectRatio, view);
// finally render the starfield
stars.render(whichCamera.getFieldOfView(), aspectRatio, whichCamera.getNearClip());
}
glEnable(GL_LIGHTING);
@ -927,7 +914,7 @@ void display(void)
agent != agentList->getAgents().end();
agent++) {
if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) {
Head *avatar = (Head *)agent->getLinkedData();
Avatar *avatar = (Avatar *)agent->getLinkedData();
avatar->render(0);
}
}
@ -935,7 +922,7 @@ void display(void)
if ( !::lookingInMirror ) balls.render();
// Render the world box
if (!::lookingInMirror && statsOn) render_world_box();
if (!::lookingInMirror && ::statsOn) { render_world_box(); }
// brad's frustum for debugging
if (::frustumOn) renderViewFrustum(::viewFrustum);
@ -977,13 +964,12 @@ void display(void)
// Show detected levels from the serial I/O ADC channel sensors
if (displayLevels) serialPort.renderLevels(WIDTH,HEIGHT);
// Display miscellaneous text stats onscreen
if (statsOn) {
glLineWidth(1.0f);
glPointSize(1.0f);
displayStats();
logger.render(WIDTH, HEIGHT);
}
// Display stats and log text onscreen
glLineWidth(1.0f);
glPointSize(1.0f);
if (::statsOn) { displayStats(); }
if (::logOn) { logger.render(WIDTH, HEIGHT); }
// Show menu
if (::menuOn) {
@ -1072,6 +1058,16 @@ int setNoise(int state) {
return iRet;
}
int setLog(int state) {
int iRet = setValue(state, &::logOn);
return iRet;
}
int setGyroLook(int state) {
int iRet = setValue(state, &::gyroLook);
return iRet;
}
int setVoxels(int state) {
return setValue(state, &::showingVoxels);
}
@ -1081,7 +1077,7 @@ int setStars(int state) {
}
int setStats(int state) {
return setValue(state, &statsOn);
return setValue(state, &::statsOn);
}
int setMenu(int state) {
@ -1190,19 +1186,24 @@ const char* getFrustumRenderModeName(int state) {
}
void initMenu() {
MenuColumn *menuColumnOptions, *menuColumnTools, *menuColumnDebug, *menuColumnFrustum;
MenuColumn *menuColumnOptions, *menuColumnRender, *menuColumnTools, *menuColumnDebug, *menuColumnFrustum;
// Options
menuColumnOptions = menu.addColumn("Options");
menuColumnOptions->addRow("Mirror (h)", setHead);
menuColumnOptions->addRow("Field (f)", setField);
menuColumnOptions->addRow("(N)oise", setNoise);
menuColumnOptions->addRow("(V)oxels", setVoxels);
menuColumnOptions->addRow("Stars (*)", setStars);
menuColumnOptions->addRow("(Q)uit", quitApp);
menuColumnOptions->addRow("Noise (n)", setNoise);
menuColumnOptions->addRow("Gyro Look", setGyroLook);
menuColumnOptions->addRow("Quit (q)", quitApp);
// Render
menuColumnRender = menu.addColumn("Render");
menuColumnRender->addRow("Voxels (V)", setVoxels);
menuColumnRender->addRow("Stars (*)", setStars);
menuColumnRender->addRow("Field (f)", setField);
// Tools
menuColumnTools = menu.addColumn("Tools");
menuColumnTools->addRow("Stats (/)", setStats);
menuColumnTools->addRow("Stats (/)", setStats);
menuColumnTools->addRow("Log ", setLog);
menuColumnTools->addRow("(M)enu", setMenu);
// Frustum Options
@ -1265,7 +1266,7 @@ void shiftPaintingColor()
}
void setupPaintingVoxel() {
glm::vec3 avatarPos = myAvatar.getBodyPosition();
glm::vec3 avatarPos = myAvatar.getPosition();
::paintingVoxel.x = avatarPos.z/-10.0; // voxel space x is negative z head space
::paintingVoxel.y = avatarPos.y/-10.0; // voxel space y is negative y head space
@ -1360,7 +1361,7 @@ void key(unsigned char k, int x, int y)
// Process keypresses
if (k == 'q' || k == 'Q') ::terminate();
if (k == '/') statsOn = !statsOn; // toggle stats
if (k == '/') ::statsOn = !::statsOn; // toggle stats
if (k == '*') ::starsOn = !::starsOn; // toggle stars
if (k == 'V' || k == 'v') ::showingVoxels = !::showingVoxels; // toggle voxels
if (k == 'F') ::frustumOn = !::frustumOn; // toggle view frustum debugging
@ -1494,13 +1495,13 @@ void idle(void) {
//
updateAvatar(deltaTime);
//loop through all the other avatars and simulate them.
//loop through all the other avatars and simulate them...
AgentList * agentList = AgentList::getInstance();
for(std::vector<Agent>::iterator agent = agentList->getAgents().begin(); agent != agentList->getAgents().end(); agent++)
{
if (agent->getLinkedData() != NULL)
{
Head *avatar = (Head *)agent->getLinkedData();
Avatar *avatar = (Avatar *)agent->getLinkedData();
avatar->simulate(deltaTime);
}
}
@ -1512,7 +1513,6 @@ void idle(void) {
glutPostRedisplay();
lastTimeIdle = check;
}
// Read serial data
@ -1612,7 +1612,7 @@ void mouseoverFunc( int x, int y)
void attachNewHeadToAgent(Agent *newAgent) {
if (newAgent->getLinkedData() == NULL) {
newAgent->setLinkedData(new Head(false));
newAgent->setLinkedData(new Avatar(false));
}
}

View file

@ -130,17 +130,18 @@ namespace starfield {
float halfPersp = perspective * 0.5f;
// determine dimensions based on a sought screen diagonal
//
// ww + hh = dd
// a = h / w => h = wa
// ww + ww aa = dd
// ww = dd / (1 + aa)
float diag = 2.0f * std::sin(halfPersp);
// define diagonal and near distance
float halfDiag = std::sin(halfPersp);
float nearClip = std::cos(halfPersp);
float hw = 0.5f * sqrt(diag * diag / (1.0f + aspect * aspect));
float hh = hw * aspect;
// determine half dimensions based on the screen diagonal
//
// ww + hh = dd
// a = w / h => w = ha
// hh + hh aa = dd
// hh = dd / (1 + aa)
float hh = sqrt(halfDiag * halfDiag / (1.0f + aspect * aspect));
float hw = hh * aspect;
// cancel all translation
mat4 matrix = orientation;
@ -154,6 +155,9 @@ namespace starfield {
float azimuth = atan2(ahead.x,-ahead.z) + Radians::pi();
float altitude = atan2(-ahead.y, hypotf(ahead.x, ahead.z));
angleHorizontalPolar<Radians>(azimuth, altitude);
float const eps = 0.002f;
altitude = glm::clamp(altitude,
-Radians::halfPi() + eps, Radians::halfPi() - eps);
#if STARFIELD_HEMISPHERE_ONLY
altitude = std::max(0.0f, altitude);
#endif
@ -162,24 +166,25 @@ namespace starfield {
// printLog("Stars.cpp: starting on tile #%d\n", tileIndex);
#if STARFIELD_DEBUG_CULLING
mat4 matrix_debug = glm::translate(
glm::frustum(-hw, hw, -hh, hh, nearClip, 10.0f),
vec3(0.0f, 0.0f, -4.0f)) * glm::affineInverse(matrix);
mat4 matrix_debug = glm::translate(glm::frustum(-hw, hw, -hh, hh, nearClip, 10.0f),
vec3(0.0f, 0.0f, -4.0f)) *
glm::affineInverse(matrix);
#endif
matrix = glm::frustum(-hw,hw, -hh,hh, nearClip,10.0f)
* glm::affineInverse(matrix);
matrix = glm::frustum(-hw,hw, -hh,hh, nearClip,10.0f) * glm::affineInverse(matrix);
this->_itrOutIndex = (unsigned*) _arrBatchOffs;
this->_vecWxform = vec3(row(matrix, 3));
this->_valHalfPersp = halfPersp;
this->_valMinBright = minBright;
floodFill(_arrTile + tileIndex, TileSelection(*this,
_arrTile, _arrTile + _objTiling.getTileCount(),
(Tile**) _arrBatchCount));
TileSelection::Cursor cursor;
cursor.current = _arrTile + _objTiling.getTileIndex(azimuth, altitude);
cursor.firstInRow = _arrTile + _objTiling.getTileIndex(0.0f, altitude);
floodFill(cursor, TileSelection(*this, _arrTile, _arrTile + _objTiling.getTileCount(),
(TileSelection::Cursor*) _arrBatchCount));
#if STARFIELD_DEBUG_CULLING
# define matrix matrix_debug
@ -269,31 +274,35 @@ namespace starfield {
class TileSelection {
public:
struct Cursor { Tile* current, * firstInRow; };
private:
Renderer& _refRenderer;
Tile** const _arrStack;
Tile** _itrStack;
Cursor* const _arrStack;
Cursor* _itrStack;
Tile const* const _arrTile;
Tile const* const _itrTilesEnd;
Tile const* const _ptrTilesEnd;
public:
TileSelection(Renderer& renderer, Tile const* tiles,
Tile const* tiles_end, Tile** stack) :
Tile const* tiles_end, Cursor* stack) :
_refRenderer(renderer),
_arrStack(stack),
_itrStack(stack),
_arrTile(tiles),
_itrTilesEnd(tiles_end) {
_ptrTilesEnd(tiles_end) {
}
protected:
// flood fill strategy
bool select(Tile* t) {
bool select(Cursor const& c) {
Tile* t = c.current;
if (t < _arrTile || t >= _itrTilesEnd ||
if (t < _arrTile || t >= _ptrTilesEnd ||
!! (t->flags & Tile::checked)) {
// out of bounds or been here already
@ -311,7 +320,8 @@ namespace starfield {
return false;
}
bool process(Tile* t) {
bool process(Cursor const& c) {
Tile* t = c.current;
if (! (t->flags & Tile::visited)) {
@ -321,14 +331,39 @@ namespace starfield {
return false;
}
void right(Tile*& cursor) const { cursor += 1; }
void left(Tile*& cursor) const { cursor -= 1; }
void up(Tile*& cursor) const { cursor += yStride(); }
void down(Tile*& cursor) const { cursor -= yStride(); }
void right(Cursor& c) const {
void defer(Tile* t) { *_itrStack++ = t; }
c.current += 1;
if (c.current == c.firstInRow + _refRenderer._objTiling.getAzimuthalTiles()) {
c.current = c.firstInRow;
}
}
void left(Cursor& c) const {
if (c.current == c.firstInRow) {
c.current = c.firstInRow + _refRenderer._objTiling.getAzimuthalTiles();
}
c.current -= 1;
}
void up(Cursor& c) const {
bool deferred(Tile*& cursor) {
unsigned d = _refRenderer._objTiling.getAzimuthalTiles();
c.current += d;
c.firstInRow += d;
}
void down(Cursor& c) const {
unsigned d = _refRenderer._objTiling.getAzimuthalTiles();
c.current -= d;
c.firstInRow -= d;
}
void defer(Cursor const& t) {
*_itrStack++ = t;
}
bool deferred(Cursor& cursor) {
if (_itrStack != _arrStack) {
cursor = *--_itrStack;
@ -336,12 +371,6 @@ namespace starfield {
}
return false;
}
private:
unsigned yStride() const {
return _refRenderer._objTiling.getAzimuthalTiles();
}
};
bool visitTile(Tile* t) {
@ -362,6 +391,7 @@ namespace starfield {
bool tileVisible(Tile* t, unsigned i) {
float slice = _objTiling.getSliceAngle();
float halfSlice = 0.5f * slice;
unsigned stride = _objTiling.getAzimuthalTiles();
float azimuth = (i % stride) * slice;
float altitude = (i / stride) * slice - Radians::halfPi();
@ -371,14 +401,13 @@ namespace starfield {
vec3 tileCenter = vec3(gx * exz, sin(altitude), gz * exz);
float w = dot(_vecWxform, tileCenter);
float halfSlice = 0.5f * slice;
float daz = halfSlice * cos(abs(altitude) - halfSlice);
float daz = halfSlice * cos(std::max(0.0f, abs(altitude) - halfSlice));
float dal = halfSlice;
float adjustedNear = cos(_valHalfPersp + sqrt(daz * daz + dal * dal));
// printLog("Stars.cpp: checking tile #%d, w = %f, near = %f\n", i, w, nearClip);
return w > adjustedNear;
return w >= adjustedNear;
}
void updateVertexCount(Tile* t, BrightnessLevel minBright) {

View file

@ -1,5 +1,5 @@
//
// starfield/renderer/
// starfield/renderer/Tiling.h
// interface
//
// Created by Tobias Schwinger on 3/22/13.
@ -51,6 +51,7 @@ namespace starfield {
private:
unsigned discreteAngle(float unsigned_angle) const {
return unsigned(floor(unsigned_angle * _valRcpSlice + 0.5f));
}

View file

@ -69,7 +69,7 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
// and return the number of bytes to push the pointer
// Body world position
memcpy(destinationBuffer, &_bodyPosition, sizeof(float) * 3);
memcpy(destinationBuffer, &_position, sizeof(float) * 3);
destinationBuffer += sizeof(float) * 3;
// Body rotation (NOTE: This needs to become a quaternion to save two bytes)
@ -125,7 +125,7 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
unsigned char* startPosition = sourceBuffer;
// Body world position
memcpy(&_bodyPosition, sourceBuffer, sizeof(float) * 3);
memcpy(&_position, sourceBuffer, sizeof(float) * 3);
sourceBuffer += sizeof(float) * 3;
// Body rotation (NOTE: This needs to become a quaternion to save two bytes)
@ -171,14 +171,14 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
return sourceBuffer - startPosition;
}
glm::vec3 AvatarData::getBodyPosition() {
return glm::vec3(_bodyPosition.x,
_bodyPosition.y,
_bodyPosition.z);
glm::vec3 AvatarData::getPosition() {
return glm::vec3(_position.x,
_position.y,
_position.z);
}
void AvatarData::setBodyPosition(glm::vec3 bodyPosition) {
_bodyPosition = bodyPosition;
void AvatarData::setPosition(glm::vec3 position) {
_position = position;
}
void AvatarData::setHandPosition(glm::vec3 handPosition) {

View file

@ -20,8 +20,8 @@ public:
AvatarData* clone() const;
glm::vec3 getBodyPosition();
void setBodyPosition(glm::vec3 bodyPosition);
glm::vec3 getPosition();
void setPosition(glm::vec3 position);
void setHandPosition(glm::vec3 handPosition);
int getBroadcastData(unsigned char* destinationBuffer);
@ -39,20 +39,20 @@ public:
void setHeadPitch(float p) {_headPitch = p; }
void setHeadYaw(float y) {_headYaw = y; }
void setHeadRoll(float r) {_headRoll = r; };
const float getHeadPitch() const { return _headPitch; };
const float getHeadYaw() const { return _headYaw; };
const float getHeadRoll() const { return _headRoll; };
float getHeadPitch() const { return _headPitch; };
float getHeadYaw() const { return _headYaw; };
float getHeadRoll() const { return _headRoll; };
void addHeadPitch(float p) {_headPitch -= p; }
void addHeadYaw(float y){_headYaw -= y; }
void addHeadRoll(float r){_headRoll += r; }
// Hand State
void setHandState(char s) { _handState = s; };
const float getHandState() const {return _handState; };
char getHandState() const {return _handState; };
// Instantaneous audio loudness to drive mouth/facial animation
void setLoudness(float l) { _audioLoudness = l; };
const float getLoudness() const {return _audioLoudness; };
float getLoudness() const {return _audioLoudness; };
// getters for camera details
const glm::vec3& getCameraPosition() const { return _cameraPosition; };
@ -75,7 +75,7 @@ public:
void setCameraFarClip(float farClip) { _cameraFarClip = farClip; }
protected:
glm::vec3 _bodyPosition;
glm::vec3 _position;
glm::vec3 _handPosition;
// Body rotation

View file

@ -261,30 +261,19 @@ float Agent::getAverageKilobitsPerSecond() {
}
void Agent::printLog(Agent const& agent) {
sockaddr_in *agentPublicSocket = (sockaddr_in *) agent.publicSocket;
sockaddr_in *agentLocalSocket = (sockaddr_in *) agent.localSocket;
const char* publicAddressString = (agentPublicSocket == NULL)
? "Unknown"
: inet_ntoa(agentPublicSocket->sin_addr);
unsigned short publicAddressPort = (agentPublicSocket == NULL)
? 0
: ntohs(agentPublicSocket->sin_port);
char publicAddressBuffer[16] = {'\0'};
unsigned short publicAddressPort = loadBufferWithSocketInfo(publicAddressBuffer, agent.publicSocket);
char localAddressBuffer[16] = {'\0'};
unsigned short localAddressPort = loadBufferWithSocketInfo(localAddressBuffer, agent.localSocket);
const char* localAddressString = (agentLocalSocket == NULL)
? "Unknown"
: inet_ntoa(agentLocalSocket->sin_addr);
unsigned short localAddressPort = (agentLocalSocket == NULL)
? 0
: ntohs(agentPublicSocket->sin_port);
::printLog("ID: %d T: %s (%c) PA: %s:%d LA: %s:%d\n",
agent.agentId,
agent.getTypeName(),
agent.type,
publicAddressString,
publicAddressBuffer,
publicAddressPort,
localAddressString,
localAddressBuffer,
localAddressPort);
}

View file

@ -24,7 +24,7 @@
using shared_lib::printLog;
const char SOLO_AGENT_TYPES_STRING[] = {
const char SOLO_AGENT_TYPES[3] = {
AGENT_TYPE_AVATAR_MIXER,
AGENT_TYPE_AUDIO_MIXER,
AGENT_TYPE_VOXEL
@ -305,8 +305,8 @@ void AgentList::handlePingReply(sockaddr *agentAddress) {
}
}
Agent* AgentList::soloAgentOfType(char agentType) {
if (memchr(SOLO_AGENT_TYPES_STRING, agentType, 1)) {
Agent* AgentList::soloAgentOfType(char agentType) {
if (memchr(SOLO_AGENT_TYPES, agentType, sizeof(SOLO_AGENT_TYPES)) != NULL) {
for(std::vector<Agent>::iterator agent = agents.begin(); agent != agents.end(); agent++) {
if (agent->getType() == agentType) {
return &*agent;
@ -428,7 +428,7 @@ void *checkInWithDomainServer(void *args) {
sockaddr_in tempAddress;
memcpy(&tempAddress.sin_addr, pHostInfo->h_addr_list[0], pHostInfo->h_length);
strcpy(DOMAIN_IP, inet_ntoa(tempAddress.sin_addr));
printLog("Domain server: %s \n", DOMAIN_HOSTNAME);
printLog("Domain server: %s - %s\n", DOMAIN_HOSTNAME, DOMAIN_IP);
} else {
printLog("Failed lookup domainserver\n");

View file

@ -22,7 +22,7 @@
const int MAX_PACKET_SIZE = 1500;
const unsigned int AGENT_SOCKET_LISTEN_PORT = 40103;
const int AGENT_SILENCE_THRESHOLD_USECS = 2 * 1000000;
extern const char SOLO_AGENT_TYPES_STRING[];
extern const char SOLO_AGENT_TYPES[3];
extern char DOMAIN_HOSTNAME[];
extern char DOMAIN_IP[100]; // IP Address will be re-set by lookup on startup

View file

@ -0,0 +1,103 @@
//
// AudioInjector.cpp
// hifi
//
// Created by Stephen Birarda on 4/23/13.
//
//
#include <sys/time.h>
#include <fstream>
#include <cstring>
#include "SharedUtil.h"
#include "PacketHeaders.h"
#include "AudioInjector.h"
const int BUFFER_LENGTH_BYTES = 512;
const int BUFFER_LENGTH_SAMPLES = BUFFER_LENGTH_BYTES / sizeof(int16_t);
const float SAMPLE_RATE = 22050.0f;
const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES / SAMPLE_RATE) * 1000000;
AudioInjector::AudioInjector(const char* filename) :
_numTotalBytesAudio(0),
_bearing(0),
_attenuationModifier(255)
{
_position[0] = 0.0f;
_position[1] = 0.0f;
_position[2] = 0.0f;
std::fstream sourceFile;
sourceFile.open(filename, std::ios::in | std::ios::binary);
sourceFile.seekg(0, std::ios::end);
_numTotalBytesAudio = sourceFile.tellg();
if (_numTotalBytesAudio == -1) {
printf("Error reading audio data from file %s\n", filename);
_audioSampleArray = NULL;
} else {
printf("Read %d bytes from audio file\n", _numTotalBytesAudio);
sourceFile.seekg(0, std::ios::beg);
long sizeOfShortArray = _numTotalBytesAudio / 2;
_audioSampleArray = new int16_t[sizeOfShortArray];
sourceFile.read((char *)_audioSampleArray, _numTotalBytesAudio);
}
}
AudioInjector::~AudioInjector() {
delete[] _audioSampleArray;
}
void AudioInjector::setPosition(float* position) {
_position[0] = position[0];
_position[1] = position[1];
_position[2] = position[2];
}
void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destinationSocket) const {
if (_audioSampleArray != NULL) {
timeval startTime;
// one byte for header, 3 positional floats, 1 bearing float, 1 attenuation modifier byte
int leadingBytes = 1 + (sizeof(float) * 4) + 1;
unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes];
dataPacket[0] = PACKET_HEADER_INJECT_AUDIO;
unsigned char *currentPacketPtr = dataPacket + 1;
for (int i = 0; i < 3; i++) {
memcpy(currentPacketPtr, &_position[i], sizeof(float));
currentPacketPtr += sizeof(float);
}
*currentPacketPtr = _attenuationModifier;
currentPacketPtr++;
memcpy(currentPacketPtr, &_bearing, sizeof(float));
currentPacketPtr += sizeof(float);
for (int i = 0; i < _numTotalBytesAudio; i += BUFFER_LENGTH_BYTES) {
gettimeofday(&startTime, NULL);
int numBytesToCopy = BUFFER_LENGTH_BYTES;
if (_numTotalBytesAudio - i < BUFFER_LENGTH_BYTES) {
numBytesToCopy = _numTotalBytesAudio - i;
memset(currentPacketPtr + numBytesToCopy, 0, BUFFER_LENGTH_BYTES - numBytesToCopy);
}
memcpy(currentPacketPtr, _audioSampleArray + (i / 2), numBytesToCopy);
injectorSocket->send(destinationSocket, dataPacket, sizeof(dataPacket));
double usecToSleep = BUFFER_SEND_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&startTime));
if (usecToSleep > 0) {
usleep(usecToSleep);
}
}
}
}

View file

@ -0,0 +1,35 @@
//
// AudioInjector.h
// hifi
//
// Created by Stephen Birarda on 4/23/13.
//
//
#ifndef __hifi__AudioInjector__
#define __hifi__AudioInjector__
#include <iostream>
#include <netinet/in.h>
#include "UDPSocket.h"
class AudioInjector {
public:
AudioInjector(const char* filename);
~AudioInjector();
void setPosition(float* position);
void setBearing(float bearing) { _bearing = bearing; }
void setAttenuationModifier(unsigned char attenuationModifier) { _attenuationModifier = attenuationModifier; }
void injectAudio(UDPSocket* injectorSocket, sockaddr* destinationSocket) const;
private:
int16_t* _audioSampleArray;
int _numTotalBytesAudio;
float _position[3];
float _bearing;
unsigned char _attenuationModifier;
};
#endif /* defined(__hifi__AudioInjector__) */

View file

@ -9,32 +9,31 @@
#ifndef __hifi__FloodFill__
#define __hifi__FloodFill__
/**
* Line scanning, iterative flood fill algorithm.
*
* The strategy must obey the following contract:
*
* There is an associated cursor that represents a position on the image.
* The member functions 'left(C&)', 'right(C&)', 'up(C&)', and 'down(C&)'
* move it.
* The state of a cursor can be deferred to temporary storage (typically a
* stack or a queue) using the 'defer(C const&)' member function.
* Calling 'deferred(C&)' restores a cursor's state from temporary storage
* and removes it there.
* The 'select(C const&)' and 'process(C const&)' functions control the
* algorithm. The former is called to determine where to go. It may be
* called multiple times but does not have to (and should not) return
* 'true' more than once for a pixel to be selected (will cause memory
* overuse, otherwise). The latter will never be called for a given pixel
* unless previously selected. It may be called multiple times, in which
* case it should return 'true' upon successful processing and 'false'
* when an already processed pixel has been visited.
*
* Note: The terms "image" and "pixel" are used for illustratory purposes
* and mean "undirected graph with 4-connected 2D grid topology" and "node",
* respectively.
*
*/
//
// Line scanning, iterative flood fill algorithm.
//
// The strategy must obey the following contract:
//
// There is an associated cursor that represents a position on the image.
// The member functions 'left(C&)', 'right(C&)', 'up(C&)', and 'down(C&)'
// move it.
// The state of a cursor can be deferred to temporary storage (typically a
// stack or a queue) using the 'defer(C const&)' member function.
// Calling 'deferred(C&)' restores a cursor's state from temporary storage
// and removes it there.
// The 'select(C const&)' and 'process(C const&)' functions control the
// algorithm. The former is called to determine where to go. It may be
// called multiple times but does not have to (and should not) return
// 'true' more than once for a pixel to be selected (will cause memory
// overuse, otherwise). The latter will never be called for a given pixel
// unless previously selected. It may be called multiple times, in which
// case it should return 'true' upon successful processing and 'false'
// when an already processed pixel has been visited.
//
// Note: The terms "image" and "pixel" are used for illustratory purposes
// and mean "undirected graph with 4-connected 2D grid topology" and "node",
// respectively.
//
template< class Strategy, typename Cursor >
void floodFill(Cursor const& position,
Strategy const& strategy = Strategy());
@ -63,57 +62,39 @@ struct floodFill_impl : Strategy {
}
Cursor higher, lower, h,l, i;
bool higherFound, lowerFound, hf, lf;
do {
if (! process(position)) {
continue;
}
higher = position; higherFound = false;
up(higher); yTest(higher, higherFound);
lower = position; lowerFound = false;
down(lower); yTest(lower, lowerFound);
higher = position;
up(higher);
if (select(higher)) { defer(higher); }
lower = position;
down(lower);
if (select(lower)) { defer(lower); }
i = position, h = higher, l = lower;
hf = higherFound, lf = lowerFound;
do {
right(i), right(h), right(l); yTest(h,hf); yTest(l,lf);
} while (selectAndProcess(i));
right(i), right(h), right(l);
if (select(h)) { defer(h); }
if (select(l)) { defer(l); }
} while (select(i) && process(i));
i = position, h = higher, l = lower;
hf = higherFound, lf = lowerFound;
do {
left(i); left(h); left(l); yTest(h,hf); yTest(l,lf);
left(i); left(h); left(l);
if (select(h)) { defer(h); }
if (select(l)) { defer(l); }
} while (selectAndProcess(i));
} while (select(i) && process(i));
} while (deferred(position));
}
bool selectAndProcess(Cursor const& i) {
if (select(i)) {
process(i);
return true;
}
return false;
}
void yTest(Cursor const& i, bool& state) {
if (! select(i)) {
state = false;
} else if (! state) {
state = true;
defer(i);
}
}
};
template< class Strategy, typename Cursor >

View file

@ -107,6 +107,18 @@ int getLocalAddress() {
return localAddress;
}
unsigned short loadBufferWithSocketInfo(char *addressBuffer, sockaddr *socket) {
if (socket != NULL) {
char *copyBuffer = inet_ntoa(((sockaddr_in*) socket)->sin_addr);
memcpy(addressBuffer, copyBuffer, strlen(copyBuffer));
return htons(((sockaddr_in*) socket)->sin_port);
} else {
const char* unknownAddress = "Unknown";
memcpy(addressBuffer, unknownAddress, strlen(unknownAddress));
return 0;
}
}
UDPSocket::UDPSocket(int listeningPort) {
init();
// create the socket

View file

@ -36,5 +36,6 @@ int packSocket(unsigned char *packStore, in_addr_t inAddress, in_port_t networkO
int packSocket(unsigned char *packStore, sockaddr *socketToPack);
int unpackSocket(unsigned char *packedData, sockaddr *unpackDestSocket);
int getLocalAddress();
unsigned short loadBufferWithSocketInfo(char *addressBuffer, sockaddr *socket);
#endif /* defined(__interface__UDPSocket__) */

View file

@ -19,7 +19,7 @@ VoxelAgentData::~VoxelAgentData() {
}
VoxelAgentData::VoxelAgentData(const VoxelAgentData &otherAgentData) {
memcpy(&_bodyPosition, &otherAgentData._bodyPosition, sizeof(_bodyPosition));
memcpy(&_position, &otherAgentData._position, sizeof(_position));
rootMarkerNode = new MarkerNode();
}

View file

@ -199,7 +199,7 @@ void *distributeVoxelsToListeners(void *args) {
stopOctal = randomTree.loadBitstreamBuffer(voxelPacketEnd,
randomTree.rootNode,
agentData->rootMarkerNode,
agentData->getBodyPosition(),
agentData->getPosition(),
treeRoot,
viewFrustum,
::viewFrustumCulling,