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

Conflicts:
	interface/src/Application.h
	interface/src/Audio.h
	interface/src/Webcam.cpp
This commit is contained in:
Andrzej Kapolka 2013-07-18 18:09:57 -07:00
commit b5a8c2710c
77 changed files with 1659 additions and 827 deletions

View file

@ -14,7 +14,7 @@ include_glm(${TARGET_NAME} ${ROOT_DIR})
include(${MACRO_DIR}/SetupHifiProject.cmake)
setup_hifi_project(${TARGET_NAME})
setup_hifi_project(${TARGET_NAME} TRUE)
# link in the shared library
include(${MACRO_DIR}/LinkHifiLibrary.cmake)

View file

@ -9,7 +9,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake
set(TARGET_NAME audio-mixer)
include(${MACRO_DIR}/SetupHifiProject.cmake)
setup_hifi_project(${TARGET_NAME})
setup_hifi_project(${TARGET_NAME} TRUE)
# set up the external glm library
include(${MACRO_DIR}/IncludeGLM.cmake)

View file

@ -10,7 +10,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake
# setup the project
include(${MACRO_DIR}/SetupHifiProject.cmake)
setup_hifi_project(${TARGET_NAME})
setup_hifi_project(${TARGET_NAME} TRUE)
# include glm
include(${MACRO_DIR}/IncludeGLM.cmake)

View file

@ -1,9 +1,15 @@
MACRO(SETUP_HIFI_LIBRARY TARGET)
project(${TARGET_NAME})
project(${TARGET})
# grab the implemenation and header files
file(GLOB LIB_SRCS src/*.h src/*.cpp)
# create a library and set the property so it can be referenced later
add_library(${TARGET_NAME} ${LIB_SRCS})
add_library(${TARGET} ${LIB_SRCS})
find_package(Qt4 REQUIRED QtCore)
include(${QT_USE_FILE})
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${QT_QTGUI_INCLUDE_DIR}")
target_link_libraries(${TARGET} ${QT_LIBRARIES})
ENDMACRO(SETUP_HIFI_LIBRARY _target)

View file

@ -1,4 +1,4 @@
MACRO(SETUP_HIFI_PROJECT TARGET)
MACRO(SETUP_HIFI_PROJECT TARGET INCLUDE_QT)
project(${TARGET})
# grab the implemenation and header files
@ -6,4 +6,12 @@ MACRO(SETUP_HIFI_PROJECT TARGET)
# add the executable
add_executable(${TARGET} ${TARGET_SRCS})
ENDMACRO(SETUP_HIFI_PROJECT _target)
IF (${INCLUDE_QT})
find_package(Qt4 REQUIRED QtCore)
include(${QT_USE_FILE})
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${QT_QTGUI_INCLUDE_DIR}")
ENDIF()
target_link_libraries(${TARGET} ${QT_LIBRARIES})
ENDMACRO(SETUP_HIFI_PROJECT _target _include_qt)

View file

@ -6,7 +6,7 @@ set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
set(TARGET_NAME domain-server)
include(${MACRO_DIR}/SetupHifiProject.cmake)
setup_hifi_project(${TARGET_NAME})
setup_hifi_project(${TARGET_NAME} TRUE)
# link the shared hifi library
include(${MACRO_DIR}/LinkHifiLibrary.cmake)

View file

@ -9,7 +9,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake
set(TARGET_NAME eve)
include(${MACRO_DIR}/SetupHifiProject.cmake)
setup_hifi_project(${TARGET_NAME})
setup_hifi_project(${TARGET_NAME} TRUE)
include(${MACRO_DIR}/IncludeGLM.cmake)
include_glm(${TARGET_NAME} ${ROOT_DIR})

View file

@ -9,7 +9,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake
set(TARGET_NAME injector)
include(${MACRO_DIR}/SetupHifiProject.cmake)
setup_hifi_project(${TARGET_NAME})
setup_hifi_project(${TARGET_NAME} TRUE)
# set up the external glm library
include(${MACRO_DIR}/IncludeGLM.cmake)

View file

@ -70,10 +70,10 @@
using namespace std;
// Starfield information
static char STAR_FILE[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt";
static char STAR_FILE[] = "http://s3-us-west-1.amazonaws.com/highfidelity/stars.txt";
static char STAR_CACHE_FILE[] = "cachedStars.txt";
static const bool TESTING_PARTICLE_SYSTEM = false;
static const bool TESTING_PARTICLE_SYSTEM = true;
static const int BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH = 6; // farther dragged clicks are ignored
@ -164,6 +164,11 @@ void GLCanvas::wheelEvent(QWheelEvent* event) {
Application::getInstance()->wheelEvent(event);
}
void messageHandler(QtMsgType type, const char* message) {
fprintf(stdout, "%s", message);
LogDisplay::instance.addMessage(message);
}
Application::Application(int& argc, char** argv, timeval &startup_time) :
QApplication(argc, argv),
_window(new QMainWindow(desktop())),
@ -173,6 +178,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
_frameCount(0),
_fps(120.0f),
_justStarted(true),
_particleSystemInitialized(false),
_coolDemoParticleEmitter(-1),
_wantToKillLocalVoxels(false),
_frustumDrawingMode(FRUSTUM_DRAW_MODE_ALL),
_viewFrustumOffsetYaw(-135.0),
@ -188,6 +195,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
_isTouchPressed(false),
_yawFromTouch(0.0f),
_pitchFromTouch(0.0f),
_groundPlaneImpact(0.0f),
_mousePressed(false),
_mouseVoxelScale(1.0f / 1024.0f),
_justEditedVoxel(false),
@ -210,7 +218,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
{
_applicationStartupTime = startup_time;
_window->setWindowTitle("Interface");
printLog("Interface Startup:\n");
qInstallMsgHandler(messageHandler);
unsigned int listenPort = 0; // bind to an ephemeral port by default
const char** constArgv = const_cast<const char**>(argv);
@ -233,7 +242,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
// Handle Local Domain testing with the --local command line
if (cmdOptionExists(argc, constArgv, "--local")) {
printLog("Local Domain MODE!\n");
qDebug("Local Domain MODE!\n");
NodeList::getInstance()->setDomainIPToLocalhost();
}
@ -297,7 +306,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
}
void Application::initializeGL() {
printLog( "Created Display Window.\n" );
qDebug( "Created Display Window.\n" );
// initialize glut for shape drawing; Qt apparently initializes it on OS X
#ifndef __APPLE__
@ -312,10 +321,10 @@ void Application::initializeGL() {
_viewFrustumOffsetCamera.setFarClip(500.0 * TREE_SCALE);
initDisplay();
printLog( "Initialized Display.\n" );
qDebug( "Initialized Display.\n" );
init();
printLog( "Init() complete.\n" );
qDebug( "Init() complete.\n" );
// Check to see if the user passed in a command line option for randomizing colors
bool wantColorRandomizer = !arguments().contains("--NoColorRandomizer");
@ -324,13 +333,13 @@ void Application::initializeGL() {
// Voxel File. If so, load it now.
if (!_voxelsFilename.isEmpty()) {
_voxels.loadVoxelsFile(_voxelsFilename.constData(), wantColorRandomizer);
printLog("Local Voxel File loaded.\n");
qDebug("Local Voxel File loaded.\n");
}
// create thread for receipt of data via UDP
if (_enableNetworkThread) {
pthread_create(&_networkReceiveThread, NULL, networkReceive, NULL);
printLog("Network receive thread created.\n");
qDebug("Network receive thread created.\n");
}
// call terminate before exiting
@ -352,7 +361,7 @@ void Application::initializeGL() {
_justStarted = false;
char title[50];
sprintf(title, "Interface: %4.2f seconds\n", startupTime);
printLog("%s", title);
qDebug("%s", title);
_window->setWindowTitle(title);
const char LOGSTASH_INTERFACE_START_TIME_KEY[] = "interface-start-time";
@ -1177,25 +1186,20 @@ void Application::editPreferences() {
return;
}
const char* newHostname = domainServerHostname->text().toLocal8Bit().data();
char newHostname[MAX_HOSTNAME_BYTES] = {};
memcpy(newHostname, domainServerHostname->text().toAscii().data(), domainServerHostname->text().size());
// check if the domain server hostname is new
if (memcmp(NodeList::getInstance()->getDomainHostname(), newHostname, sizeof(&newHostname)) != 0) {
// if so we need to clear the nodelist and delete the local voxels
Node *voxelServer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_VOXEL_SERVER);
if (voxelServer) {
voxelServer->lock();
}
_voxels.killLocalVoxels();
if (voxelServer) {
voxelServer->unlock();
}
if (memcmp(NodeList::getInstance()->getDomainHostname(), newHostname, strlen(newHostname)) != 0) {
NodeList::getInstance()->clear();
// kill the local voxels
_voxels.killLocalVoxels();
// reset the environment to default
_environment.resetToDefault();
NodeList::getInstance()->setDomainHostname(newHostname);
}
@ -1456,12 +1460,12 @@ bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) {
uint64_t elapsed = now - args->lastSendTime;
int usecToSleep = CLIENT_TO_SERVER_VOXEL_SEND_INTERVAL_USECS - elapsed;
if (usecToSleep > 0) {
printLog("sendVoxelsOperation: packet: %d bytes:%ld elapsed %ld usecs, sleeping for %d usecs!\n",
args->packetsSent, args->bytesSent, elapsed, usecToSleep);
qDebug("sendVoxelsOperation: packet: %d bytes:%lld elapsed %lld usecs, sleeping for %d usecs!\n",
args->packetsSent, args->bytesSent, elapsed, usecToSleep);
usleep(usecToSleep);
} else {
printLog("sendVoxelsOperation: packet: %d bytes:%ld elapsed %ld usecs, no need to sleep!\n",
args->packetsSent, args->bytesSent, elapsed);
qDebug("sendVoxelsOperation: packet: %d bytes:%lld elapsed %lld usecs, no need to sleep!\n",
args->packetsSent, args->bytesSent, elapsed);
}
args->lastSendTime = now;
}
@ -1505,7 +1509,7 @@ void Application::importVoxelsToClipboard() {
if (fileNameString.endsWith(".png", Qt::CaseInsensitive)) {
QImage pngImage = QImage(fileName);
if (pngImage.height() != pngImage.width()) {
printLog("ERROR: Bad PNG size: height != width.\n");
qDebug("ERROR: Bad PNG size: height != width.\n");
return;
}
@ -1539,7 +1543,7 @@ void Application::importVoxels() {
if (fileNameString.endsWith(".png", Qt::CaseInsensitive)) {
QImage pngImage = QImage(fileName);
if (pngImage.height() != pngImage.width()) {
printLog("ERROR: Bad PNG size: height != width.\n");
qDebug("ERROR: Bad PNG size: height != width.\n");
return;
}
@ -1644,9 +1648,9 @@ void Application::pasteVoxels() {
// If we have voxels left in the packet, then send the packet
if (args.bufferInUse > (numBytesPacketHeader + sizeof(unsigned short int))) {
controlledBroadcastToNodes(args.messageBuffer, args.bufferInUse, & NODE_TYPE_VOXEL_SERVER, 1);
printLog("sending packet: %d\n", ++args.packetsSent);
qDebug("sending packet: %d\n", ++args.packetsSent);
args.bytesSent += args.bufferInUse;
printLog("total bytes sent: %ld\n", args.bytesSent);
qDebug("total bytes sent: %lld\n", args.bytesSent);
}
if (calculatedOctCode) {
@ -1713,8 +1717,8 @@ void Application::initMenu() {
"First Person", this, SLOT(setRenderFirstPerson(bool)), Qt::Key_P))->setCheckable(true);
(_manualThirdPerson = renderMenu->addAction(
"Third Person", this, SLOT(setRenderThirdPerson(bool))))->setCheckable(true);
renderMenu->addAction("Increase Avatar Size", this, SLOT(increaseAvatarSize()), Qt::SHIFT | Qt::Key_Plus);
renderMenu->addAction("Decrease Avatar Size", this, SLOT(decreaseAvatarSize()), Qt::SHIFT | Qt::Key_Minus);
renderMenu->addAction("Increase Avatar Size", this, SLOT(increaseAvatarSize()), Qt::ALT | Qt::Key_Plus);
renderMenu->addAction("Decrease Avatar Size", this, SLOT(decreaseAvatarSize()), Qt::ALT | Qt::Key_Minus);
QMenu* toolsMenu = menuBar->addMenu("Tools");
@ -1894,7 +1898,7 @@ void Application::init() {
_audio.setJitterBufferSamples(_audioJitterBufferSamples);
}
printLog("Loaded settings.\n");
qDebug("Loaded settings.\n");
sendAvatarVoxelURLMessage(_myAvatar.getVoxels()->getVoxelURL());
@ -1904,9 +1908,10 @@ void Application::init() {
_palette.addTool(&_swatch);
_palette.addAction(_colorVoxelMode, 0, 2);
_palette.addAction(_eyedropperMode, 0, 3);
_palette.addAction(_selectVoxelMode, 0, 4);
_palette.addAction(_selectVoxelMode, 0, 4);
}
const float MAX_AVATAR_EDIT_VELOCITY = 1.0f;
const float MAX_VOXEL_EDIT_DISTANCE = 20.0f;
const float HEAD_SPHERE_RADIUS = 0.07;
@ -2071,6 +2076,7 @@ void Application::update(float deltaTime) {
// Leap finger-sensing device
LeapManager::enableFakeFingers(_simulateLeapHand->isChecked() || _testRaveGlove->isChecked());
LeapManager::nextFrame();
_myAvatar.getHand().setRaveGloveActive(_testRaveGlove->isChecked());
_myAvatar.getHand().setLeapFingers(LeapManager::getFingerTips(), LeapManager::getFingerRoots());
_myAvatar.getHand().setLeapHands(LeapManager::getHandPositions(), LeapManager::getHandNormals());
@ -2118,6 +2124,8 @@ void Application::update(float deltaTime) {
_myAvatar.simulate(deltaTime, NULL);
}
_myAvatar.getHand().simulate(deltaTime, true);
if (!OculusManager::isConnected()) {
if (_lookingInMirror->isChecked()) {
if (_myCamera.getMode() != CAMERA_MODE_MIRROR) {
@ -2166,8 +2174,8 @@ void Application::update(float deltaTime) {
#endif
if (TESTING_PARTICLE_SYSTEM) {
_particleSystem.simulate(deltaTime);
}
updateParticleSystem(deltaTime);
}
}
void Application::updateAvatar(float deltaTime) {
@ -2560,7 +2568,7 @@ void Application::displaySide(Camera& whichCamera) {
//draw a grid ground plane....
if (_renderGroundPlaneOn->isChecked()) {
drawGroundPlaneGrid(EDGE_SIZE_GROUND_PLANE);
renderGroundPlaneGrid(EDGE_SIZE_GROUND_PLANE, _audio.getCollisionSoundMagnitude());
}
// Draw voxels
if (_renderVoxels->isChecked()) {
@ -2616,7 +2624,9 @@ void Application::displaySide(Camera& whichCamera) {
}
if (TESTING_PARTICLE_SYSTEM) {
_particleSystem.render();
if (_particleSystemInitialized) {
_particleSystem.render();
}
}
// Render the world box
@ -2636,6 +2646,9 @@ void Application::displayOverlay() {
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
// Display a single screen-size quad to
renderCollisionOverlay(_glWidget->width(), _glWidget->height(), _audio.getCollisionSoundMagnitude());
#ifndef _WIN32
_audio.render(_glWidget->width(), _glWidget->height());
if (_oscilloscopeOn->isChecked()) {
@ -2907,7 +2920,7 @@ glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) {
// render the coverage map on screen
void Application::renderCoverageMapV2() {
//printLog("renderCoverageMap()\n");
//qDebug("renderCoverageMap()\n");
glDisable(GL_LIGHTING);
glLineWidth(2.0);
@ -2952,7 +2965,7 @@ void Application::renderCoverageMapsV2Recursively(CoverageMapV2* map) {
// render the coverage map on screen
void Application::renderCoverageMap() {
//printLog("renderCoverageMap()\n");
//qDebug("renderCoverageMap()\n");
glDisable(GL_LIGHTING);
glLineWidth(2.0);
@ -3283,7 +3296,7 @@ void Application::eyedropperVoxelUnderCursor() {
}
void Application::goHome() {
printLog("Going Home!\n");
qDebug("Going Home!\n");
_myAvatar.setPosition(START_LOCATION);
}
@ -3378,7 +3391,7 @@ void* Application::networkReceive(void* args) {
case PACKET_TYPE_ENVIRONMENT_DATA: {
if (app->_renderVoxels->isChecked()) {
Node* voxelServer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_VOXEL_SERVER);
if (voxelServer) {
if (voxelServer && socketMatch(voxelServer->getActiveSocket(), &senderAddress)) {
voxelServer->lock();
if (app->_incomingPacket[0] == PACKET_TYPE_ENVIRONMENT_DATA) {
@ -3528,3 +3541,68 @@ void Application::exportSettings() {
}
void Application::updateParticleSystem(float deltaTime) {
if (!_particleSystemInitialized) {
// create a stable test emitter and spit out a bunch of particles
_coolDemoParticleEmitter = _particleSystem.addEmitter();
if (_coolDemoParticleEmitter != -1) {
_particleSystem.setShowingEmitter(_coolDemoParticleEmitter, true);
glm::vec3 particleEmitterPosition = glm::vec3(5.0f, 1.0f, 5.0f);
_particleSystem.setEmitterPosition(_coolDemoParticleEmitter, particleEmitterPosition);
glm::vec3 velocity(0.0f, 0.1f, 0.0f);
float lifespan = 100000.0f;
_particleSystem.emitParticlesNow(_coolDemoParticleEmitter, 1500, velocity, lifespan);
}
// signal that the particle system has been initialized
_particleSystemInitialized = true;
} else {
// update the particle system
static float t = 0.0f;
t += deltaTime;
if (_coolDemoParticleEmitter != -1) {
glm::vec3 tilt = glm::vec3
(
30.0f * sinf( t * 0.55f ),
0.0f,
30.0f * cosf( t * 0.75f )
);
_particleSystem.setEmitterRotation(_coolDemoParticleEmitter, glm::quat(glm::radians(tilt)));
ParticleSystem::ParticleAttributes attributes;
attributes.radius = 0.01f;
attributes.color = glm::vec4( 1.0f, 1.0f, 1.0f, 1.0f);
attributes.gravity = 0.0f + 0.05f * sinf( t * 0.52f );
attributes.airFriction = 2.5 + 2.0f * sinf( t * 0.32f );
attributes.jitter = 0.05f + 0.05f * sinf( t * 0.42f );
attributes.emitterAttraction = 0.015f + 0.015f * cosf( t * 0.6f );
attributes.tornadoForce = 0.0f + 0.03f * sinf( t * 0.7f );
attributes.neighborAttraction = 0.1f + 0.1f * cosf( t * 0.8f );
attributes.neighborRepulsion = 0.2f + 0.2f * sinf( t * 0.4f );
attributes.bounce = 1.0f;
attributes.usingCollisionSphere = true;
attributes.collisionSpherePosition = glm::vec3( 5.0f, 0.5f, 5.0f );
attributes.collisionSphereRadius = 0.5f;
if (attributes.gravity < 0.0f) {
attributes.gravity = 0.0f;
}
_particleSystem.setParticleAttributes(_coolDemoParticleEmitter, attributes);
}
_particleSystem.setUpDirection(glm::vec3(0.0f, 1.0f, 0.0f));
_particleSystem.simulate(deltaTime);
}
}

View file

@ -22,8 +22,6 @@
#include <NodeList.h>
#include <PacketHeaders.h>
#include <ViewFrustum.h>
#ifndef _WIN32
#include "Audio.h"
#endif
@ -31,15 +29,18 @@
#include "BandwidthMeter.h"
#include "Camera.h"
#include "Environment.h"
#include "PacketHeaders.h"
#include "ParticleSystem.h"
#include "renderer/GeometryCache.h"
#include "SerialInterface.h"
#include "Stars.h"
#include "Swatch.h"
#include "ToolsPalette.h"
#include "ViewFrustum.h"
#include "VoxelSystem.h"
#include "Webcam.h"
#include "avatar/Avatar.h"
#include "avatar/HandControl.h"
#include "renderer/GeometryCache.h"
#include "ui/BandwidthDialog.h"
#include "ui/ChatEntry.h"
@ -83,7 +84,10 @@ public:
const glm::vec3 getMouseVoxelWorldCoordinates(const VoxelDetail _mouseVoxel);
void updateParticleSystem(float deltaTime);
Avatar* getAvatar() { return &_myAvatar; }
Audio* getAudio() { return &_audio; }
Camera* getCamera() { return &_myCamera; }
ViewFrustum* getViewFrustum() { return &_viewFrustum; }
VoxelSystem* getVoxels() { return &_voxels; }
@ -104,6 +108,9 @@ public slots:
void sendAvatarFaceVideoMessage(int frameCount, const QByteArray& data);
void setGroundPlaneImpact(float groundPlaneImpact) { _groundPlaneImpact = groundPlaneImpact; }
private slots:
void timer();
@ -210,7 +217,7 @@ private:
void deleteVoxelUnderCursor();
void eyedropperVoxelUnderCursor();
void resetSensors();
void setMenuShortcutsEnabled(bool enabled);
void updateCursor();
@ -290,6 +297,8 @@ private:
timeval _timerStart, _timerEnd;
timeval _lastTimeUpdated;
bool _justStarted;
bool _particleSystemInitialized;
int _coolDemoParticleEmitter;
Stars _stars;
@ -348,6 +357,8 @@ private:
float _yawFromTouch;
float _pitchFromTouch;
float _groundPlaneImpact;
VoxelDetail _mouseVoxelDragging;
glm::vec3 _voxelThrust;
bool _mousePressed; // true if mouse has been pressed (clear when finished)

View file

@ -7,24 +7,25 @@
//
#ifndef _WIN32
#include <iostream>
#include <cstring>
#include <fstream>
#include <iostream>
#include <pthread.h>
#include <sys/stat.h>
#include <cstring>
#include <StdDev.h>
#include <UDPSocket.h>
#include <SharedUtil.h>
#include <PacketHeaders.h>
#include <AngleUtil.h>
#include <NodeList.h>
#include <NodeTypes.h>
#include <AngleUtil.h>
#include <PacketHeaders.h>
#include <SharedUtil.h>
#include <StdDev.h>
#include <UDPSocket.h>
#include "Application.h"
#include "Audio.h"
#include "Util.h"
#include "Log.h"
// Uncomment the following definition to test audio device latency by copying output to input
//#define TEST_AUDIO_LOOPBACK
@ -75,9 +76,12 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o
NodeList* nodeList = NodeList::getInstance();
Application* interface = Application::getInstance();
Avatar* interfaceAvatar = interface->getAvatar();
memset(outputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL);
memset(outputRight, 0, PACKET_LENGTH_BYTES_PER_CHANNEL);
// Add Procedural effects to input samples
addProceduralSounds(inputLeft, BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
addProceduralSounds(inputLeft, outputLeft, outputRight, BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
if (nodeList && inputLeft) {
@ -134,12 +138,8 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o
+ leadingBytes);
}
}
memset(outputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL);
memset(outputRight, 0, PACKET_LENGTH_BYTES_PER_CHANNEL);
AudioRingBuffer* ringBuffer = &_ringBuffer;
// if there is anything in the ring buffer, decide what to do:
@ -151,7 +151,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o
// If not enough audio has arrived to start playback, keep waiting
//
#ifdef SHOW_AUDIO_DEBUG
printLog("%i,%i,%i,%i\n",
qDebug("%i,%i,%i,%i\n",
_packetsReceivedThisPlayback,
ringBuffer->diffLastWriteNextOutput(),
PACKET_LENGTH_SAMPLES,
@ -168,7 +168,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o
_packetsReceivedThisPlayback = 0;
_wasStarved = 10; // Frames for which to render the indication that the system was starved.
#ifdef SHOW_AUDIO_DEBUG
printLog("Starved, remaining samples = %d\n",
qDebug("Starved, remaining samples = %d\n",
ringBuffer->diffLastWriteNextOutput());
#endif
@ -179,7 +179,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o
if (!ringBuffer->isStarted()) {
ringBuffer->setStarted(true);
#ifdef SHOW_AUDIO_DEBUG
printLog("starting playback %0.1f msecs delayed, jitter = %d, pkts recvd: %d \n",
qDebug("starting playback %0.1f msecs delayed, jitter = %d, pkts recvd: %d \n",
(usecTimestampNow() - usecTimestamp(&_firstPacketReceivedTime))/1000.0,
_jitterBufferSamples,
_packetsReceivedThisPlayback);
@ -250,11 +250,11 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o
}
}
#ifndef TEST_AUDIO_LOOPBACK
outputLeft[s] = leftSample;
outputRight[s] = rightSample;
outputLeft[s] += leftSample;
outputRight[s] += rightSample;
#else
outputLeft[s] = inputLeft[s];
outputRight[s] = inputLeft[s];
outputLeft[s] += inputLeft[s];
outputRight[s] += inputLeft[s];
#endif
}
ringBuffer->setNextOutput(ringBuffer->getNextOutput() + PACKET_LENGTH_SAMPLES);
@ -299,8 +299,8 @@ int Audio::audioCallback (const void* inputBuffer,
static void outputPortAudioError(PaError error) {
if (error != paNoError) {
printLog("-- portaudio termination error --\n");
printLog("PortAudio error (%d): %s\n", error, Pa_GetErrorText(error));
qDebug("-- portaudio termination error --\n");
qDebug("PortAudio error (%d): %s\n", error, Pa_GetErrorText(error));
}
}
@ -332,7 +332,13 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) :
_lastYawMeasuredMaximum(0),
_flangeIntensity(0.0f),
_flangeRate(0.0f),
_flangeWeight(0.0f)
_flangeWeight(0.0f),
_collisionSoundMagnitude(0.0f),
_collisionSoundFrequency(0.0f),
_collisionSoundNoise(0.0f),
_collisionSoundDuration(0.0f),
_proceduralEffectSample(0),
_heartbeatMagnitude(0.0f)
{
outputPortAudioError(Pa_Initialize());
@ -349,7 +355,7 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) :
outputParameters.device = Pa_GetDefaultOutputDevice();
if (inputParameters.device == -1 || outputParameters.device == -1) {
printLog("Audio: Missing device.\n");
qDebug("Audio: Missing device.\n");
outputPortAudioError(Pa_Terminate());
return;
}
@ -384,12 +390,12 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) :
outputPortAudioError(Pa_StartStream(_stream));
// Uncomment these lines to see the system-reported latency
//printLog("Default low input, output latency (secs): %0.4f, %0.4f\n",
//qDebug("Default low input, output latency (secs): %0.4f, %0.4f\n",
// Pa_GetDeviceInfo(Pa_GetDefaultInputDevice())->defaultLowInputLatency,
// Pa_GetDeviceInfo(Pa_GetDefaultOutputDevice())->defaultLowOutputLatency);
const PaStreamInfo* streamInfo = Pa_GetStreamInfo(_stream);
printLog("Started audio with reported latency msecs In/Out: %.0f, %.0f\n", streamInfo->inputLatency * 1000.f,
qDebug("Started audio with reported latency msecs In/Out: %.0f, %.0f\n", streamInfo->inputLatency * 1000.f,
streamInfo->outputLatency * 1000.f);
gettimeofday(&_lastReceiveTime, NULL);
@ -588,7 +594,10 @@ void Audio::lowPassFilter(int16_t* inputBuffer) {
}
// Take a pointer to the acquired microphone input samples and add procedural sounds
void Audio::addProceduralSounds(int16_t* inputBuffer, int numSamples) {
void Audio::addProceduralSounds(int16_t* inputBuffer,
int16_t* outputLeft,
int16_t* outputRight,
int numSamples) {
const float MAX_AUDIBLE_VELOCITY = 6.0;
const float MIN_AUDIBLE_VELOCITY = 0.1;
const int VOLUME_BASELINE = 400;
@ -597,14 +606,48 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, int numSamples) {
float speed = glm::length(_lastVelocity);
float volume = VOLUME_BASELINE * (1.f - speed / MAX_AUDIBLE_VELOCITY);
int sample;
//
// Travelling noise
//
// Add a noise-modulated sinewave with volume that tapers off with speed increasing
if ((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) {
for (int i = 0; i < numSamples; i++) {
inputBuffer[i] += (int16_t)((sinf((float) i / SOUND_PITCH * speed) * randFloat()) * volume * speed);
inputBuffer[i] += (int16_t)(sinf((float) (_proceduralEffectSample + i) / SOUND_PITCH ) * volume * (1.f + randFloat() * 0.25f) * speed);
}
}
const float COLLISION_SOUND_CUTOFF_LEVEL = 0.01f;
const float COLLISION_SOUND_MAX_VOLUME = 1000.f;
const float UP_MAJOR_FIFTH = powf(1.5f, 4.0f);
const float DOWN_TWO_OCTAVES = 4.f;
const float DOWN_FOUR_OCTAVES = 16.f;
float t;
if (_collisionSoundMagnitude > COLLISION_SOUND_CUTOFF_LEVEL) {
for (int i = 0; i < numSamples; i++) {
t = (float) _proceduralEffectSample + (float) i;
sample = sinf(t * _collisionSoundFrequency) +
sinf(t * _collisionSoundFrequency / DOWN_TWO_OCTAVES) +
sinf(t * _collisionSoundFrequency / DOWN_FOUR_OCTAVES * UP_MAJOR_FIFTH);
sample *= _collisionSoundMagnitude * COLLISION_SOUND_MAX_VOLUME;
inputBuffer[i] += sample;
outputLeft[i] += sample;
outputRight[i] += sample;
_collisionSoundMagnitude *= _collisionSoundDuration;
}
}
_proceduralEffectSample += numSamples;
}
//
// Starts a collision sound. magnitude is 0-1, with 1 the loudest possible sound.
//
void Audio::startCollisionSound(float magnitude, float frequency, float noise, float duration) {
_collisionSoundMagnitude = magnitude;
_collisionSoundFrequency = frequency;
_collisionSoundNoise = noise;
_collisionSoundDuration = duration;
}
// -----------------------------------------------------------
// Accoustic ping (audio system round trip time determination)
// -----------------------------------------------------------
@ -650,7 +693,7 @@ inline void Audio::eventuallySendRecvPing(int16_t* inputLeft, int16_t* outputLef
// As of the next frame, we'll be recoding PING_FRAMES_TO_RECORD from
// the mic (pointless to start now as we can't record unsent audio).
_isSendingEchoPing = false;
printLog("Send audio ping\n");
qDebug("Send audio ping\n");
} else if (_pingFramesToRecord > 0) {
@ -664,7 +707,7 @@ inline void Audio::eventuallySendRecvPing(int16_t* inputLeft, int16_t* outputLef
if (_pingFramesToRecord == 0) {
_pingAnalysisPending = true;
printLog("Received ping echo\n");
qDebug("Received ping echo\n");
}
}
}
@ -688,25 +731,25 @@ inline void Audio::analyzePing() {
// Determine extrema
int botAt = findExtremum(_echoSamplesLeft, PING_SAMPLES_TO_ANALYZE, -1);
if (botAt == -1) {
printLog("Audio Ping: Minimum not found.\n");
qDebug("Audio Ping: Minimum not found.\n");
return;
}
int topAt = findExtremum(_echoSamplesLeft, PING_SAMPLES_TO_ANALYZE, 1);
if (topAt == -1) {
printLog("Audio Ping: Maximum not found.\n");
qDebug("Audio Ping: Maximum not found.\n");
return;
}
// Determine peak amplitude - warn if low
int ampli = (_echoSamplesLeft[topAt] - _echoSamplesLeft[botAt]) / 2;
if (ampli < PING_MIN_AMPLI) {
printLog("Audio Ping unreliable - low amplitude %d.\n", ampli);
qDebug("Audio Ping unreliable - low amplitude %d.\n", ampli);
}
// Determine period - warn if doesn't look like our signal
int halfPeriod = abs(topAt - botAt);
if (abs(halfPeriod-PING_HALF_PERIOD) > PING_MAX_PERIOD_DIFFERENCE) {
printLog("Audio Ping unreliable - peak distance %d vs. %d\n", halfPeriod, PING_HALF_PERIOD);
qDebug("Audio Ping unreliable - peak distance %d vs. %d\n", halfPeriod, PING_HALF_PERIOD);
}
// Ping is sent:
@ -747,7 +790,7 @@ inline void Audio::analyzePing() {
int delay = (botAt + topAt) / 2 + PING_PERIOD;
printLog("\n| Audio Ping results:\n+----- ---- --- - - - - -\n\n"
qDebug("\n| Audio Ping results:\n+----- ---- --- - - - - -\n\n"
"Delay = %d samples (%d ms)\nPeak amplitude = %d\n\n",
delay, (delay * 1000) / int(SAMPLE_RATE), ampli);
}

View file

@ -14,7 +14,6 @@
#include <StdDev.h>
#include "Oscilloscope.h"
#include "avatar/Avatar.h"
static const int NUM_AUDIO_CHANNELS = 2;
@ -43,7 +42,11 @@ public:
int getJitterBufferSamples() { return _jitterBufferSamples; };
void lowPassFilter(int16_t* inputBuffer);
void startCollisionSound(float magnitude, float frequency, float noise, float duration);
float getCollisionSoundMagnitude() { return _collisionSoundMagnitude; };
void ping();
// Call periodically to eventually perform round trip time analysis,
@ -81,7 +84,13 @@ private:
float _flangeIntensity;
float _flangeRate;
float _flangeWeight;
float _collisionSoundMagnitude;
float _collisionSoundFrequency;
float _collisionSoundNoise;
float _collisionSoundDuration;
int _proceduralEffectSample;
float _heartbeatMagnitude;
// Audio callback in class context.
inline void performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* outputRight);
@ -93,7 +102,7 @@ private:
inline void analyzePing();
// Add sounds that we want the user to not hear themselves, by adding on top of mic input signal
void addProceduralSounds(int16_t* inputBuffer, int numSamples);
void addProceduralSounds(int16_t* inputBuffer, int16_t* outputLeft, int16_t* outputRight, int numSamples);
// Audio callback called by portaudio. Calls 'performIO'.

View file

@ -9,7 +9,6 @@
#include "BandwidthMeter.h"
#include "InterfaceConfig.h"
#include "Log.h"
#include "Util.h"
namespace { // .cpp-local

View file

@ -5,9 +5,10 @@
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
#include <glm/gtx/quaternion.hpp>
#include <SharedUtil.h>
#include <VoxelConstants.h>
#include "Log.h"
#include "Camera.h"
#include "Util.h"

View file

@ -47,6 +47,11 @@ void Environment::init() {
_data[getZeroAddress()][0];
}
void Environment::resetToDefault() {
_data.clear();
_data[getZeroAddress()][0];
}
void Environment::renderAtmospheres(Camera& camera) {
// get the lock for the duration of the call
QMutexLocker locker(&_mutex);

View file

@ -24,6 +24,7 @@ class Environment {
public:
void init();
void resetToDefault();
void renderAtmospheres(Camera& camera);
glm::vec3 getGravity (const glm::vec3& position);

View file

@ -15,7 +15,7 @@
#include "Util.h"
using namespace std;
FILE* const LogDisplay::DEFAULT_STREAM = stdout;
FILE* const LogDisplay::DEFAULT_STREAM = 0l;
//
// Singleton constructor
@ -26,9 +26,7 @@ LogDisplay LogDisplay::instance;
// State management
//
LogDisplay::LogDisplay() :
LogDisplay::LogDisplay() :
_textRenderer(SANS_FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT),
_stream(DEFAULT_STREAM),
_chars(0l),
@ -53,8 +51,6 @@ LogDisplay::LogDisplay() :
memset(_lines, 0, LINE_BUFFER_SIZE * sizeof(char*));
setCharacterSize(DEFAULT_CHAR_WIDTH, DEFAULT_CHAR_HEIGHT);
printLog = & printLogHandler;
}
@ -92,32 +88,7 @@ void LogDisplay::setCharacterSize(unsigned width, unsigned height) {
// Logging
//
int LogDisplay::printLogHandler(char const* fmt, ...) {
va_list args;
int n;
char buf[MAX_MESSAGE_LENGTH];
va_start(args,fmt);
// print to buffer
n = vsnprintf(buf, MAX_MESSAGE_LENGTH, fmt, args);
if (n > 0) {
// all fine? log the message
instance.addMessage(buf);
} else {
// error? -> mutter on stream or stderr
fprintf(instance._stream != 0l ? instance._stream : stderr,
"Log: Failed to log message with format string = \"%s\".\n", fmt);
}
va_end(args);
return n;
}
inline void LogDisplay::addMessage(char const* ptr) {
void LogDisplay::addMessage(const char* ptr) {
pthread_mutex_lock(& _mutex);

View file

@ -12,7 +12,6 @@
#include <stdarg.h>
#include <pthread.h>
#include "Log.h"
#include "ui/TextRenderer.h"
class LogDisplay {
@ -21,6 +20,9 @@ public:
static LogDisplay instance;
void render(unsigned screenWidth, unsigned screenHeight);
// log formatted message
void addMessage(const char* message);
// settings
@ -50,12 +52,6 @@ private:
LogDisplay(LogDisplay const&); // = delete;
LogDisplay& operator=(LogDisplay const&); // = delete;
// format and log message - entrypoint used to replace global 'printLog'
static int printLogHandler(char const* fmt, ...);
// log formatted message (called by printLogHandler)
inline void addMessage(char const*);
TextRenderer _textRenderer;
FILE* _stream; // FILE as secondary destination for log messages
char* _chars; // character buffer base address

View file

@ -8,116 +8,217 @@
#include <glm/glm.hpp>
#include "InterfaceConfig.h"
#include <SharedUtil.h>
#include "ParticleSystem.h"
#include "Application.h"
const float DEFAULT_PARTICLE_RADIUS = 0.01f;
const float DEFAULT_PARTICLE_BOUNCE = 1.0f;
const float DEFAULT_PARTICLE_AIR_FRICTION = 2.0f;
ParticleSystem::ParticleSystem() {
_numberOfParticles = 1500;
assert(_numberOfParticles <= MAX_PARTICLES);
_bounce = 0.9f;
_timer = 0.0f;
_airFriction = 6.0f;
_jitter = 0.1f;
_homeAttraction = 0.0f;
_tornadoForce = 0.0f;
_neighborAttraction = 0.02f;
_neighborRepulsion = 0.9f;
_tornadoAxis = glm::normalize(glm::vec3(0.1f, 1.0f, 0.1f));
_home = glm::vec3(5.0f, 1.0f, 5.0f);
_TEST_bigSphereRadius = 0.5f;
_TEST_bigSpherePosition = glm::vec3( 5.0f, _TEST_bigSphereRadius, 5.0f);
_numEmitters = 0;
_numParticles = 0;
_upDirection = glm::vec3(0.0f, 1.0f, 0.0f); // default
for (unsigned int emitterIndex = 0; emitterIndex < MAX_EMITTERS; emitterIndex++) {
_emitter[emitterIndex].position = glm::vec3(0.0f, 0.0f, 0.0f);
_emitter[emitterIndex].rotation = glm::quat();
_emitter[emitterIndex].visible = false;
_emitter[emitterIndex].baseParticle.alive = false;
_emitter[emitterIndex].baseParticle.age = 0.0f;
_emitter[emitterIndex].baseParticle.lifespan = 0.0f;
_emitter[emitterIndex].baseParticle.radius = 0.0f;
_emitter[emitterIndex].baseParticle.emitterIndex = 0;
_emitter[emitterIndex].baseParticle.position = glm::vec3(0.0f, 0.0f, 0.0f);
_emitter[emitterIndex].baseParticle.velocity = glm::vec3(0.0f, 0.0f, 0.0f);
for (int lifeStage = 0; lifeStage<NUM_PARTICLE_LIFE_STAGES; lifeStage++) {
for (unsigned int p = 0; p < _numberOfParticles; p++) {
_particle[p].position = _home;
_particle[p].velocity = glm::vec3(0.0f, 0.0f, 0.0f);
float radian = ((float)p / (float)_numberOfParticles) * PI_TIMES_TWO;
float wave = sinf(radian);
float red = 0.5f + 0.5f * wave;
float green = 0.3f + 0.3f * wave;
float blue = 0.2f - 0.2f * wave;
_particle[p].color = glm::vec3(red, green, blue);
_particle[p].age = 0.0f;
_particle[p].radius = 0.01f;
}
ParticleAttributes * a = &_emitter[emitterIndex].particleAttributes[lifeStage];
a->radius = DEFAULT_PARTICLE_RADIUS;
a->color = glm::vec4(0.0f, 0.0f, 0.0f, 0.0f);
a->bounce = DEFAULT_PARTICLE_BOUNCE;
a->airFriction = DEFAULT_PARTICLE_AIR_FRICTION;
a->gravity = 0.0f;
a->jitter = 0.0f;
a->emitterAttraction = 0.0f;
a->tornadoForce = 0.0f;
a->neighborAttraction = 0.0f;
a->neighborRepulsion = 0.0f;
a->collisionSphereRadius = 0.0f;
a->collisionSpherePosition = glm::vec3(0.0f, 0.0f, 0.0f);
a->usingCollisionSphere = false;
}
};
for (unsigned int p = 0; p < MAX_PARTICLES; p++) {
_particle[p].alive = false;
_particle[p].age = 0.0f;
_particle[p].lifespan = 0.0f;
_particle[p].radius = 0.0f;
_particle[p].emitterIndex = 0;
_particle[p].position = glm::vec3(0.0f, 0.0f, 0.0f);
_particle[p].velocity = glm::vec3(0.0f, 0.0f, 0.0f);
}
}
int ParticleSystem::addEmitter() {
_numEmitters ++;
if (_numEmitters > MAX_EMITTERS) {
return -1;
}
return _numEmitters - 1;
}
void ParticleSystem::simulate(float deltaTime) {
runSpecialEffectsTest(deltaTime);
for (unsigned int p = 0; p < _numberOfParticles; p++) {
updateParticle(p, deltaTime);
// update particles
for (unsigned int p = 0; p < _numParticles; p++) {
if (_particle[p].alive) {
if (_particle[p].age > _particle[p].lifespan) {
killParticle(p);
} else {
updateParticle(p, deltaTime);
}
}
}
}
void ParticleSystem::emitParticlesNow(int e, int num, glm::vec3 velocity, float lifespan) {
void ParticleSystem::runSpecialEffectsTest(float deltaTime) {
_timer += deltaTime;
_gravity = 0.01f + 0.01f * sinf( _timer * 0.52f );
_airFriction = 3.0f + 2.0f * sinf( _timer * 0.32f );
_jitter = 0.05f + 0.05f * sinf( _timer * 0.42f );
_homeAttraction = 0.01f + 0.01f * cosf( _timer * 0.6f );
_tornadoForce = 0.0f + 0.03f * sinf( _timer * 0.7f );
_neighborAttraction = 0.1f + 0.1f * cosf( _timer * 0.8f );
_neighborRepulsion = 0.4f + 0.3f * sinf( _timer * 0.4f );
_tornadoAxis = glm::vec3
(
0.0f + 0.5f * sinf( _timer * 0.55f ),
1.0f,
0.0f + 0.5f * cosf( _timer * 0.75f )
);
for (unsigned int p = 0; p < num; p++) {
createParticle(e, velocity, lifespan);
}
}
void ParticleSystem::createParticle(int e, glm::vec3 velocity, float lifespan) {
for (unsigned int p = 0; p < MAX_PARTICLES; p++) {
if (!_particle[p].alive) {
_particle[p].emitterIndex = e;
_particle[p].lifespan = lifespan;
_particle[p].alive = true;
_particle[p].age = 0.0f;
_particle[p].velocity = velocity;
_particle[p].position = _emitter[e].position;
_particle[p].radius = _emitter[e].particleAttributes[0].radius;
_particle[p].color = _emitter[e].particleAttributes[0].color;
_numParticles ++;
assert(_numParticles <= MAX_PARTICLES);
return;
}
}
}
void ParticleSystem::killParticle(int p) {
assert( p >= 0);
assert( p < MAX_PARTICLES);
assert( _numParticles > 0);
_particle[p].alive = false;
_numParticles --;
}
void ParticleSystem::setParticleAttributes(int emitterIndex, ParticleAttributes attributes) {
for (int lifeStage = 0; lifeStage < NUM_PARTICLE_LIFE_STAGES; lifeStage ++ ) {
setParticleAttributes(emitterIndex, lifeStage, attributes);
}
}
void ParticleSystem::setParticleAttributes(int emitterIndex, int lifeStage, ParticleAttributes attributes) {
ParticleAttributes * a = &_emitter[emitterIndex].particleAttributes[lifeStage];
a->radius = attributes.radius;
a->color = attributes.color;
a->bounce = attributes.bounce;
a->gravity = attributes.gravity;
a->airFriction = attributes.airFriction;
a->jitter = attributes.jitter;
a->emitterAttraction = attributes.emitterAttraction;
a->tornadoForce = attributes.tornadoForce;
a->neighborAttraction = attributes.neighborAttraction;
a->neighborRepulsion = attributes.neighborRepulsion;
a->usingCollisionSphere = attributes.usingCollisionSphere;
a->collisionSpherePosition = attributes.collisionSpherePosition;
a->collisionSphereRadius = attributes.collisionSphereRadius;
}
void ParticleSystem::updateParticle(int p, float deltaTime) {
_particle[p].age += deltaTime;
assert(_particle[p].age <= _particle[p].lifespan);
float ageFraction = _particle[p].age / _particle[p].lifespan;
int lifeStage = (int)( ageFraction * (NUM_PARTICLE_LIFE_STAGES-1) );
float lifeStageFraction = ageFraction * ( NUM_PARTICLE_LIFE_STAGES - 1 ) - lifeStage;
_particle[p].radius
= _emitter[_particle[p].emitterIndex].particleAttributes[lifeStage ].radius * (1.0f - lifeStageFraction)
+ _emitter[_particle[p].emitterIndex].particleAttributes[lifeStage+1].radius * lifeStageFraction;
_particle[p].color
= _emitter[_particle[p].emitterIndex].particleAttributes[lifeStage ].color * (1.0f - lifeStageFraction)
+ _emitter[_particle[p].emitterIndex].particleAttributes[lifeStage+1].color * lifeStageFraction;
Emitter myEmitter = _emitter[_particle[p].emitterIndex];
// apply random jitter
float j = myEmitter.particleAttributes[lifeStage].jitter;
_particle[p].velocity +=
glm::vec3
(
-_jitter * ONE_HALF + _jitter * randFloat(),
-_jitter * ONE_HALF + _jitter * randFloat(),
-_jitter * ONE_HALF + _jitter * randFloat()
-j * ONE_HALF + j * randFloat(),
-j * ONE_HALF + j * randFloat(),
-j * ONE_HALF + j * randFloat()
) * deltaTime;
// apply attraction to home position
glm::vec3 vectorToHome = _home - _particle[p].position;
_particle[p].velocity += vectorToHome * _homeAttraction * deltaTime;
glm::vec3 vectorToHome = myEmitter.position - _particle[p].position;
_particle[p].velocity += vectorToHome * myEmitter.particleAttributes[lifeStage].emitterAttraction * deltaTime;
// apply neighbor attraction
int neighbor = p + 1;
if (neighbor == _numberOfParticles ) {
if (neighbor == _numParticles ) {
neighbor = 0;
}
glm::vec3 vectorToNeighbor = _particle[p].position - _particle[neighbor].position;
_particle[p].velocity -= vectorToNeighbor * _neighborAttraction * deltaTime;
if ( _particle[neighbor].emitterIndex == _particle[p].emitterIndex) {
glm::vec3 vectorToNeighbor = _particle[p].position - _particle[neighbor].position;
_particle[p].velocity -= vectorToNeighbor * myEmitter.particleAttributes[lifeStage].neighborAttraction * deltaTime;
float distanceToNeighbor = glm::length(vectorToNeighbor);
if (distanceToNeighbor > 0.0f) {
_particle[neighbor].velocity += (vectorToNeighbor / ( 1.0f + distanceToNeighbor * distanceToNeighbor)) * _neighborRepulsion * deltaTime;
float distanceToNeighbor = glm::length(vectorToNeighbor);
if (distanceToNeighbor > 0.0f) {
_particle[neighbor].velocity += (vectorToNeighbor / ( 1.0f + distanceToNeighbor * distanceToNeighbor)) * myEmitter.particleAttributes[lifeStage].neighborRepulsion * deltaTime;
}
}
// apply tornado force
glm::vec3 tornadoDirection = glm::cross(vectorToHome, _tornadoAxis);
_particle[p].velocity += tornadoDirection * _tornadoForce * deltaTime;
glm::vec3 emitterUp = myEmitter.rotation * IDENTITY_UP;
glm::vec3 tornadoDirection = glm::cross(vectorToHome, emitterUp);
_particle[p].velocity += tornadoDirection * myEmitter.particleAttributes[lifeStage].tornadoForce * deltaTime;
// apply air friction
float drag = 1.0 - _airFriction * deltaTime;
float drag = 1.0 - myEmitter.particleAttributes[lifeStage].airFriction * deltaTime;
if (drag < 0.0f) {
_particle[p].velocity = glm::vec3(0.0f, 0.0f, 0.0f);
} else {
@ -125,7 +226,7 @@ void ParticleSystem::updateParticle(int p, float deltaTime) {
}
// apply gravity
_particle[p].velocity.y -= _gravity * deltaTime;
_particle[p].velocity -= _upDirection * myEmitter.particleAttributes[lifeStage].gravity * deltaTime;
// update position by velocity
_particle[p].position += _particle[p].velocity;
@ -135,49 +236,149 @@ void ParticleSystem::updateParticle(int p, float deltaTime) {
_particle[p].position.y = _particle[p].radius;
if (_particle[p].velocity.y < 0.0f) {
_particle[p].velocity.y *= -_bounce;
_particle[p].velocity.y *= -myEmitter.particleAttributes[lifeStage].bounce;
}
}
// collision with sphere
glm::vec3 vectorToSphereCenter = _TEST_bigSpherePosition - _particle[p].position;
float distanceToSphereCenter = glm::length(vectorToSphereCenter);
float combinedRadius = _TEST_bigSphereRadius + _particle[p].radius;
if (distanceToSphereCenter < combinedRadius) {
if (distanceToSphereCenter > 0.0f){
glm::vec3 directionToSphereCenter = vectorToSphereCenter / distanceToSphereCenter;
_particle[p].position = _TEST_bigSpherePosition - directionToSphereCenter * combinedRadius;
if (myEmitter.particleAttributes[lifeStage].usingCollisionSphere) {
glm::vec3 vectorToSphereCenter = myEmitter.particleAttributes[lifeStage].collisionSpherePosition - _particle[p].position;
float distanceToSphereCenter = glm::length(vectorToSphereCenter);
float combinedRadius = myEmitter.particleAttributes[lifeStage].collisionSphereRadius + _particle[p].radius;
if (distanceToSphereCenter < combinedRadius) {
if (distanceToSphereCenter > 0.0f){
glm::vec3 directionToSphereCenter = vectorToSphereCenter / distanceToSphereCenter;
_particle[p].position = myEmitter.particleAttributes[lifeStage].collisionSpherePosition - directionToSphereCenter * combinedRadius;
}
}
}
// do this at the end...
_particle[p].age += deltaTime;
}
void ParticleSystem::setEmitterBaseParticle(int emitterIndex, bool showing ) {
_emitter[emitterIndex].baseParticle.alive = true;
_emitter[emitterIndex].baseParticle.emitterIndex = emitterIndex;
}
void ParticleSystem::setEmitterBaseParticle(int emitterIndex, bool showing, float radius, glm::vec4 color ) {
_emitter[emitterIndex].baseParticle.alive = true;
_emitter[emitterIndex].baseParticle.emitterIndex = emitterIndex;
_emitter[emitterIndex].baseParticle.radius = radius;
_emitter[emitterIndex].baseParticle.color = color;
}
void ParticleSystem::render() {
for (unsigned int p = 0; p < _numberOfParticles; p++) {
glColor3f(_particle[p].color.x, _particle[p].color.y, _particle[p].color.z);
// render the emitters
for (int e = 0; e < _numEmitters; e++) {
if (_emitter[e].baseParticle.alive) {
glColor4f(_emitter[e].baseParticle.color.r, _emitter[e].baseParticle.color.g, _emitter[e].baseParticle.color.b, _emitter[e].baseParticle.color.a );
glPushMatrix();
glTranslatef(_emitter[e].position.x, _emitter[e].position.y, _emitter[e].position.z);
glutSolidSphere(_emitter[e].baseParticle.radius, 6, 6);
glPopMatrix();
}
if (_emitter[e].visible) {
renderEmitter(e, 0.2f);
}
};
// render the particles
for (unsigned int p = 0; p < _numParticles; p++) {
if (_particle[p].alive) {
renderParticle(p);
}
}
}
void ParticleSystem::renderParticle(int p) {
glColor4f(_particle[p].color.r, _particle[p].color.g, _particle[p].color.b, _particle[p].color.a );
if (USE_BILLBOARD_RENDERING) {
glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition();
glm::vec3 viewVector = _particle[p].position - cameraPosition;
float distance = glm::length(viewVector);
if (distance >= 0.0f) {
viewVector /= distance;
glm::vec3 up = glm::vec3(viewVector.y, viewVector.z, viewVector.x);
glm::vec3 right = glm::vec3(viewVector.z, viewVector.x, viewVector.y);
glm::vec3 p0 = _particle[p].position - right * _particle[p].radius - up * _particle[p].radius;
glm::vec3 p1 = _particle[p].position + right * _particle[p].radius - up * _particle[p].radius;
glm::vec3 p2 = _particle[p].position + right * _particle[p].radius + up * _particle[p].radius;
glm::vec3 p3 = _particle[p].position - right * _particle[p].radius + up * _particle[p].radius;
glBegin(GL_TRIANGLES);
glVertex3f(p0.x, p0.y, p0.z);
glVertex3f(p1.x, p1.y, p1.z);
glVertex3f(p2.x, p2.y, p2.z);
glEnd();
glBegin(GL_TRIANGLES);
glVertex3f(p0.x, p0.y, p0.z);
glVertex3f(p2.x, p2.y, p2.z);
glVertex3f(p3.x, p3.y, p3.z);
glEnd();
}
} else {
glPushMatrix();
glTranslatef(_particle[p].position.x, _particle[p].position.y, _particle[p].position.z);
glutSolidSphere(_particle[p].radius, 6, 6);
glPopMatrix();
// render velocity lines
glColor4f( _particle[p].color.x, _particle[p].color.y, _particle[p].color.z, 0.5f);
glm::vec3 end = _particle[p].position - _particle[p].velocity * 2.0f;
glBegin(GL_LINES);
glVertex3f(_particle[p].position.x, _particle[p].position.y, _particle[p].position.z);
glVertex3f(end.x, end.y, end.z);
glEnd();
if (SHOW_VELOCITY_TAILS) {
glColor4f( _particle[p].color.x, _particle[p].color.y, _particle[p].color.z, 0.5f);
glm::vec3 end = _particle[p].position - _particle[p].velocity * 2.0f;
glBegin(GL_LINES);
glVertex3f(_particle[p].position.x, _particle[p].position.y, _particle[p].position.z);
glVertex3f(end.x, end.y, end.z);
glEnd();
}
}
}
void ParticleSystem::renderEmitter(int e, float size) {
glm::vec3 r = _emitter[e].rotation * IDENTITY_FRONT * size;
glm::vec3 u = _emitter[e].rotation * IDENTITY_RIGHT * size;
glm::vec3 f = _emitter[e].rotation * IDENTITY_UP * size;
glLineWidth(2.0f);
glColor3f(0.8f, 0.4, 0.4);
glBegin(GL_LINES);
glVertex3f(_emitter[e].position.x, _emitter[e].position.y, _emitter[e].position.z);
glVertex3f(_emitter[e].position.x + r.x, _emitter[e].position.y + r.y, _emitter[e].position.z + r.z);
glEnd();
glColor3f(0.4f, 0.8, 0.4);
glBegin(GL_LINES);
glVertex3f(_emitter[e].position.x, _emitter[e].position.y, _emitter[e].position.z);
glVertex3f(_emitter[e].position.x + u.x, _emitter[e].position.y + u.y, _emitter[e].position.z + u.z);
glEnd();
glColor3f(0.4f, 0.4, 0.8);
glBegin(GL_LINES);
glVertex3f(_emitter[e].position.x, _emitter[e].position.y, _emitter[e].position.z);
glVertex3f(_emitter[e].position.x + f.x, _emitter[e].position.y + f.y, _emitter[e].position.z + f.z);
glEnd();
}

View file

@ -4,56 +4,86 @@
//
// Created by Jeffrey on July 10, 2013
//
//
#ifndef hifi_ParticleSystem_h
#define hifi_ParticleSystem_h
const int MAX_PARTICLES = 5000;
const int MAX_EMITTERS = 10;
#include <glm/gtc/quaternion.hpp>
const int MAX_PARTICLES = 5000;
const int MAX_EMITTERS = 20;
const int NUM_PARTICLE_LIFE_STAGES = 4;
const bool USE_BILLBOARD_RENDERING = false;
const bool SHOW_VELOCITY_TAILS = false;
class ParticleSystem {
public:
struct ParticleAttributes {
float radius;
glm::vec4 color;
float bounce;
float gravity;
float airFriction;
float jitter;
float emitterAttraction;
float tornadoForce;
float neighborAttraction;
float neighborRepulsion;
bool usingCollisionSphere;
glm::vec3 collisionSpherePosition;
float collisionSphereRadius;
};
ParticleSystem();
int addEmitter(); // add (create new) emitter and get its unique id
void emitParticlesNow(int emitterIndex, int numParticles, glm::vec3 velocity, float lifespan);
void simulate(float deltaTime);
void render();
void setUpDirection(glm::vec3 upDirection) {_upDirection = upDirection;} // tell particle system which direction is up
void setEmitterBaseParticle(int emitterIndex, bool showing );
void setEmitterBaseParticle(int emitterIndex, bool showing, float radius, glm::vec4 color );
void setParticleAttributes (int emitterIndex, ParticleAttributes attributes);
void setParticleAttributes (int emitterIndex, int lifeStage, ParticleAttributes attributes);
void setEmitterPosition (int emitterIndex, glm::vec3 position) { _emitter[emitterIndex].position = position; } // set position of emitter
void setEmitterRotation (int emitterIndex, glm::quat rotation) { _emitter[emitterIndex].rotation = rotation; } // set rotation of emitter
void setShowingEmitter (int emitterIndex, bool showing ) { _emitter[emitterIndex].visible = showing; } // set its visibiity
private:
struct Particle {
glm::vec3 position;
glm::vec3 velocity;
glm::vec3 color;
float age;
float radius;
};
struct Emitter {
glm::vec3 position;
glm::vec3 direction;
};
float _bounce;
float _gravity;
float _timer;
Emitter _emitter[MAX_EMITTERS];
Particle _particle[MAX_PARTICLES];
int _numberOfParticles;
glm::vec3 _home;
glm::vec3 _tornadoAxis;
float _airFriction;
float _jitter;
float _homeAttraction;
float _tornadoForce;
float _neighborAttraction;
float _neighborRepulsion;
float _TEST_bigSphereRadius;
glm::vec3 _TEST_bigSpherePosition;
struct Particle {
bool alive; // is the particle active?
glm::vec3 position; // position
glm::vec3 velocity; // velocity
glm::vec4 color; // color (rgba)
float age; // age in seconds
float radius; // radius
float lifespan; // how long this particle stays alive (in seconds)
int emitterIndex; // which emitter created this particle?
};
struct Emitter {
glm::vec3 position;
glm::quat rotation;
bool visible;
Particle baseParticle; // a non-physical particle at the emitter position
ParticleAttributes particleAttributes[NUM_PARTICLE_LIFE_STAGES]; // the attributes of particles emitted from this emitter
};
glm::vec3 _upDirection;
Emitter _emitter[MAX_EMITTERS];
Particle _particle[MAX_PARTICLES];
int _numParticles;
int _numEmitters;
// private methods
void updateParticle(int index, float deltaTime);
void runSpecialEffectsTest(float deltaTime);
void createParticle(int e, glm::vec3 velocity, float lifespan);
void killParticle(int p);
void renderEmitter(int emitterIndex, float size);
void renderParticle(int p);
};
#endif

View file

@ -36,6 +36,28 @@ const int LONG_TERM_RATE_SAMPLES = 1000;
const bool USING_INVENSENSE_MPU9150 = 1;
SerialInterface::SerialInterface() :
_active(false),
_gravity(0, 0, 0),
_averageRotationRates(0, 0, 0),
_averageAcceleration(0, 0, 0),
_estimatedRotation(0, 0, 0),
_estimatedPosition(0, 0, 0),
_estimatedVelocity(0, 0, 0),
_lastAcceleration(0, 0, 0),
_lastRotationRates(0, 0, 0),
_compassMinima(-211, -132, -186),
_compassMaxima(89, 95, 98),
_angularVelocityToLinearAccel(0.003f, -0.001f, -0.006f,
-0.005f, -0.001f, -0.006f,
0.010f, 0.004f, 0.007f),
_angularAccelToLinearAccel(0.0f, 0.0f, 0.002f,
0.0f, 0.0f, 0.001f,
-0.002f, -0.002f, 0.0f)
{
}
void SerialInterface::pair() {
#ifndef _WIN32
@ -75,10 +97,10 @@ void SerialInterface::initializePort(char* portname) {
#ifndef _WIN32
_serialDescriptor = open(portname, O_RDWR | O_NOCTTY | O_NDELAY);
printLog("Opening SerialUSB %s: ", portname);
qDebug("Opening SerialUSB %s: ", portname);
if (_serialDescriptor == -1) {
printLog("Failed.\n");
qDebug("Failed.\n");
return;
}
@ -112,7 +134,7 @@ void SerialInterface::initializePort(char* portname) {
mpu_set_sensors(INV_XYZ_GYRO | INV_XYZ_ACCEL | INV_XYZ_COMPASS);
}
printLog("Connected.\n");
qDebug("Connected.\n");
resetSerial();
_active = true;
@ -351,7 +373,7 @@ void SerialInterface::readData(float deltaTime) {
gettimeofday(&now, NULL);
if (diffclock(&lastGoodRead, &now) > NO_READ_MAXIMUM_MSECS) {
printLog("No data - Shutting down SerialInterface.\n");
qDebug("No data - Shutting down SerialInterface.\n");
resetSerial();
}
} else {

View file

@ -1,17 +1,14 @@
//
// SerialInterface.h
//
// hifi
//
// Created by Stephen Birarda on 2/15/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__SerialInterface__
#define __interface__SerialInterface__
#include <glm/glm.hpp>
#include "Util.h"
#include "world.h"
#include "InterfaceConfig.h"
#include "Log.h"
// These includes are for serial port reading/writing
#ifndef _WIN32
#include <unistd.h>
@ -20,30 +17,16 @@
#include <dirent.h>
#endif
#include <glm/glm.hpp>
#include "InterfaceConfig.h"
#include "Util.h"
extern const bool USING_INVENSENSE_MPU9150;
class SerialInterface {
public:
SerialInterface() : _active(false),
_gravity(0, 0, 0),
_averageRotationRates(0, 0, 0),
_averageAcceleration(0, 0, 0),
_estimatedRotation(0, 0, 0),
_estimatedPosition(0, 0, 0),
_estimatedVelocity(0, 0, 0),
_lastAcceleration(0, 0, 0),
_lastRotationRates(0, 0, 0),
_compassMinima(-211, -132, -186),
_compassMaxima(89, 95, 98),
_angularVelocityToLinearAccel(
0.003f, -0.001f, -0.006f,
-0.005f, -0.001f, -0.006f,
0.010f, 0.004f, 0.007f),
_angularAccelToLinearAccel(
0.0f, 0.0f, 0.002f,
0.0f, 0.0f, 0.001f,
-0.002f, -0.002f, 0.0f)
{}
SerialInterface();
void pair();
void readData(float deltaTime);

View file

@ -13,11 +13,9 @@
#include <PacketHeaders.h>
#include "InterfaceConfig.h"
#include "Log.h"
#include "Transmitter.h"
#include "Util.h"
const float DELTA_TIME = 1.f / 60.f;
const float DECAY_RATE = 0.15f;
@ -40,7 +38,7 @@ void Transmitter::checkForLostTransmitter() {
int msecsSinceLast = diffclock(_lastReceivedPacket, &now);
if (msecsSinceLast > TIME_TO_ASSUME_LOST_MSECS) {
resetLevels();
printLog("Transmitter signal lost.\n");
qDebug("Transmitter signal lost.\n");
}
}
}
@ -95,12 +93,12 @@ void Transmitter::processIncomingData(unsigned char* packetData, int numBytes) {
_estimatedRotation.y *= (1.f - DECAY_RATE * DELTA_TIME);
if (!_isConnected) {
printLog("Transmitter Connected.\n");
qDebug("Transmitter Connected.\n");
_isConnected = true;
_estimatedRotation *= 0.0;
}
} else {
printLog("Transmitter packet read error, %d bytes.\n", numBytes);
qDebug("Transmitter packet read error, %d bytes.\n", numBytes);
}
}

View file

@ -6,7 +6,6 @@
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
//
#include "InterfaceConfig.h"
#include <iostream>
#include <cstring>
#include <time.h>
@ -15,16 +14,16 @@
#include <glm/glm.hpp>
#include <glm/gtc/noise.hpp>
#include <glm/gtx/quaternion.hpp>
#include <AvatarData.h>
#include <SharedUtil.h>
#include "Log.h"
#include "InterfaceConfig.h"
#include "ui/TextRenderer.h"
#include "world.h"
#include "Util.h"
#include "VoxelConstants.h"
#include "world.h"
#include "Util.h"
using namespace std;
@ -326,22 +325,38 @@ void drawvec3(int x, int y, float scale, float rotate, float thick, int mono, gl
glPopMatrix();
}
void renderCollisionOverlay(int width, int height, float magnitude) {
const float MIN_VISIBLE_COLLISION = 0.01f;
if (magnitude > MIN_VISIBLE_COLLISION) {
glColor4f(0, 0, 0, magnitude);
glBegin(GL_QUADS);
glVertex2f(0, 0);
glVertex2d(width, 0);
glVertex2d(width, height);
glVertex2d(0, height);
glEnd();
}
}
void drawGroundPlaneGrid(float size) {
glColor3f(0.4f, 0.5f, 0.3f);
void renderGroundPlaneGrid(float size, float impact) {
glLineWidth(2.0);
glm::vec4 impactColor(1, 0, 0, 1);
glm::vec3 lineColor(0.4, 0.5, 0.3);
glm::vec4 surfaceColor(0.5, 0.5, 0.5, 0.4);
glColor3fv(&lineColor.x);
for (float x = 0; x <= size; x++) {
glBegin(GL_LINES);
glVertex3f(x, 0.0f, 0);
glVertex3f(x, 0.0f, size);
glVertex3f(0, 0.0f, x);
glVertex3f(size, 0.0f, x);
glVertex3f(x, 0, 0);
glVertex3f(x, 0, size);
glVertex3f(0, 0, x);
glVertex3f(size, 0, x);
glEnd();
}
// Draw a translucent quad just underneath the grid.
glColor4f(0.5, 0.5, 0.5, 0.4);
// Draw the floor, colored for recent impact
glm::vec4 floorColor = impact * impactColor + (1.f - impact) * surfaceColor;
glColor4fv(&floorColor.x);
glBegin(GL_QUADS);
glVertex3f(0, 0, 0);
glVertex3f(size, 0, 0);
@ -452,7 +467,7 @@ void renderOrientationDirections(glm::vec3 position, const glm::quat& orientatio
bool closeEnoughForGovernmentWork(float a, float b) {
float distance = std::abs(a-b);
//printLog("closeEnoughForGovernmentWork() a=%1.10f b=%1.10f distance=%1.10f\n",a,b,distance);
//qDebug("closeEnoughForGovernmentWork() a=%1.10f b=%1.10f distance=%1.10f\n",a,b,distance);
return (distance < 0.00001f);
}
@ -470,7 +485,7 @@ void runTimingTests() {
gettimeofday(&endTime, NULL);
}
elapsedMsecs = diffclock(&startTime, &endTime);
printLog("gettimeofday() usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests);
qDebug("gettimeofday() usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests);
// Random number generation
gettimeofday(&startTime, NULL);
@ -479,7 +494,7 @@ void runTimingTests() {
}
gettimeofday(&endTime, NULL);
elapsedMsecs = diffclock(&startTime, &endTime);
printLog("rand() stored in array usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests);
qDebug("rand() stored in array usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests);
// Random number generation using randFloat()
gettimeofday(&startTime, NULL);
@ -488,7 +503,7 @@ void runTimingTests() {
}
gettimeofday(&endTime, NULL);
elapsedMsecs = diffclock(&startTime, &endTime);
printLog("randFloat() stored in array usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests);
qDebug("randFloat() stored in array usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests);
// PowF function
fTest = 1145323.2342f;
@ -498,7 +513,7 @@ void runTimingTests() {
}
gettimeofday(&endTime, NULL);
elapsedMsecs = diffclock(&startTime, &endTime);
printLog("powf(f, 0.5) usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests);
qDebug("powf(f, 0.5) usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests);
// Vector Math
float distance;
@ -511,7 +526,7 @@ void runTimingTests() {
}
gettimeofday(&endTime, NULL);
elapsedMsecs = diffclock(&startTime, &endTime);
printLog("vector math usecs: %f [%f msecs total for %d tests]\n",
qDebug("vector math usecs: %f [%f msecs total for %d tests]\n",
1000.0f * elapsedMsecs / (float) numTests, elapsedMsecs, numTests);
// Vec3 test
@ -525,7 +540,7 @@ void runTimingTests() {
}
gettimeofday(&endTime, NULL);
elapsedMsecs = diffclock(&startTime, &endTime);
printLog("vec3 assign and dot() usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests);
qDebug("vec3 assign and dot() usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests);
}

View file

@ -57,7 +57,10 @@ glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha);
double diffclock(timeval *clock1,timeval *clock2);
void drawGroundPlaneGrid(float size);
void renderGroundPlaneGrid(float size, float impact);
void renderCollisionOverlay(int width, int height, float magnitude);
void renderDiskShadow(glm::vec3 position, glm::vec3 upDirection, float radius, float darkness);

View file

@ -5,28 +5,31 @@
// Created by Philip on 12/31/12.
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
//
#ifdef _WIN32
#define _timeval_
#define _USE_MATH_DEFINES
#endif
#include <cstring>
#include <cmath>
#include <iostream> // to load voxels from file
#include <fstream> // to load voxels from file
#include <pthread.h>
#include <glm/gtc/random.hpp>
#include <SharedUtil.h>
#include <OctalCode.h>
#include <PacketHeaders.h>
#include <PerfStat.h>
#include <OctalCode.h>
#include <pthread.h>
#include <SharedUtil.h>
#include "Application.h"
#include "Log.h"
#include "VoxelConstants.h"
#include "CoverageMap.h"
#include "CoverageMapV2.h"
#include "InterfaceConfig.h"
#include "renderer/ProgramObject.h"
#include "VoxelConstants.h"
#include "VoxelSystem.h"
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,
@ -141,16 +144,16 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
int commandLength = strlen(command); // commands are null terminated strings
int totalLength = 1+commandLength+1;
printLog("got Z message len(%d)= %s\n", numBytes, command);
qDebug("got Z message len(%d)= %s\n", numBytes, command);
while (totalLength <= numBytes) {
if (0==strcmp(command,(char*)"erase all")) {
printLog("got Z message == erase all\n");
qDebug("got Z message == erase all\n");
_tree->eraseAllVoxels();
_voxelsInReadArrays = _voxelsInWriteArrays = 0; // better way to do this??
}
if (0==strcmp(command,(char*)"add scene")) {
printLog("got Z message == add scene - NOT SUPPORTED ON INTERFACE\n");
qDebug("got Z message == add scene - NOT SUPPORTED ON INTERFACE\n");
}
totalLength += commandLength+1;
}
@ -705,7 +708,7 @@ bool VoxelSystem::randomColorOperation(VoxelNode* node, void* extraData) {
void VoxelSystem::randomizeVoxelColors() {
_nodeCount = 0;
_tree->recurseTreeWithOperation(randomColorOperation);
printLog("setting randomized true color for %d nodes\n", _nodeCount);
qDebug("setting randomized true color for %d nodes\n", _nodeCount);
setupNewVoxelsForDrawing();
}
@ -719,7 +722,7 @@ bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, void* extraData)
void VoxelSystem::falseColorizeRandom() {
_nodeCount = 0;
_tree->recurseTreeWithOperation(falseColorizeRandomOperation);
printLog("setting randomized false color for %d nodes\n", _nodeCount);
qDebug("setting randomized false color for %d nodes\n", _nodeCount);
setupNewVoxelsForDrawing();
}
@ -733,7 +736,7 @@ void VoxelSystem::trueColorize() {
PerformanceWarning warn(true, "trueColorize()",true);
_nodeCount = 0;
_tree->recurseTreeWithOperation(trueColorizeOperation);
printLog("setting true color for %d nodes\n", _nodeCount);
qDebug("setting true color for %d nodes\n", _nodeCount);
setupNewVoxelsForDrawing();
}
@ -753,7 +756,7 @@ bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, void* extraData)
void VoxelSystem::falseColorizeInView(ViewFrustum* viewFrustum) {
_nodeCount = 0;
_tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)viewFrustum);
printLog("setting in view false color for %d nodes\n", _nodeCount);
qDebug("setting in view false color for %d nodes\n", _nodeCount);
setupNewVoxelsForDrawing();
}
@ -803,10 +806,10 @@ void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) {
_maxDistance = 0.0;
_minDistance = FLT_MAX;
_tree->recurseTreeWithOperation(getDistanceFromViewRangeOperation,(void*)viewFrustum);
printLog("determining distance range for %d nodes\n", _nodeCount);
qDebug("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);
qDebug("setting in distance false color for %d nodes\n", _nodeCount);
setupNewVoxelsForDrawing();
}
@ -918,7 +921,7 @@ void VoxelSystem::removeOutOfView() {
}
bool showRemoveDebugDetails = false;
if (showRemoveDebugDetails) {
printLog("removeOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld _removedVoxels.count()=%d \n",
qDebug("removeOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld _removedVoxels.count()=%d \n",
args.nodesScanned, args.nodesRemoved, args.nodesInside,
args.nodesIntersect, args.nodesOutside, _removedVoxels.count()
);
@ -984,7 +987,7 @@ bool VoxelSystem::falseColorizeRandomEveryOtherOperation(VoxelNode* node, void*
void VoxelSystem::falseColorizeRandomEveryOther() {
falseColorizeRandomEveryOtherArgs args;
_tree->recurseTreeWithOperation(falseColorizeRandomEveryOtherOperation,&args);
printLog("randomized false color for every other node: total %ld, colorable %ld, colored %ld\n",
qDebug("randomized false color for every other node: total %ld, colorable %ld, colored %ld\n",
args.totalNodes, args.colorableNodes, args.coloredNodes);
setupNewVoxelsForDrawing();
}
@ -1045,7 +1048,7 @@ bool VoxelSystem::collectStatsForTreesAndVBOsOperation(VoxelNode* node, void* ex
unsigned long nodeIndex = node->getBufferIndex();
if (args->hasIndexFound[nodeIndex]) {
args->duplicateVBOIndex++;
printLog("duplicateVBO found... index=%ld, isDirty=%s, shouldRender=%s \n", nodeIndex,
qDebug("duplicateVBO found... index=%ld, isDirty=%s, shouldRender=%s \n", nodeIndex,
debug::valueOf(node->isDirty()), debug::valueOf(node->getShouldRender()));
} else {
args->hasIndexFound[nodeIndex] = true;
@ -1080,13 +1083,13 @@ void VoxelSystem::collectStatsForTreesAndVBOs() {
args.expectedMax = _voxelsInWriteArrays;
_tree->recurseTreeWithOperation(collectStatsForTreesAndVBOsOperation,&args);
printLog("Local Voxel Tree Statistics:\n total nodes %ld \n leaves %ld \n dirty %ld \n colored %ld \n shouldRender %ld \n",
qDebug("Local Voxel Tree Statistics:\n total nodes %ld \n leaves %ld \n dirty %ld \n colored %ld \n shouldRender %ld \n",
args.totalNodes, args.leafNodes, args.dirtyNodes, args.coloredNodes, args.shouldRenderNodes);
printLog(" _voxelsDirty=%s \n _voxelsInWriteArrays=%ld \n minDirty=%ld \n maxDirty=%ld \n", debug::valueOf(_voxelsDirty),
qDebug(" _voxelsDirty=%s \n _voxelsInWriteArrays=%ld \n minDirty=%ld \n maxDirty=%ld \n", debug::valueOf(_voxelsDirty),
_voxelsInWriteArrays, minDirty, maxDirty);
printLog(" inVBO %ld \n nodesInVBOOverExpectedMax %ld \n duplicateVBOIndex %ld \n nodesInVBONotShouldRender %ld \n",
qDebug(" inVBO %ld \n nodesInVBOOverExpectedMax %ld \n duplicateVBOIndex %ld \n nodesInVBONotShouldRender %ld \n",
args.nodesInVBO, args.nodesInVBOOverExpectedMax, args.duplicateVBOIndex, args.nodesInVBONotShouldRender);
glBufferIndex minInVBO = GLBUFFER_INDEX_UNKNOWN;
@ -1099,7 +1102,7 @@ void VoxelSystem::collectStatsForTreesAndVBOs() {
}
}
printLog(" minInVBO=%ld \n maxInVBO=%ld \n _voxelsInWriteArrays=%ld \n _voxelsInReadArrays=%ld \n",
qDebug(" minInVBO=%ld \n maxInVBO=%ld \n _voxelsInWriteArrays=%ld \n _voxelsInReadArrays=%ld \n",
minInVBO, maxInVBO, _voxelsInWriteArrays, _voxelsInReadArrays);
}
@ -1124,7 +1127,7 @@ void VoxelSystem::createVoxel(float x, float y, float z, float s,
unsigned char red, unsigned char green, unsigned char blue, bool destructive) {
pthread_mutex_lock(&_treeLock);
//printLog("VoxelSystem::createVoxel(%f,%f,%f,%f)\n",x,y,z,s);
//qDebug("VoxelSystem::createVoxel(%f,%f,%f,%f)\n",x,y,z,s);
_tree->createVoxel(x, y, z, s, red, green, blue, destructive);
setupNewVoxelsForDrawing();
@ -1250,9 +1253,9 @@ bool VoxelSystem::falseColorizeOccludedOperation(VoxelNode* node, void* extraDat
args->occludedVoxels++;
} else if (result == STORED) {
args->notOccludedVoxels++;
//printLog("***** falseColorizeOccludedOperation() NODE is STORED *****\n");
//qDebug("***** falseColorizeOccludedOperation() NODE is STORED *****\n");
} else if (result == DOESNT_FIT) {
//printLog("***** falseColorizeOccludedOperation() NODE DOESNT_FIT???? *****\n");
//qDebug("***** falseColorizeOccludedOperation() NODE DOESNT_FIT???? *****\n");
}
}
return true; // keep going!
@ -1285,7 +1288,7 @@ void VoxelSystem::falseColorizeOccluded() {
_tree->recurseTreeWithOperationDistanceSorted(falseColorizeOccludedOperation, position, (void*)&args);
printLog("falseColorizeOccluded()\n position=(%f,%f)\n total=%ld\n colored=%ld\n occluded=%ld\n notOccluded=%ld\n outOfView=%ld\n subtreeVoxelsSkipped=%ld\n stagedForDeletion=%ld\n nonLeaves=%ld\n nonLeavesOutOfView=%ld\n nonLeavesOccluded=%ld\n pointInside_calls=%ld\n occludes_calls=%ld\n intersects_calls=%ld\n",
qDebug("falseColorizeOccluded()\n position=(%f,%f)\n total=%ld\n colored=%ld\n occluded=%ld\n notOccluded=%ld\n outOfView=%ld\n subtreeVoxelsSkipped=%ld\n stagedForDeletion=%ld\n nonLeaves=%ld\n nonLeavesOutOfView=%ld\n nonLeavesOccluded=%ld\n pointInside_calls=%ld\n occludes_calls=%ld\n intersects_calls=%ld\n",
position.x, position.y,
args.totalVoxels, args.coloredVoxels, args.occludedVoxels,
args.notOccludedVoxels, args.outOfView, args.subtreeVoxelsSkipped,
@ -1371,9 +1374,9 @@ bool VoxelSystem::falseColorizeOccludedV2Operation(VoxelNode* node, void* extraD
args->occludedVoxels++;
} else if (result == V2_STORED) {
args->notOccludedVoxels++;
//printLog("***** falseColorizeOccludedOperation() NODE is STORED *****\n");
//qDebug("***** falseColorizeOccludedOperation() NODE is STORED *****\n");
} else if (result == V2_DOESNT_FIT) {
//printLog("***** falseColorizeOccludedOperation() NODE DOESNT_FIT???? *****\n");
//qDebug("***** falseColorizeOccludedOperation() NODE DOESNT_FIT???? *****\n");
}
delete voxelPolygon; // V2 maps don't store polygons, so we're always in charge of freeing
}
@ -1410,7 +1413,7 @@ void VoxelSystem::falseColorizeOccludedV2() {
_tree->recurseTreeWithOperationDistanceSorted(falseColorizeOccludedV2Operation, position, (void*)&args);
printLog("falseColorizeOccludedV2()\n position=(%f,%f)\n total=%ld\n colored=%ld\n occluded=%ld\n notOccluded=%ld\n outOfView=%ld\n subtreeVoxelsSkipped=%ld\n stagedForDeletion=%ld\n nonLeaves=%ld\n nonLeavesOutOfView=%ld\n nonLeavesOccluded=%ld\n pointInside_calls=%ld\n occludes_calls=%ld\n intersects_calls=%ld\n",
qDebug("falseColorizeOccludedV2()\n position=(%f,%f)\n total=%ld\n colored=%ld\n occluded=%ld\n notOccluded=%ld\n outOfView=%ld\n subtreeVoxelsSkipped=%ld\n stagedForDeletion=%ld\n nonLeaves=%ld\n nonLeavesOutOfView=%ld\n nonLeavesOccluded=%ld\n pointInside_calls=%ld\n occludes_calls=%ld\n intersects_calls=%ld\n",
position.x, position.y,
args.totalVoxels, args.coloredVoxels, args.occludedVoxels,
args.notOccludedVoxels, args.outOfView, args.subtreeVoxelsSkipped,

View file

@ -15,7 +15,6 @@
#include <UVCCameraControl.hpp>
#endif
#include <Log.h>
#include <SharedUtil.h>
#include "Application.h"
@ -158,7 +157,7 @@ void Webcam::setFrame(const Mat& color, int format, const Mat& depth, const Rota
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _textureSize.width = colorImage.width, _textureSize.height = colorImage.height,
0, format, GL_UNSIGNED_BYTE, colorImage.imageData);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
printLog("Capturing video at %gx%g.\n", _textureSize.width, _textureSize.height);
qDebug("Capturing video at %gx%g.\n", _textureSize.width, _textureSize.height);
} else {
glBindTexture(GL_TEXTURE_2D, _colorTextureID);
@ -327,26 +326,26 @@ static glm::quat xnToGLM(const XnMatrix3X3& matrix) {
}
static void XN_CALLBACK_TYPE newUser(UserGenerator& generator, XnUserID id, void* cookie) {
printLog("Found user %d.\n", id);
qDebug("Found user %d.\n", id);
generator.GetSkeletonCap().RequestCalibration(id, false);
}
static void XN_CALLBACK_TYPE lostUser(UserGenerator& generator, XnUserID id, void* cookie) {
printLog("Lost user %d.\n", id);
qDebug("Lost user %d.\n", id);
}
static void XN_CALLBACK_TYPE calibrationStarted(SkeletonCapability& capability, XnUserID id, void* cookie) {
printLog("Calibration started for user %d.\n", id);
qDebug("Calibration started for user %d.\n", id);
}
static void XN_CALLBACK_TYPE calibrationCompleted(SkeletonCapability& capability,
XnUserID id, XnCalibrationStatus status, void* cookie) {
if (status == XN_CALIBRATION_STATUS_OK) {
printLog("Calibration completed for user %d.\n", id);
qDebug("Calibration completed for user %d.\n", id);
capability.StartTracking(id);
} else {
printLog("Calibration failed to user %d.\n", id);
qDebug("Calibration failed to user %d.\n", id);
capability.RequestCalibration(id, true);
}
}
@ -441,7 +440,7 @@ void FrameGrabber::grabFrame() {
// make sure it's in the format we expect
if (image->nChannels != 3 || image->depth != IPL_DEPTH_8U || image->dataOrder != IPL_DATA_ORDER_PIXEL ||
image->origin != 0) {
printLog("Invalid webcam image format.\n");
qDebug("Invalid webcam image format.\n");
return;
}
color = image;
@ -629,7 +628,7 @@ bool FrameGrabber::init() {
// load our face cascade
switchToResourcesParentIfRequired();
if (_faceCascade.empty() && !_faceCascade.load("resources/haarcascades/haarcascade_frontalface_alt.xml")) {
printLog("Failed to load Haar cascade for face tracking.\n");
qDebug("Failed to load Haar cascade for face tracking.\n");
return false;
}
@ -662,7 +661,7 @@ bool FrameGrabber::init() {
// next, an ordinary webcam
if ((_capture = cvCaptureFromCAM(-1)) == 0) {
printLog("Failed to open webcam.\n");
qDebug("Failed to open webcam.\n");
return false;
}
const int IDEAL_FRAME_WIDTH = 320;

View file

@ -5,24 +5,25 @@
// Created by Philip Rosedale on 9/11/12.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
#include <vector>
#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>
#include <glm/gtx/vector_angle.hpp>
#include <vector>
#include <NodeList.h>
#include <NodeTypes.h>
#include <OculusManager.h>
#include <PacketHeaders.h>
#include <SharedUtil.h>
#include "world.h"
#include "Application.h"
#include "Avatar.h"
#include "Hand.h"
#include "Head.h"
#include "Log.h"
#include "Physics.h"
#include "world.h"
#include "ui/TextRenderer.h"
#include <NodeList.h>
#include <NodeTypes.h>
#include <PacketHeaders.h>
#include <OculusManager.h>
using namespace std;
@ -97,6 +98,7 @@ Avatar::Avatar(Node* owningNode) :
_elapsedTimeMoving(0.0f),
_elapsedTimeStopped(0.0f),
_elapsedTimeSinceCollision(0.0f),
_lastCollisionPosition(0, 0, 0),
_speedBrakes(false),
_isThrustOn(false),
_voxels(this)
@ -548,13 +550,13 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
// For gravity, always move the avatar by the amount driven by gravity, so that the collision
// routines will detect it and collide every frame when pulled by gravity to a surface
//
_velocity += _scale * _gravity * (GRAVITY_EARTH * deltaTime);
_position += _scale * _gravity * (GRAVITY_EARTH * deltaTime) * deltaTime;
const float MIN_DISTANCE_AFTER_COLLISION_FOR_GRAVITY = 0.02f;
if (glm::length(_position - _lastCollisionPosition) > MIN_DISTANCE_AFTER_COLLISION_FOR_GRAVITY) {
_velocity += _scale * _gravity * (GRAVITY_EARTH * deltaTime);
}
}
updateCollisionWithEnvironment();
updateCollisionWithVoxels();
updateCollisionWithEnvironment(deltaTime);
updateCollisionWithVoxels(deltaTime);
updateAvatarCollisions(deltaTime);
}
@ -826,6 +828,15 @@ void Avatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMovem
} else {
_avatarTouch.setHasInteractingOther(false);
}
// If there's a leap-interaction hand visible, use that as the endpoint
for (size_t i = 0; i < getHand().getPalms().size(); ++i) {
PalmData& palm = getHand().getPalms()[i];
if (palm.isActive()) {
_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = palm.getPosition();
}
}
}//if (_isMine)
//constrain right arm length and re-adjust elbow position as it bends
@ -875,29 +886,40 @@ void Avatar::updateCollisionWithSphere(glm::vec3 position, float radius, float d
}
}
void Avatar::updateCollisionWithEnvironment() {
void Avatar::updateCollisionWithEnvironment(float deltaTime) {
glm::vec3 up = getBodyUpDirection();
float radius = _height * 0.125f;
const float ENVIRONMENT_SURFACE_ELASTICITY = 1.0f;
const float ENVIRONMENT_SURFACE_DAMPING = 0.01;
const float ENVIRONMENT_COLLISION_FREQUENCY = 0.05f;
const float VISIBLE_GROUND_COLLISION_VELOCITY = 0.2f;
glm::vec3 penetration;
if (Application::getInstance()->getEnvironment()->findCapsulePenetration(
_position - up * (_pelvisFloatingHeight - radius),
_position + up * (_height - _pelvisFloatingHeight - radius), radius, penetration)) {
float velocityTowardCollision = glm::dot(_velocity, glm::normalize(penetration));
if (velocityTowardCollision > VISIBLE_GROUND_COLLISION_VELOCITY) {
Application::getInstance()->setGroundPlaneImpact(1.0f);
}
_lastCollisionPosition = _position;
updateCollisionSound(penetration, deltaTime, ENVIRONMENT_COLLISION_FREQUENCY);
applyHardCollision(penetration, ENVIRONMENT_SURFACE_ELASTICITY, ENVIRONMENT_SURFACE_DAMPING);
}
}
void Avatar::updateCollisionWithVoxels() {
void Avatar::updateCollisionWithVoxels(float deltaTime) {
float radius = _height * 0.125f;
const float VOXEL_ELASTICITY = 1.4f;
const float VOXEL_DAMPING = 0.0;
const float VOXEL_COLLISION_FREQUENCY = 0.5f;
glm::vec3 penetration;
if (Application::getInstance()->getVoxels()->findCapsulePenetration(
_position - glm::vec3(0.0f, _pelvisFloatingHeight - radius, 0.0f),
_position + glm::vec3(0.0f, _height - _pelvisFloatingHeight - radius, 0.0f), radius, penetration)) {
_lastCollisionPosition = _position;
updateCollisionSound(penetration, deltaTime, VOXEL_COLLISION_FREQUENCY);
applyHardCollision(penetration, VOXEL_ELASTICITY, VOXEL_DAMPING);
}
}
@ -926,6 +948,36 @@ void Avatar::applyHardCollision(const glm::vec3& penetration, float elasticity,
}
}
void Avatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTime, float frequency) {
// consider whether to have the collision make a sound
const float AUDIBLE_COLLISION_THRESHOLD = 0.02f;
const float COLLISION_LOUDNESS = 1.f;
const float DURATION_SCALING = 0.004f;
const float NOISE_SCALING = 0.1f;
glm::vec3 velocity = _velocity;
glm::vec3 gravity = getGravity();
if (glm::length(gravity) > EPSILON) {
// If gravity is on, remove the effect of gravity on velocity for this
// frame, so that we are not constantly colliding with the surface
velocity -= _scale * glm::length(gravity) * GRAVITY_EARTH * deltaTime * glm::normalize(gravity);
}
float velocityTowardCollision = glm::dot(velocity, glm::normalize(penetration));
float velocityTangentToCollision = glm::length(velocity) - velocityTowardCollision;
if (velocityTowardCollision > AUDIBLE_COLLISION_THRESHOLD) {
// Volume is proportional to collision velocity
// Base frequency is modified upward by the angle of the collision
// Noise is a function of the angle of collision
// Duration of the sound is a function of both base frequency and velocity of impact
Application::getInstance()->getAudio()->startCollisionSound(
fmin(COLLISION_LOUDNESS * velocityTowardCollision, 1.f),
frequency * (1.f + velocityTangentToCollision / velocityTowardCollision),
fmin(velocityTangentToCollision / velocityTowardCollision * NOISE_SCALING, 1.f),
1.f - DURATION_SCALING * powf(frequency, 0.5f) / velocityTowardCollision);
}
}
void Avatar::updateAvatarCollisions(float deltaTime) {
// Reset detector for nearest avatar
@ -1055,7 +1107,7 @@ void Avatar::render(bool lookingInMirror, bool renderAvatarBalls) {
}
glPushMatrix();
glm::vec3 chatPosition = _bodyBall[BODY_BALL_HEAD_BASE].position + getBodyUpDirection() * chatMessageHeight;
glm::vec3 chatPosition = _bodyBall[BODY_BALL_HEAD_BASE].position + getBodyUpDirection() * chatMessageHeight * _scale;
glTranslatef(chatPosition.x, chatPosition.y, chatPosition.z);
glm::quat chatRotation = Application::getInstance()->getCamera()->getRotation();
glm::vec3 chatAxis = glm::axis(chatRotation);
@ -1065,7 +1117,7 @@ void Avatar::render(bool lookingInMirror, bool renderAvatarBalls) {
glColor3f(0, 0.8, 0);
glRotatef(180, 0, 1, 0);
glRotatef(180, 0, 0, 1);
glScalef(chatMessageScale, chatMessageScale, 1.0f);
glScalef(_scale * chatMessageScale, _scale * chatMessageScale, 1.0f);
glDisable(GL_LIGHTING);
glDepthMask(false);

View file

@ -10,18 +10,21 @@
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <AvatarData.h>
#include <QSettings>
#include "world.h"
#include <AvatarData.h>
#include "AvatarTouch.h"
#include "AvatarVoxelSystem.h"
#include "InterfaceConfig.h"
#include "SerialInterface.h"
#include "Balls.h"
#include "Hand.h"
#include "Head.h"
#include "InterfaceConfig.h"
#include "Skeleton.h"
#include "SerialInterface.h"
#include "Transmitter.h"
#include "world.h"
const float BODY_BALL_RADIUS_PELVIS = 0.07;
const float BODY_BALL_RADIUS_TORSO = 0.065;
@ -115,7 +118,8 @@ public:
const glm::vec3& amplifyAngle,
float yawFromTouch,
float pitchFromTouch);
void addBodyYaw(float y) {_bodyYaw += y;};
void addBodyYaw(float bodyYaw) {_bodyYaw += bodyYaw;};
void addBodyYawDelta(float bodyYawDelta) {_bodyYawDelta += bodyYawDelta;}
void render(bool lookingInMirror, bool renderAvatarBalls);
//setters
@ -152,6 +156,7 @@ public:
float getElapsedTimeStopped () const { return _elapsedTimeStopped;}
float getElapsedTimeMoving () const { return _elapsedTimeMoving;}
float getElapsedTimeSinceCollision() const { return _elapsedTimeSinceCollision;}
const glm::vec3& getLastCollisionPosition () const { return _lastCollisionPosition;}
float getAbsoluteHeadYaw () const;
float getAbsoluteHeadPitch () const;
Head& getHead () {return _head; }
@ -159,6 +164,8 @@ public:
glm::quat getOrientation () const;
glm::quat getWorldAlignedOrientation() const;
glm::vec3 getGravity () const { return _gravity; }
glm::vec3 getUprightHeadPosition() const;
AvatarVoxelSystem* getVoxels() { return &_voxels; }
@ -240,6 +247,7 @@ private:
float _elapsedTimeMoving; // Timers to drive camera transitions when moving
float _elapsedTimeStopped;
float _elapsedTimeSinceCollision;
glm::vec3 _lastCollisionPosition;
bool _speedBrakes;
bool _isThrustOn;
@ -259,9 +267,10 @@ private:
void updateAvatarCollisions(float deltaTime);
void updateArmIKAndConstraints( float deltaTime );
void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime );
void updateCollisionWithEnvironment();
void updateCollisionWithVoxels();
void updateCollisionWithEnvironment(float deltaTime);
void updateCollisionWithVoxels(float deltaTime);
void applyHardCollision(const glm::vec3& penetration, float elasticity, float damping);
void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency);
void applyCollisionWithOtherAvatar( Avatar * other, float deltaTime );
void checkForMouseRayTouching();
};

View file

@ -93,7 +93,7 @@ const Mode MODES[] = {
void AvatarVoxelSystem::cycleMode() {
_mode = (_mode + 1) % (sizeof(MODES) / sizeof(MODES[0]));
printLog("Voxeltar bind mode %d.\n", _mode);
qDebug("Voxeltar bind mode %d.\n", _mode);
// rebind
QUrl url = _voxelURL;
@ -255,7 +255,7 @@ void AvatarVoxelSystem::handleVoxelDownloadProgress(qint64 bytesReceived, qint64
}
void AvatarVoxelSystem::handleVoxelReplyError() {
printLog("%s\n", _voxelReply->errorString().toAscii().constData());
qDebug("%s\n", _voxelReply->errorString().toAscii().constData());
_voxelReply->disconnect(this);
_voxelReply->deleteLater();

View file

@ -22,9 +22,12 @@ Hand::Hand(Avatar* owningAvatar) :
_renderAlpha(1.0),
_lookingInMirror(false),
_ballColor(0.0, 0.0, 0.4),
_position(0.0, 0.4, 0.0),
_orientation(0.0, 0.0, 0.0, 1.0)
_particleSystemInitialized(false)
{
// initialize all finger particle emitters with an invalid id as default
for (int f = 0; f< NUM_FINGERS_PER_HAND; f ++ ) {
_fingerParticleEmitter[f] = -1;
}
}
void Hand::init() {
@ -40,46 +43,89 @@ void Hand::reset() {
}
void Hand::simulate(float deltaTime, bool isMine) {
}
glm::vec3 Hand::leapPositionToWorldPosition(const glm::vec3& leapPosition) {
float unitScale = 0.001; // convert mm to meters
return _position + _orientation * (leapPosition * unitScale);
if (_isRaveGloveActive) {
updateFingerParticles(deltaTime);
}
}
void Hand::calculateGeometry() {
glm::vec3 offset(0.2, -0.2, -0.3); // place the hand in front of the face where we can see it
Head& head = _owningAvatar->getHead();
_position = head.getPosition() + head.getOrientation() * offset;
_orientation = head.getOrientation();
_basePosition = head.getPosition() + head.getOrientation() * offset;
_baseOrientation = head.getOrientation();
int numLeapBalls = _fingerTips.size();
_leapBalls.resize(numLeapBalls);
for (int i = 0; i < _fingerTips.size(); ++i) {
_leapBalls[i].rotation = _orientation;
_leapBalls[i].position = leapPositionToWorldPosition(_fingerTips[i]);
_leapBalls[i].radius = 0.01;
_leapBalls[i].touchForce = 0.0;
_leapBalls[i].isCollidable = true;
_leapBalls.clear();
for (size_t i = 0; i < getNumPalms(); ++i) {
PalmData& palm = getPalms()[i];
if (palm.isActive()) {
for (size_t f = 0; f < palm.getNumFingers(); ++f) {
FingerData& finger = palm.getFingers()[f];
if (finger.isActive()) {
const float standardBallRadius = 0.01f;
_leapBalls.resize(_leapBalls.size() + 1);
HandBall& ball = _leapBalls.back();
ball.rotation = _baseOrientation;
ball.position = finger.getTipPosition();
ball.radius = standardBallRadius;
ball.touchForce = 0.0;
ball.isCollidable = true;
}
}
}
}
}
void Hand::render(bool lookingInMirror) {
_renderAlpha = 1.0;
_lookingInMirror = lookingInMirror;
calculateGeometry();
if (_isRaveGloveActive) {
renderRaveGloveStage();
if (_particleSystemInitialized) {
_particleSystem.render();
}
}
glEnable(GL_DEPTH_TEST);
glEnable(GL_RESCALE_NORMAL);
renderHandSpheres();
}
void Hand::renderRaveGloveStage() {
if (_owningAvatar && _owningAvatar->isMyAvatar()) {
Head& head = _owningAvatar->getHead();
glm::quat headOrientation = head.getOrientation();
glm::vec3 headPosition = head.getPosition();
float scale = 100.0f;
glm::vec3 vc = headOrientation * glm::vec3( 0.0f, 0.0f, -30.0f) + headPosition;
glm::vec3 v0 = headOrientation * (glm::vec3(-1.0f, -1.0f, 0.0f) * scale) + vc;
glm::vec3 v1 = headOrientation * (glm::vec3( 1.0f, -1.0f, 0.0f) * scale) + vc;
glm::vec3 v2 = headOrientation * (glm::vec3( 1.0f, 1.0f, 0.0f) * scale) + vc;
glm::vec3 v3 = headOrientation * (glm::vec3(-1.0f, 1.0f, 0.0f) * scale) + vc;
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBegin(GL_TRIANGLE_FAN);
glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
glVertex3fv((float*)&vc);
glColor4f(0.0f, 0.0f, 0.0f, 0.5f);
glVertex3fv((float*)&v0);
glVertex3fv((float*)&v1);
glVertex3fv((float*)&v2);
glVertex3fv((float*)&v3);
glVertex3fv((float*)&v0);
glEnd();
glEnable(GL_DEPTH_TEST);
}
}
void Hand::renderHandSpheres() {
glPushMatrix();
// Draw the leap balls
@ -97,21 +143,29 @@ void Hand::renderHandSpheres() {
}
// Draw the finger root cones
if (_fingerTips.size() == _fingerRoots.size()) {
for (size_t i = 0; i < _fingerTips.size(); ++i) {
glColor4f(_ballColor.r, _ballColor.g, _ballColor.b, 0.5);
glm::vec3 tip = leapPositionToWorldPosition(_fingerTips[i]);
glm::vec3 root = leapPositionToWorldPosition(_fingerRoots[i]);
Avatar::renderJointConnectingCone(root, tip, 0.001, 0.003);
for (size_t i = 0; i < getNumPalms(); ++i) {
PalmData& palm = getPalms()[i];
if (palm.isActive()) {
for (size_t f = 0; f < palm.getNumFingers(); ++f) {
FingerData& finger = palm.getFingers()[f];
if (finger.isActive()) {
glColor4f(_ballColor.r, _ballColor.g, _ballColor.b, 0.5);
glm::vec3 tip = finger.getTipPosition();
glm::vec3 root = finger.getRootPosition();
Avatar::renderJointConnectingCone(root, tip, 0.001, 0.003);
}
}
}
}
// Draw the palms
if (_handPositions.size() == _handNormals.size()) {
for (size_t i = 0; i < _handPositions.size(); ++i) {
for (size_t i = 0; i < getNumPalms(); ++i) {
PalmData& palm = getPalms()[i];
if (palm.isActive()) {
const float palmThickness = 0.002f;
glColor4f(_ballColor.r, _ballColor.g, _ballColor.b, 0.25);
glm::vec3 tip = leapPositionToWorldPosition(_handPositions[i]);
glm::vec3 root = leapPositionToWorldPosition(_handPositions[i] + (_handNormals[i] * 2.0f));
glm::vec3 tip = palm.getPosition();
glm::vec3 root = palm.getPosition() + palm.getNormal() * palmThickness;
Avatar::renderJointConnectingCone(root, tip, 0.05, 0.03);
}
}
@ -121,14 +175,133 @@ void Hand::renderHandSpheres() {
void Hand::setLeapFingers(const std::vector<glm::vec3>& fingerTips,
const std::vector<glm::vec3>& fingerRoots) {
_fingerTips = fingerTips;
_fingerRoots = fingerRoots;
// TODO: add id-checking here to increase finger stability
size_t fingerIndex = 0;
for (size_t i = 0; i < getNumPalms(); ++i) {
PalmData& palm = getPalms()[i];
for (size_t f = 0; f < palm.getNumFingers(); ++f) {
FingerData& finger = palm.getFingers()[f];
if (fingerIndex < fingerTips.size()) {
finger.setActive(true);
finger.setRawTipPosition(fingerTips[fingerIndex]);
finger.setRawRootPosition(fingerRoots[fingerIndex]);
fingerIndex++;
}
else {
finger.setActive(false);
}
}
}
}
void Hand::setLeapHands(const std::vector<glm::vec3>& handPositions,
const std::vector<glm::vec3>& handNormals) {
_handPositions = handPositions;
_handNormals = handNormals;
for (size_t i = 0; i < getNumPalms(); ++i) {
PalmData& palm = getPalms()[i];
if (i < handPositions.size()) {
palm.setActive(true);
palm.setRawPosition(handPositions[i]);
palm.setRawNormal(handNormals[i]);
}
else {
palm.setActive(false);
}
}
}
void Hand::updateFingerParticles(float deltaTime) {
if (!_particleSystemInitialized) {
for ( int f = 0; f< NUM_FINGERS_PER_HAND; f ++ ) {
_particleSystem.setShowingEmitter(f, true );
_fingerParticleEmitter[f] = _particleSystem.addEmitter();
assert( _fingerParticleEmitter[f] != -1 );
ParticleSystem::ParticleAttributes attributes;
// set attributes for each life stage of the particle:
attributes.radius = 0.0f;
attributes.color = glm::vec4( 1.0f, 1.0f, 0.5f, 0.5f);
attributes.gravity = 0.0f;
attributes.airFriction = 0.0f;
attributes.jitter = 0.002f;
attributes.emitterAttraction = 0.0f;
attributes.tornadoForce = 0.0f;
attributes.neighborAttraction = 0.0f;
attributes.neighborRepulsion = 0.0f;
attributes.bounce = 1.0f;
attributes.usingCollisionSphere = false;
_particleSystem.setParticleAttributes(_fingerParticleEmitter[f], 0, attributes);
attributes.radius = 0.01f;
attributes.jitter = 0.0f;
attributes.gravity = -0.005f;
attributes.color = glm::vec4( 1.0f, 0.2f, 0.0f, 0.4f);
_particleSystem.setParticleAttributes(_fingerParticleEmitter[f], 1, attributes);
attributes.radius = 0.01f;
attributes.gravity = 0.0f;
attributes.color = glm::vec4( 0.0f, 0.0f, 0.0f, 0.2f);
_particleSystem.setParticleAttributes(_fingerParticleEmitter[f], 2, attributes);
attributes.radius = 0.02f;
attributes.color = glm::vec4( 0.0f, 0.0f, 0.0f, 0.0f);
_particleSystem.setParticleAttributes(_fingerParticleEmitter[f], 3, attributes);
}
_particleSystemInitialized = true;
} else {
// update the particles
static float t = 0.0f;
t += deltaTime;
int fingerIndex = 0;
for (size_t i = 0; i < getNumPalms(); ++i) {
PalmData& palm = getPalms()[i];
if (palm.isActive()) {
for (size_t f = 0; f < palm.getNumFingers(); ++f) {
FingerData& finger = palm.getFingers()[f];
if (finger.isActive()) {
if (_fingerParticleEmitter[fingerIndex] != -1) {
glm::vec3 particleEmitterPosition = finger.getTipPosition();
glm::vec3 fingerDirection = particleEmitterPosition - leapPositionToWorldPosition(finger.getRootPosition());
float fingerLength = glm::length(fingerDirection);
if (fingerLength > 0.0f) {
fingerDirection /= fingerLength;
} else {
fingerDirection = IDENTITY_UP;
}
glm::quat particleEmitterRotation = rotationBetween(palm.getNormal(), fingerDirection);
//glm::quat particleEmitterRotation = glm::angleAxis(0.0f, fingerDirection);
_particleSystem.setEmitterPosition(_fingerParticleEmitter[f], particleEmitterPosition);
_particleSystem.setEmitterRotation(_fingerParticleEmitter[f], particleEmitterRotation);
const glm::vec3 velocity = fingerDirection * 0.002f;
const float lifespan = 1.0f;
_particleSystem.emitParticlesNow(_fingerParticleEmitter[f], 1, velocity, lifespan);
}
}
}
}
}
_particleSystem.setUpDirection(glm::vec3(0.0f, 1.0f, 0.0f));
_particleSystem.simulate(deltaTime);
}
}

View file

@ -15,10 +15,10 @@
#include "world.h"
#include "InterfaceConfig.h"
#include "SerialInterface.h"
#include "ParticleSystem.h"
#include <SharedUtil.h>
#include <vector>
class Avatar;
class ProgramObject;
@ -46,27 +46,33 @@ public:
const std::vector<glm::vec3>& fingerRoots);
void setLeapHands (const std::vector<glm::vec3>& handPositions,
const std::vector<glm::vec3>& handNormals);
void updateFingerParticles(float deltaTime);
void setRaveGloveActive(bool active) { _isRaveGloveActive = active; }
// getters
const glm::vec3& getLeapBallPosition (int ball) const { return _leapBalls[ball].position;}
// position conversion
glm::vec3 leapPositionToWorldPosition(const glm::vec3& leapPosition);
bool isRaveGloveActive () const { return _isRaveGloveActive; }
private:
// disallow copies of the Hand, copy of owning Avatar is disallowed too
Hand(const Hand&);
Hand& operator= (const Hand&);
ParticleSystem _particleSystem;
Avatar* _owningAvatar;
float _renderAlpha;
bool _lookingInMirror;
bool _isRaveGloveActive;
glm::vec3 _ballColor;
glm::vec3 _position;
glm::quat _orientation;
std::vector<HandBall> _leapBalls;
bool _particleSystemInitialized;
int _fingerParticleEmitter[NUM_FINGERS_PER_HAND];
// private methods
void renderRaveGloveStage();
void renderHandSpheres();
void calculateGeometry();
};

View file

@ -227,8 +227,9 @@ void Head::simulate(float deltaTime, bool isMine) {
const float CAMERA_FOLLOW_HEAD_RATE_START = 0.01f;
const float CAMERA_FOLLOW_HEAD_RATE_MAX = 0.5f;
const float CAMERA_FOLLOW_HEAD_RATE_RAMP_RATE = 1.05f;
const float CAMERA_STOP_TOLERANCE_DEGREES = 0.1f;
const float CAMERA_START_TOLERANCE_DEGREES = 2.0f;
const float CAMERA_STOP_TOLERANCE_DEGREES = 0.5f;
const float CAMERA_PITCH_START_TOLERANCE_DEGREES = 20.0f;
const float CAMERA_YAW_START_TOLERANCE_DEGREES = 10.0f;
float cameraHeadAngleDifference = glm::length(glm::vec2(_pitch - _cameraPitch, _yaw - _cameraYaw));
if (_isCameraMoving) {
_cameraFollowHeadRate = glm::clamp(_cameraFollowHeadRate * CAMERA_FOLLOW_HEAD_RATE_RAMP_RATE,
@ -241,7 +242,8 @@ void Head::simulate(float deltaTime, bool isMine) {
_isCameraMoving = false;
}
} else {
if (cameraHeadAngleDifference > CAMERA_START_TOLERANCE_DEGREES) {
if ((fabs(_pitch - _cameraPitch) > CAMERA_PITCH_START_TOLERANCE_DEGREES) ||
(fabs(_yaw - _cameraYaw) > CAMERA_YAW_START_TOLERANCE_DEGREES)) {
_isCameraMoving = true;
_cameraFollowHeadRate = CAMERA_FOLLOW_HEAD_RATE_START;
}

View file

@ -16,15 +16,16 @@
//
#include "Application.h"
#include "Log.h"
#include <QDebug>
int main(int argc, const char * argv[]) {
timeval startup_time;
gettimeofday(&startup_time, NULL);
Application app(argc, const_cast<char**>(argv), startup_time);
printLog( "Created QT Application.\n" );
qDebug( "Created QT Application.\n" );
int exitCode = app.exec();
printLog("Normal exit.\n");
qDebug("Normal exit.\n");
return exitCode;
}

View file

@ -39,7 +39,6 @@
#include "InterfaceConfig.h"
#include "renderer/ProgramObject.h"
#include "Log.h"
#include <cstddef>
#include <cfloat>

View file

@ -38,12 +38,12 @@ namespace starfield {
if (! UrlReader::readUrl(url, *this, cacheFile))
{
printLog("%s:%d: %s\n",
qDebug("%s:%d: %s\n",
_urlStr, _lineNo, getError());
return false;
}
printLog("Loaded %u stars.\n", _recordsRead);
qDebug("Loaded %u stars.\n", _recordsRead);
return true;
}
@ -63,7 +63,7 @@ namespace starfield {
_vertices->clear();
_vertices->reserve(_limit);
// printLog("Stars.cpp: loader begin %s\n", url);
// qDebug("Stars.cpp: loader begin %s\n", url);
}
size_t transfer(char* input, size_t bytes) {
@ -103,7 +103,7 @@ namespace starfield {
} else {
printLog("Stars.cpp:%d: Bad input from %s\n",
qDebug("Stars.cpp:%d: Bad input from %s\n",
_lineNo, _urlStr);
}
@ -128,7 +128,7 @@ namespace starfield {
// remember the brightness at its top
if (_recordsRead == _limit) {
// printLog("Stars.cpp: vertex limit reached -> heap mode\n");
// qDebug("Stars.cpp: vertex limit reached -> heap mode\n");
make_heap(
_vertices->begin(), _vertices->end(),

View file

@ -7,8 +7,6 @@
#include <QPalette>
#include <QColor>
#include "Log.h"
BandwidthDialog::BandwidthDialog(QWidget* parent, BandwidthMeter* model) :
QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint),
_model(model) {

View file

@ -18,6 +18,8 @@
using namespace std;
static const float fingerVectorRadix = 4; // bits of precision when converting from float<->fixed
AvatarData::AvatarData(Node* owningNode) :
NodeData(owningNode),
_handPosition(0,0,0),
@ -127,36 +129,22 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
*destinationBuffer++ = bitItems;
// leap hand data
// In order to make the hand data version-robust, hand data packing is just a series of vec3's,
// with conventions. If a client doesn't know the conventions, they can just get the vec3's
// and render them as balls, or ignore them, without crashing or disrupting anyone.
// Current convention:
// Zero or more fingetTip positions, followed by the same number of fingerRoot positions
const std::vector<glm::vec3>& fingerTips = _handData->getFingerTips();
const std::vector<glm::vec3>& fingerRoots = _handData->getFingerRoots();
size_t numFingerVectors = fingerTips.size() + fingerRoots.size();
if (numFingerVectors > 255)
numFingerVectors = 0; // safety. We shouldn't ever get over 255, so consider that invalid.
std::vector<glm::vec3> fingerVectors;
_handData->encodeRemoteData(fingerVectors);
/////////////////////////////////
// Temporarily disable Leap finger sending, as it's causing a crash whenever someone's got a Leap connected
numFingerVectors = 0;
fingerVectors.clear();
/////////////////////////////////
*destinationBuffer++ = (unsigned char)numFingerVectors;
if (numFingerVectors > 0) {
for (size_t i = 0; i < fingerTips.size(); ++i) {
destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerTips[i].x, 4);
destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerTips[i].y, 4);
destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerTips[i].z, 4);
}
for (size_t i = 0; i < fingerRoots.size(); ++i) {
destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerRoots[i].x, 4);
destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerRoots[i].y, 4);
destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerRoots[i].z, 4);
}
if (fingerVectors.size() > 255)
fingerVectors.clear(); // safety. We shouldn't ever get over 255, so consider that invalid.
*destinationBuffer++ = (unsigned char)fingerVectors.size();
for (size_t i = 0; i < fingerVectors.size(); ++i) {
destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerVectors[i].x, fingerVectorRadix);
destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerVectors[i].y, fingerVectorRadix);
destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerVectors[i].z, fingerVectorRadix);
}
// skeleton joints
@ -222,7 +210,7 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
memcpy(&handPositionRelative, sourceBuffer, sizeof(float) * 3);
_handPosition = _position + handPositionRelative;
sourceBuffer += sizeof(float) * 3;
// Lookat Position
memcpy(&_headData->_lookAtPosition, sourceBuffer, sizeof(_headData->_lookAtPosition));
sourceBuffer += sizeof(_headData->_lookAtPosition);
@ -263,25 +251,16 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
// leap hand data
if (sourceBuffer - startPosition < numBytes) // safety check
{
std::vector<glm::vec3> fingerTips;
std::vector<glm::vec3> fingerRoots;
unsigned int numFingerVectors = *sourceBuffer++;
unsigned int numFingerTips = numFingerVectors / 2;
unsigned int numFingerRoots = numFingerVectors - numFingerTips;
fingerTips.resize(numFingerTips);
fingerRoots.resize(numFingerRoots);
for (size_t i = 0; i < numFingerTips; ++i) {
sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerTips[i].x), 4);
sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerTips[i].y), 4);
sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerTips[i].z), 4);
if (numFingerVectors > 0) {
std::vector<glm::vec3> fingerVectors(numFingerVectors);
for (size_t i = 0; i < numFingerVectors; ++i) {
sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerVectors[i].x), fingerVectorRadix);
sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerVectors[i].y), fingerVectorRadix);
sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerVectors[i].z), fingerVectorRadix);
}
_handData->decodeRemoteData(fingerVectors);
}
for (size_t i = 0; i < numFingerRoots; ++i) {
sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerRoots[i].x), 4);
sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerRoots[i].y), 4);
sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerRoots[i].z), 4);
}
_handData->setFingerTips(fingerTips);
_handData->setFingerRoots(fingerRoots);
}
// skeleton joints
@ -430,4 +409,3 @@ int unpackFloatFromByte(unsigned char* buffer, float& value, float scaleBy) {
value = ((float)holder / (float) 255) * scaleBy;
return sizeof(holder);
}

View file

@ -29,7 +29,6 @@ const int WANT_OCCLUSION_CULLING_BIT = 7; // 8th bit
const float MAX_AUDIO_LOUDNESS = 1000.0; // close enough for mouth animation
enum KeyState
{
NO_KEY_DOWN = 0,

View file

@ -9,7 +9,74 @@
#include "HandData.h"
HandData::HandData(AvatarData* owningAvatar) :
_basePosition(0.0f, 0.0f, 0.0f),
_baseOrientation(0.0f, 0.0f, 0.0f, 1.0f),
_owningAvatarData(owningAvatar)
{
for (int i = 0; i < 2; ++i) {
_palms.push_back(PalmData(this));
}
}
PalmData::PalmData(HandData* owningHandData) :
_rawPosition(0, 0, 0),
_rawNormal(0, 1, 0),
_isActive(false),
_owningHandData(owningHandData)
{
for (int i = 0; i < NUM_FINGERS_PER_HAND; ++i) {
_fingers.push_back(FingerData(this, owningHandData));
}
}
FingerData::FingerData(PalmData* owningPalmData, HandData* owningHandData) :
_tipRawPosition(0, 0, 0),
_rootRawPosition(0, 0, 0),
_isActive(false),
_owningPalmData(owningPalmData),
_owningHandData(owningHandData)
{
}
void HandData::encodeRemoteData(std::vector<glm::vec3>& fingerVectors) {
fingerVectors.clear();
for (size_t i = 0; i < getNumPalms(); ++i) {
PalmData& palm = getPalms()[i];
fingerVectors.push_back(palm.getRawPosition());
fingerVectors.push_back(palm.getRawNormal());
for (size_t f = 0; f < palm.getNumFingers(); ++f) {
FingerData& finger = palm.getFingers()[f];
if (finger.isActive()) {
fingerVectors.push_back(finger.getTipRawPosition());
fingerVectors.push_back(finger.getRootRawPosition());
}
else {
fingerVectors.push_back(glm::vec3(0,0,0));
fingerVectors.push_back(glm::vec3(0,0,0));
}
}
}
}
void HandData::decodeRemoteData(const std::vector<glm::vec3>& fingerVectors) {
size_t vectorIndex = 0;
for (size_t i = 0; i < getNumPalms(); ++i) {
PalmData& palm = getPalms()[i];
// If a palm is active, there will be
// 1 vector for its position
// 1 vector for normal
// 10 vectors for fingers (5 tip/root pairs)
bool palmActive = fingerVectors.size() >= i * 12;
palm.setActive(palmActive);
if (palmActive) {
palm.setRawPosition(fingerVectors[vectorIndex++]);
palm.setRawNormal(fingerVectors[vectorIndex++]);
for (size_t f = 0; f < NUM_FINGERS_PER_HAND; ++f) {
FingerData& finger = palm.getFingers()[i];
finger.setRawTipPosition(fingerVectors[vectorIndex++]);
finger.setRawRootPosition(fingerVectors[vectorIndex++]);
}
}
}
}

View file

@ -13,8 +13,13 @@
#include <vector>
#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>
class AvatarData;
class FingerData;
class PalmData;
const int NUM_FINGERS_PER_HAND = 5;
class HandData {
public:
@ -22,26 +27,79 @@ public:
// These methods return the positions in Leap-relative space.
// To convert to world coordinates, use Hand::leapPositionToWorldPosition.
const std::vector<glm::vec3>& getFingerTips() const { return _fingerTips; }
const std::vector<glm::vec3>& getFingerRoots() const { return _fingerRoots; }
const std::vector<glm::vec3>& getHandPositions() const { return _handPositions; }
const std::vector<glm::vec3>& getHandNormals() const { return _handNormals; }
void setFingerTips(const std::vector<glm::vec3>& fingerTips) { _fingerTips = fingerTips; }
void setFingerRoots(const std::vector<glm::vec3>& fingerRoots) { _fingerRoots = fingerRoots; }
void setHandPositions(const std::vector<glm::vec3>& handPositons) { _handPositions = handPositons; }
void setHandNormals(const std::vector<glm::vec3>& handNormals) { _handNormals = handNormals; }
// position conversion
glm::vec3 leapPositionToWorldPosition(const glm::vec3& leapPosition) {
const float unitScale = 0.001; // convert mm to meters
return _basePosition + _baseOrientation * (leapPosition * unitScale);
}
glm::vec3 leapDirectionToWorldDirection(const glm::vec3& leapDirection) {
return glm::normalize(_baseOrientation * leapDirection);
}
std::vector<PalmData>& getPalms() { return _palms; }
size_t getNumPalms() { return _palms.size(); }
// Use these for sending and receiving hand data
void encodeRemoteData(std::vector<glm::vec3>& fingerVectors);
void decodeRemoteData(const std::vector<glm::vec3>& fingerVectors);
friend class AvatarData;
protected:
std::vector<glm::vec3> _fingerTips;
std::vector<glm::vec3> _fingerRoots;
std::vector<glm::vec3> _handPositions;
std::vector<glm::vec3> _handNormals;
glm::vec3 _basePosition; // Hands are placed relative to this
glm::quat _baseOrientation; // Hands are placed relative to this
AvatarData* _owningAvatarData;
std::vector<PalmData> _palms;
private:
// privatize copy ctor and assignment operator so copies of this object cannot be made
HandData(const HandData&);
HandData& operator= (const HandData&);
};
class FingerData {
public:
FingerData(PalmData* owningPalmData, HandData* owningHandData);
glm::vec3 getTipPosition() const { return _owningHandData->leapPositionToWorldPosition(_tipRawPosition); }
glm::vec3 getRootPosition() const { return _owningHandData->leapPositionToWorldPosition(_rootRawPosition); }
const glm::vec3& getTipRawPosition() const { return _tipRawPosition; }
const glm::vec3& getRootRawPosition() const { return _rootRawPosition; }
bool isActive() const { return _isActive; }
void setActive(bool active) { _isActive = active; }
void setRawTipPosition(const glm::vec3& pos) { _tipRawPosition = pos; }
void setRawRootPosition(const glm::vec3& pos) { _rootRawPosition = pos; }
private:
glm::vec3 _tipRawPosition;
glm::vec3 _rootRawPosition;
bool _isActive; // This has current valid data
PalmData* _owningPalmData;
HandData* _owningHandData;
};
class PalmData {
public:
PalmData(HandData* owningHandData);
glm::vec3 getPosition() const { return _owningHandData->leapPositionToWorldPosition(_rawPosition); }
glm::vec3 getNormal() const { return _owningHandData->leapDirectionToWorldDirection(_rawNormal); }
const glm::vec3& getRawPosition() const { return _rawPosition; }
const glm::vec3& getRawNormal() const { return _rawNormal; }
bool isActive() const { return _isActive; }
std::vector<FingerData>& getFingers() { return _fingers; }
size_t getNumFingers() { return _fingers.size(); }
void setActive(bool active) { _isActive = active; }
void setRawPosition(const glm::vec3& pos) { _rawPosition = pos; }
void setRawNormal(const glm::vec3& normal) { _rawNormal = normal; }
private:
std::vector<FingerData> _fingers;
glm::vec3 _rawPosition;
glm::vec3 _rawNormal;
bool _isActive; // This has current valid data
HandData* _owningHandData;
};
#endif /* defined(__hifi__HandData__) */

View file

@ -1,14 +1,13 @@
cmake_minimum_required(VERSION 2.8)
set(ROOT_DIR ../..)
set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
set(TARGET_NAME shared)
project(${TARGET_NAME})
# grab the implemenation and header files
file(GLOB HIFI_SHARED_SRCS src/*.h src/*.cpp)
# create a library and set the property so it can be referenced later
add_library(${TARGET_NAME} ${HIFI_SHARED_SRCS})
set(HIFI_SHARED_LIBRARY ${TARGET_NAME})
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
setup_hifi_library(${TARGET_NAME})
set(EXTERNAL_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external)

View file

@ -1,15 +0,0 @@
//
// Log.cpp
// hifi
//
// Created by Tobias Schwinger on 4/17/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include "Log.h"
#include <cstdio>
using namespace std;
int (* printLog)(char const*, ...) = & printf;

View file

@ -1,21 +0,0 @@
//
// Log.h
// hifi
//
// Created by Tobias Schwinger on 4/17/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __hifi__shared_Log__
#define __hifi__shared_Log__
//
// Pointer to log function
//
// An application may reset this variable to receive the log messages
// issued using 'printLog'. It defaults to a pointer to 'printf'.
//
extern int (* printLog)(char const*, ...);
#endif /* defined(__hifi__shared_Log__) */

View file

@ -6,15 +6,9 @@
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include "stdio.h"
#include <pthread.h>
#include "Node.h"
#include "NodeTypes.h"
#include <cstring>
#include "Log.h"
#include "UDPSocket.h"
#include "SharedUtil.h"
#include <pthread.h>
#include <stdio.h>
#ifdef _WIN32
#include "Syssocket.h"
@ -22,6 +16,13 @@
#include <arpa/inet.h>
#endif
#include "Node.h"
#include "NodeTypes.h"
#include "SharedUtil.h"
#include "UDPSocket.h"
#include <QDebug>
int unpackNodeId(unsigned char* packedData, uint16_t* nodeId) {
memcpy(nodeId, packedData, sizeof(uint16_t));
return sizeof(uint16_t);
@ -140,18 +141,14 @@ float Node::getAverageKilobitsPerSecond() {
}
}
void Node::printLog(Node const& node) {
QDebug operator<<(QDebug debug, const Node &node) {
char publicAddressBuffer[16] = {'\0'};
unsigned short publicAddressPort = loadBufferWithSocketInfo(publicAddressBuffer, node._publicSocket);
unsigned short publicAddressPort = loadBufferWithSocketInfo(publicAddressBuffer, node.getPublicSocket());
//char localAddressBuffer[16] = {'\0'};
//unsigned short localAddressPort = loadBufferWithSocketInfo(localAddressBuffer, node.localSocket);
::printLog("# %d %s (%c) @ %s:%d\n",
node._nodeID,
node.getTypeName(),
node._type,
publicAddressBuffer,
publicAddressPort);
debug << "#" << node.getNodeID() << node.getTypeName() << node.getType();
debug.nospace() << publicAddressBuffer << ":" << publicAddressPort;
return debug.nospace();
}

View file

@ -9,8 +9,8 @@
#ifndef __hifi__Node__
#define __hifi__Node__
#include <stdint.h>
#include <ostream>
#include <stdint.h>
#ifdef _WIN32
#include "Syssocket.h"
@ -18,8 +18,10 @@
#include <sys/socket.h>
#endif
#include "SimpleMovingAverage.h"
#include <QDebug>
#include "NodeData.h"
#include "SimpleMovingAverage.h"
class Node {
public:
@ -89,8 +91,9 @@ private:
pthread_mutex_t _mutex;
};
int unpackNodeId(unsigned char *packedData, uint16_t *nodeId);
int packNodeId(unsigned char *packStore, uint16_t nodeId);
QDebug operator<<(QDebug debug, const Node &message);
#endif /* defined(__hifi__Node__) */

View file

@ -11,11 +11,12 @@
#include <cstdlib>
#include <cstdio>
#include <QDebug>
#include "NodeList.h"
#include "NodeTypes.h"
#include "PacketHeaders.h"
#include "SharedUtil.h"
#include "Log.h"
#ifdef _WIN32
#include "Syssocket.h"
@ -42,7 +43,7 @@ NodeList* NodeList::createInstance(char ownerType, unsigned int socketListenPort
if (!_sharedInstance) {
_sharedInstance = new NodeList(ownerType, socketListenPort);
} else {
printLog("NodeList createInstance called with existing instance.\n");
qDebug("NodeList createInstance called with existing instance.\n");
}
return _sharedInstance;
@ -50,7 +51,7 @@ NodeList* NodeList::createInstance(char ownerType, unsigned int socketListenPort
NodeList* NodeList::getInstance() {
if (!_sharedInstance) {
printLog("NodeList getInstance called before call to createInstance. Returning NULL pointer.\n");
qDebug("NodeList getInstance called before call to createInstance. Returning NULL pointer.\n");
}
return _sharedInstance;
@ -274,12 +275,13 @@ void NodeList::sendDomainServerCheckIn() {
sockaddr_in tempAddress;
memcpy(&tempAddress.sin_addr, pHostInfo->h_addr_list[0], pHostInfo->h_length);
strcpy(_domainIP, inet_ntoa(tempAddress.sin_addr));
printLog("Domain Server: %s \n", _domainHostname);
qDebug("Domain Server: %s\n", _domainHostname);
} else {
printLog("Failed domain server lookup\n");
qDebug("Failed domain server lookup\n");
}
} else if (!printedDomainServerIP) {
printLog("Domain Server IP: %s\n", _domainIP);
qDebug("Domain Server IP: %s\n", _domainIP);
printedDomainServerIP = true;
}
@ -418,8 +420,7 @@ void NodeList::addNodeToList(Node* newNode) {
++_numNodes;
printLog("Added ");
Node::printLog(*newNode);
qDebug() << "Added" << *newNode << "\n";
}
unsigned NodeList::broadcastToNodes(unsigned char *broadcastData, size_t dataBytes, const char* nodeTypes, int numNodeTypes) {
@ -471,11 +472,9 @@ void *removeSilentNodes(void *args) {
for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); ++node) {
if ((checkTimeUSecs - node->getLastHeardMicrostamp()) > NODE_SILENCE_THRESHOLD_USECS
&& node->getType() != NODE_TYPE_VOXEL_SERVER) {
if ((checkTimeUSecs - node->getLastHeardMicrostamp()) > NODE_SILENCE_THRESHOLD_USECS) {
printLog("Killed ");
Node::printLog(*node);
qDebug() << "Killed" << *node << "\n";
node->setAlive(false);
}

View file

@ -32,7 +32,7 @@ const int DOMAIN_SERVER_CHECK_IN_USECS = 1 * 1000000;
extern const char SOLO_NODE_TYPES[3];
const int MAX_HOSTNAME_BYTES = 255;
const int MAX_HOSTNAME_BYTES = 256;
extern const char DEFAULT_DOMAIN_HOSTNAME[MAX_HOSTNAME_BYTES];
extern const char DEFAULT_DOMAIN_IP[INET_ADDRSTRLEN]; // IP Address will be re-set by lookup on startup

View file

@ -6,14 +6,18 @@
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
//
#include <cmath>
#include <algorithm> // std:min
#include <cassert>
#include <cmath>
#include <cstring>
#include <QDebug>
#include "SharedUtil.h"
#include "OctalCode.h"
#include "Log.h"
int numberOfThreeBitSectionsInCode(unsigned char * octalCode) {
assert(octalCode);
if (*octalCode == 255) {
return *octalCode + numberOfThreeBitSectionsInCode(octalCode + 1);
} else {
@ -23,12 +27,12 @@ int numberOfThreeBitSectionsInCode(unsigned char * octalCode) {
void printOctalCode(unsigned char * octalCode) {
if (!octalCode) {
printLog("NULL\n");
qDebug("NULL\n");
} else {
for (int i = 0; i < bytesRequiredForCodeLength(*octalCode); i++) {
outputBits(octalCode[i],false);
}
printLog("\n");
qDebug("\n");
}
}

View file

@ -8,13 +8,14 @@
#include <stdio.h>
#include <QDebug>
#include "PacketHeaders.h"
#include "Log.h"
PACKET_VERSION versionForPacketType(PACKET_TYPE type) {
switch (type) {
case PACKET_TYPE_HEAD_DATA:
return 1;
return 2;
break;
default:
return 0;
@ -28,7 +29,7 @@ bool packetVersionMatch(unsigned char* packetHeader) {
if (packetHeader[1] == versionForPacketType(packetHeader[0])) {
return true;
} else {
printLog("There is a packet version mismatch for packet with header %c\n", packetHeader[0]);
qDebug("There is a packet version mismatch for packet with header %c\n", packetHeader[0]);
return false;
}
}

View file

@ -10,12 +10,13 @@
//
//
#include "PerfStat.h"
#include <cstdio>
#include <string>
#include <map>
#include <string>
#include "Log.h"
#include <QDebug>
#include "PerfStat.h"
// Static class members initialization here!
std::map<std::string,PerfStatHistory,std::less<std::string> > PerfStat::groupHistoryMap;
@ -58,11 +59,11 @@ PerfStat::~PerfStat() {
}
if (wantDebugOut) {
printLog("PerfStats: %s elapsed:%f average:%lf count:%ld total:%lf ut:%d us:%d ue:%d t:%ld s:%ld e:%ld\n",
this->group.c_str(),elapsed,average,count,totalTime,
(end.tv_usec-start.tv_usec),start.tv_usec,end.tv_usec,
(end.tv_sec-start.tv_sec),start.tv_sec,end.tv_sec
);
qDebug("PerfStats: %s elapsed:%f average:%lf count:%ld total:%lf ut:%d us:%d ue:%d t:%ld s:%ld e:%ld\n",
this->group.c_str(),elapsed,average,count,totalTime,
(end.tv_usec-start.tv_usec),start.tv_usec,end.tv_usec,
(end.tv_sec-start.tv_sec),start.tv_sec,end.tv_sec
);
}
};
@ -110,12 +111,12 @@ PerformanceWarning::~PerformanceWarning() {
if ((_alwaysDisplay || _renderWarningsOn) && elapsedmsec > 1) {
if (elapsedmsec > 1000) {
double elapsedsec = (end - _start) / 1000000.0;
printLog("%s%s took %lf seconds\n", (_alwaysDisplay ? "" : "WARNING!"), _message, elapsedsec);
qDebug("%s%s took %lf seconds\n", (_alwaysDisplay ? "" : "WARNING!"), _message, elapsedsec);
} else {
printLog("%s%s took %lf milliseconds\n", (_alwaysDisplay ? "" : "WARNING!"), _message, elapsedmsec);
qDebug("%s%s took %lf milliseconds\n", (_alwaysDisplay ? "" : "WARNING!"), _message, elapsedmsec);
}
} else if (_alwaysDisplay) {
printLog("%s took %lf milliseconds\n", _message, elapsedmsec);
qDebug("%s took %lf milliseconds\n", _message, elapsedmsec);
}
};

View file

@ -20,7 +20,8 @@
#include <CoreFoundation/CoreFoundation.h>
#endif
#include "Log.h"
#include <QDebug>
#include "OctalCode.h"
#include "PacketHeaders.h"
#include "SharedUtil.h"
@ -64,24 +65,24 @@ void outputBufferBits(unsigned char* buffer, int length, bool withNewLine) {
outputBits(buffer[i], false);
}
if (withNewLine) {
printLog("\n");
qDebug("\n");
}
}
void outputBits(unsigned char byte, bool withNewLine) {
if (isalnum(byte)) {
printLog("[ %d (%c): ", byte, byte);
qDebug("[ %d (%c): ", byte, byte);
} else {
printLog("[ %d (0x%x): ", byte, byte);
qDebug("[ %d (0x%x): ", byte, byte);
}
for (int i = 0; i < 8; i++) {
printLog("%d", byte >> (7 - i) & 1);
qDebug("%d", byte >> (7 - i) & 1);
}
printLog(" ] ");
qDebug(" ] ");
if (withNewLine) {
printLog("\n");
qDebug("\n");
}
}
@ -187,6 +188,10 @@ bool cmdOptionExists(int argc, const char * argv[],const char* option) {
return false;
}
void sharedMessageHandler(QtMsgType type, const char* message) {
fprintf(stdout, "%s", message);
}
//////////////////////////////////////////////////////////////////////////////////////////
// Function: createVoxelEditMessage()
// Description: creates an "insert" or "remove" voxel message for a voxel code
@ -385,14 +390,14 @@ void printVoxelCode(unsigned char* voxelCode) {
unsigned int voxelSizeInOctets = (voxelSizeInBits/3);
unsigned int voxelBufferSize = voxelSizeInBytes+1+3; // 1 for size, 3 for color
printLog("octets=%d\n",octets);
printLog("voxelSizeInBits=%d\n",voxelSizeInBits);
printLog("voxelSizeInBytes=%d\n",voxelSizeInBytes);
printLog("voxelSizeInOctets=%d\n",voxelSizeInOctets);
printLog("voxelBufferSize=%d\n",voxelBufferSize);
qDebug("octets=%d\n",octets);
qDebug("voxelSizeInBits=%d\n",voxelSizeInBits);
qDebug("voxelSizeInBytes=%d\n",voxelSizeInBytes);
qDebug("voxelSizeInOctets=%d\n",voxelSizeInOctets);
qDebug("voxelBufferSize=%d\n",voxelBufferSize);
for(int i=0;i<voxelBufferSize;i++) {
printLog("i=%d ",i);
qDebug("i=%d ",i);
outputBits(voxelCode[i]);
}
}

View file

@ -9,9 +9,11 @@
#ifndef __hifi__SharedUtil__
#define __hifi__SharedUtil__
#include <math.h>
#include <stdint.h>
#include <unistd.h>
#include <math.h>
#include <QDebug>
#ifdef _WIN32
#include "Systime.h"
@ -66,6 +68,8 @@ void loadRandomIdentifier(unsigned char* identifierBuffer, int numBytes);
const char* getCmdOption(int argc, const char * argv[],const char* option);
bool cmdOptionExists(int argc, const char * argv[],const char* option);
void sharedMessageHandler(QtMsgType type, const char* message);
struct VoxelDetail {
float x;
float y;

View file

@ -6,10 +6,9 @@
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include "UDPSocket.h"
#include <fcntl.h>
#include <cstdio>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#ifdef _WIN32
@ -21,7 +20,9 @@
#include <unistd.h>
#endif
#include "Log.h"
#include <QDebug>
#include "UDPSocket.h"
sockaddr_in destSockaddr, senderAddress;
@ -123,7 +124,7 @@ UDPSocket::UDPSocket(int listeningPort) : listeningPort(listeningPort), blocking
handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (handle <= 0) {
printLog("Failed to create socket.\n");
qDebug("Failed to create socket.\n");
return;
}
@ -136,7 +137,7 @@ UDPSocket::UDPSocket(int listeningPort) : listeningPort(listeningPort), blocking
bind_address.sin_port = htons((uint16_t) listeningPort);
if (bind(handle, (const sockaddr*) &bind_address, sizeof(sockaddr_in)) < 0) {
printLog("Failed to bind socket to port %d.\n", listeningPort);
qDebug("Failed to bind socket to port %d.\n", listeningPort);
return;
}
@ -153,7 +154,7 @@ UDPSocket::UDPSocket(int listeningPort) : listeningPort(listeningPort), blocking
tv.tv_usec = 500000;
setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv);
printLog("Created UDP socket listening on port %d.\n", listeningPort);
qDebug("Created UDP socket listening on port %d.\n", listeningPort);
}
UDPSocket::~UDPSocket() {
@ -233,7 +234,7 @@ int UDPSocket::send(sockaddr* destAddress, const void* data, size_t byteLength)
0, (sockaddr *) destAddress, sizeof(sockaddr_in));
if (sent_bytes != byteLength) {
printLog("Failed to send packet: %s\n", strerror(errno));
qDebug("Failed to send packet: %s\n", strerror(errno));
return false;
}

View file

@ -6,20 +6,17 @@
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include "UrlReader.h"
#include <new>
#include <sys/types.h>
#include <sys/stat.h>
#include "Log.h"
#ifndef _WIN32
// (Windows port is incomplete and the build files do not support CURL, yet)
#include <curl/curl.h>
#include "UrlReader.h"
//
// ATTENTION: A certain part of the implementation lives in inlined code

View file

@ -6,10 +6,13 @@
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include "CoverageMap.h"
#include <SharedUtil.h>
#include <cstring>
#include "Log.h"
#include <QDebug>
#include <SharedUtil.h>
#include "CoverageMap.h"
int CoverageMap::_mapCount = 0;
int CoverageMap::_checkMapRootCalls = 0;
@ -60,7 +63,7 @@ CoverageMap::CoverageMap(BoundingBox boundingBox, bool isRoot, bool managePolygo
{
_mapCount++;
init();
//printLog("CoverageMap created... _mapCount=%d\n",_mapCount);
//qDebug("CoverageMap created... _mapCount=%d\n",_mapCount);
};
CoverageMap::~CoverageMap() {
@ -68,19 +71,19 @@ CoverageMap::~CoverageMap() {
};
void CoverageMap::printStats() {
printLog("CoverageMap::printStats()...\n");
printLog("MINIMUM_POLYGON_AREA_TO_STORE=%f\n",MINIMUM_POLYGON_AREA_TO_STORE);
printLog("_mapCount=%d\n",_mapCount);
printLog("_checkMapRootCalls=%d\n",_checkMapRootCalls);
printLog("_notAllInView=%d\n",_notAllInView);
printLog("_maxPolygonsUsed=%d\n",CoverageRegion::_maxPolygonsUsed);
printLog("_totalPolygons=%d\n",CoverageRegion::_totalPolygons);
printLog("_occlusionTests=%d\n",CoverageRegion::_occlusionTests);
printLog("_regionSkips=%d\n",CoverageRegion::_regionSkips);
printLog("_tooSmallSkips=%d\n",CoverageRegion::_tooSmallSkips);
printLog("_regionFullSkips=%d\n",CoverageRegion::_regionFullSkips);
printLog("_outOfOrderPolygon=%d\n",CoverageRegion::_outOfOrderPolygon);
printLog("_clippedPolygons=%d\n",CoverageRegion::_clippedPolygons);
qDebug("CoverageMap::printStats()...\n");
qDebug("MINIMUM_POLYGON_AREA_TO_STORE=%f\n",MINIMUM_POLYGON_AREA_TO_STORE);
qDebug("_mapCount=%d\n",_mapCount);
qDebug("_checkMapRootCalls=%d\n",_checkMapRootCalls);
qDebug("_notAllInView=%d\n",_notAllInView);
qDebug("_maxPolygonsUsed=%d\n",CoverageRegion::_maxPolygonsUsed);
qDebug("_totalPolygons=%d\n",CoverageRegion::_totalPolygons);
qDebug("_occlusionTests=%d\n",CoverageRegion::_occlusionTests);
qDebug("_regionSkips=%d\n",CoverageRegion::_regionSkips);
qDebug("_tooSmallSkips=%d\n",CoverageRegion::_tooSmallSkips);
qDebug("_regionFullSkips=%d\n",CoverageRegion::_regionFullSkips);
qDebug("_outOfOrderPolygon=%d\n",CoverageRegion::_outOfOrderPolygon);
qDebug("_clippedPolygons=%d\n",CoverageRegion::_clippedPolygons);
}
void CoverageMap::erase() {
@ -99,7 +102,7 @@ void CoverageMap::erase() {
}
if (_isRoot && wantDebugging) {
printLog("CoverageMap last to be deleted...\n");
qDebug("CoverageMap last to be deleted...\n");
printStats();
CoverageRegion::_maxPolygonsUsed = 0;
@ -184,7 +187,7 @@ CoverageMapStorageResult CoverageMap::checkMap(VoxelProjectedPolygon* polygon, b
if (_isRoot) {
_checkMapRootCalls++;
//printLog("CoverageMap::checkMap()... storeIt=%s\n", debug::valueOf(storeIt));
//qDebug("CoverageMap::checkMap()... storeIt=%s\n", debug::valueOf(storeIt));
//polygon->printDebugDetails();
}
@ -193,7 +196,7 @@ CoverageMapStorageResult CoverageMap::checkMap(VoxelProjectedPolygon* polygon, b
// not in view, then we just discard it with a DOESNT_FIT, this saves us time checking values later.
if (!polygon->getAllInView()) {
_notAllInView++;
//printLog("CoverageMap2::checkMap()... V2_OCCLUDED\n");
//qDebug("CoverageMap2::checkMap()... V2_OCCLUDED\n");
return DOESNT_FIT;
}
@ -240,9 +243,9 @@ CoverageMapStorageResult CoverageMap::checkMap(VoxelProjectedPolygon* polygon, b
/*
if (result == STORED)
printLog("CoverageMap2::checkMap()... STORED\n");
qDebug("CoverageMap2::checkMap()... STORED\n");
else
printLog("CoverageMap2::checkMap()... OCCLUDED\n");
qDebug("CoverageMap2::checkMap()... OCCLUDED\n");
*/
return result;
@ -265,16 +268,16 @@ CoverageMapStorageResult CoverageMap::checkMap(VoxelProjectedPolygon* polygon, b
/*
switch (result) {
case STORED:
printLog("checkMap() = STORED\n");
qDebug("checkMap() = STORED\n");
break;
case NOT_STORED:
printLog("checkMap() = NOT_STORED\n");
qDebug("checkMap() = NOT_STORED\n");
break;
case OCCLUDED:
printLog("checkMap() = OCCLUDED\n");
qDebug("checkMap() = OCCLUDED\n");
break;
default:
printLog("checkMap() = ????? \n");
qDebug("checkMap() = ????? \n");
break;
}
*/
@ -287,27 +290,27 @@ CoverageMapStorageResult CoverageMap::checkMap(VoxelProjectedPolygon* polygon, b
// any of our child bounding boxes, so we should add it here.
if (storeIt) {
if (polygon->getBoundingBox().area() > CoverageMap::MINIMUM_POLYGON_AREA_TO_STORE) {
//printLog("storing polygon of area: %f\n",polygon->getBoundingBox().area());
//qDebug("storing polygon of area: %f\n",polygon->getBoundingBox().area());
if (storeIn->getPolygonCount() < MAX_POLYGONS_PER_REGION) {
storeIn->storeInArray(polygon);
//printLog("CoverageMap2::checkMap()... STORED\n");
//qDebug("CoverageMap2::checkMap()... STORED\n");
return STORED;
} else {
CoverageRegion::_regionFullSkips++;
//printLog("CoverageMap2::checkMap()... NOT_STORED\n");
//qDebug("CoverageMap2::checkMap()... NOT_STORED\n");
return NOT_STORED;
}
} else {
CoverageRegion::_tooSmallSkips++;
//printLog("CoverageMap2::checkMap()... NOT_STORED\n");
//qDebug("CoverageMap2::checkMap()... NOT_STORED\n");
return NOT_STORED;
}
} else {
//printLog("CoverageMap2::checkMap()... NOT_STORED\n");
//qDebug("CoverageMap2::checkMap()... NOT_STORED\n");
return NOT_STORED;
}
}
//printLog("CoverageMap2::checkMap()... DOESNT_FIT\n");
//qDebug("CoverageMap2::checkMap()... DOESNT_FIT\n");
return DOESNT_FIT;
}
@ -338,11 +341,11 @@ void CoverageRegion::erase() {
/**
if (_polygonCount) {
printLog("CoverageRegion::erase()...\n");
printLog("_polygonCount=%d\n",_polygonCount);
qDebug("CoverageRegion::erase()...\n");
qDebug("_polygonCount=%d\n",_polygonCount);
_myBoundingBox.printDebugDetails(getRegionName());
//for (int i = 0; i < _polygonCount; i++) {
// printLog("_polygons[%d]=",i);
// qDebug("_polygons[%d]=",i);
// _polygons[i]->getBoundingBox().printDebugDetails();
//}
}
@ -390,7 +393,7 @@ void CoverageRegion::growPolygonArray() {
_polygonDistances = newDistances;
_polygonSizes = newSizes;
_polygonArraySize = _polygonArraySize + DEFAULT_GROW_SIZE;
//printLog("CoverageMap::growPolygonArray() _polygonArraySize=%d...\n",_polygonArraySize);
//qDebug("CoverageMap::growPolygonArray() _polygonArraySize=%d...\n",_polygonArraySize);
}
const char* CoverageRegion::getRegionName() const {
@ -427,15 +430,15 @@ bool CoverageRegion::mergeItemsInArray(VoxelProjectedPolygon* seed, bool seedInA
otherPolygon->merge(*seed);
if (seedInArray) {
const int IGNORED = NULL;
int* IGNORED_ADDRESS = NULL;
// remove this otherOtherPolygon for our polygon array
_polygonCount = removeFromSortedArrays((void*)seed,
(void**)_polygons, _polygonDistances, IGNORED,
(void**)_polygons, _polygonDistances, IGNORED_ADDRESS,
_polygonCount, _polygonArraySize);
_totalPolygons--;
}
//printLog("_polygonCount=%d\n",_polygonCount);
//qDebug("_polygonCount=%d\n",_polygonCount);
// clean up
if (_managePolygons) {
@ -476,31 +479,31 @@ void CoverageRegion::storeInArray(VoxelProjectedPolygon* polygon) {
// in the list. We still check to see if the polygon is "in front" of the target polygon before we test occlusion. Since
// sometimes things come out of order.
const bool SORT_BY_SIZE = false;
const int IGNORED = NULL;
const int IGNORED = 0;
int* IGNORED_ADDRESS = NULL;
if (SORT_BY_SIZE) {
// This old code assumes that polygons will always be added in z-buffer order, but that doesn't seem to
// be a good assumption. So instead, we will need to sort this by distance. Use a binary search to find the
// insertion point in this array, and shift the array accordingly
float area = polygon->getBoundingBox().area();
float reverseArea = 4.0f - area;
//printLog("store by size area=%f reverse area=%f\n", area, reverseArea);
//qDebug("store by size area=%f reverse area=%f\n", area, reverseArea);
_polygonCount = insertIntoSortedArrays((void*)polygon, reverseArea, IGNORED,
(void**)_polygons, _polygonSizes, IGNORED,
(void**)_polygons, _polygonSizes, IGNORED_ADDRESS,
_polygonCount, _polygonArraySize);
} else {
const int IGNORED = NULL;
_polygonCount = insertIntoSortedArrays((void*)polygon, polygon->getDistance(), IGNORED,
(void**)_polygons, _polygonDistances, IGNORED,
(void**)_polygons, _polygonDistances, IGNORED_ADDRESS,
_polygonCount, _polygonArraySize);
}
// Debugging and Optimization Tuning code.
if (_polygonCount > _maxPolygonsUsed) {
_maxPolygonsUsed = _polygonCount;
//printLog("CoverageRegion new _maxPolygonsUsed reached=%d region=%s\n",_maxPolygonsUsed, getRegionName());
//qDebug("CoverageRegion new _maxPolygonsUsed reached=%d region=%s\n",_maxPolygonsUsed, getRegionName());
//_myBoundingBox.printDebugDetails("map._myBoundingBox");
} else {
//printLog("CoverageRegion::storeInArray() _polygonCount=%d region=%s\n",_polygonCount, getRegionName());
//qDebug("CoverageRegion::storeInArray() _polygonCount=%d region=%s\n",_polygonCount, getRegionName());
}
}

View file

@ -7,11 +7,13 @@
//
#include <algorithm>
#include <cstring>
#include <QDebug>
#include <SharedUtil.h>
#include "CoverageMapV2.h"
#include <SharedUtil.h>
#include <cstring>
#include "Log.h"
int CoverageMapV2::_mapCount = 0;
int CoverageMapV2::_checkMapRootCalls = 0;
@ -59,7 +61,7 @@ CoverageMapV2::CoverageMapV2(BoundingBox boundingBox, bool isRoot, bool isCovere
{
_mapCount++;
init();
//printLog("CoverageMapV2 created... _mapCount=%d\n",_mapCount);
//qDebug("CoverageMapV2 created... _mapCount=%d\n",_mapCount);
};
CoverageMapV2::~CoverageMapV2() {
@ -76,11 +78,11 @@ void CoverageMapV2::erase() {
}
if (_isRoot && wantDebugging) {
printLog("CoverageMapV2 last to be deleted...\n");
printLog("MINIMUM_POLYGON_AREA_TO_STORE=%f\n",MINIMUM_POLYGON_AREA_TO_STORE);
printLog("_mapCount=%d\n",_mapCount);
printLog("_checkMapRootCalls=%d\n",_checkMapRootCalls);
printLog("_notAllInView=%d\n",_notAllInView);
qDebug("CoverageMapV2 last to be deleted...\n");
qDebug("MINIMUM_POLYGON_AREA_TO_STORE=%f\n",MINIMUM_POLYGON_AREA_TO_STORE);
qDebug("_mapCount=%d\n",_mapCount);
qDebug("_checkMapRootCalls=%d\n",_checkMapRootCalls);
qDebug("_notAllInView=%d\n",_notAllInView);
_mapCount = 0;
_checkMapRootCalls = 0;
_notAllInView = 0;

View file

@ -7,7 +7,8 @@
#include <cstring>
#include <Log.h>
#include <QDebug>
#include <SharedUtil.h>
#include "GeometryUtil.h"

View file

@ -12,8 +12,6 @@
#include <stdio.h>
#include "Log.h"
// These are some useful utilities that vec3 is missing
void printVec3(const char* name, const glm::vec3& v) {
printf("%s x=%f y=%f z=%f\n", name, v.x, v.y, v.z);

View file

@ -6,14 +6,13 @@
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include "Tags.h"
#include <Log.h>
#include <zlib.h>
#include <zconf.h>
#include <iostream>
#include <zconf.h>
#include <zlib.h>
#include "Tags.h"
Tag::Tag(int tagId, std::stringstream &ss) : _tagId(tagId) {
int size = ss.get() << 8 | ss.get();

View file

@ -3,24 +3,23 @@
// hifi
//
// Created by Brad Hefta-Gaub on 04/11/13.
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
//
// Simple view frustum class.
//
//
#include <algorithm>
#include <glm/gtx/transform.hpp>
#include "SharedUtil.h"
#include "Log.h"
#include <QDebug>
#include "CoverageMap.h"
#include "GeometryUtil.h"
#include "SharedUtil.h"
#include "ViewFrustum.h"
#include "VoxelConstants.h"
using namespace std;
ViewFrustum::ViewFrustum() :
@ -323,40 +322,40 @@ bool ViewFrustum::matches(const ViewFrustum& compareTo, bool debug) const {
testMatches(compareTo._eyeOffsetOrientation, _eyeOffsetOrientation);
if (!result && debug) {
printLog("ViewFrustum::matches()... result=%s\n", debug::valueOf(result));
printLog("%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f\n",
qDebug("ViewFrustum::matches()... result=%s\n", debug::valueOf(result));
qDebug("%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f\n",
(testMatches(compareTo._position,_position) ? "MATCHES " : "NO MATCH"),
compareTo._position.x, compareTo._position.y, compareTo._position.z,
_position.x, _position.y, _position.z );
printLog("%s -- compareTo._direction=%f,%f,%f _direction=%f,%f,%f\n",
qDebug("%s -- compareTo._direction=%f,%f,%f _direction=%f,%f,%f\n",
(testMatches(compareTo._direction, _direction) ? "MATCHES " : "NO MATCH"),
compareTo._direction.x, compareTo._direction.y, compareTo._direction.z,
_direction.x, _direction.y, _direction.z );
printLog("%s -- compareTo._up=%f,%f,%f _up=%f,%f,%f\n",
qDebug("%s -- compareTo._up=%f,%f,%f _up=%f,%f,%f\n",
(testMatches(compareTo._up, _up) ? "MATCHES " : "NO MATCH"),
compareTo._up.x, compareTo._up.y, compareTo._up.z,
_up.x, _up.y, _up.z );
printLog("%s -- compareTo._right=%f,%f,%f _right=%f,%f,%f\n",
qDebug("%s -- compareTo._right=%f,%f,%f _right=%f,%f,%f\n",
(testMatches(compareTo._right, _right) ? "MATCHES " : "NO MATCH"),
compareTo._right.x, compareTo._right.y, compareTo._right.z,
_right.x, _right.y, _right.z );
printLog("%s -- compareTo._fieldOfView=%f _fieldOfView=%f\n",
qDebug("%s -- compareTo._fieldOfView=%f _fieldOfView=%f\n",
(testMatches(compareTo._fieldOfView, _fieldOfView) ? "MATCHES " : "NO MATCH"),
compareTo._fieldOfView, _fieldOfView);
printLog("%s -- compareTo._aspectRatio=%f _aspectRatio=%f\n",
qDebug("%s -- compareTo._aspectRatio=%f _aspectRatio=%f\n",
(testMatches(compareTo._aspectRatio, _aspectRatio) ? "MATCHES " : "NO MATCH"),
compareTo._aspectRatio, _aspectRatio);
printLog("%s -- compareTo._nearClip=%f _nearClip=%f\n",
qDebug("%s -- compareTo._nearClip=%f _nearClip=%f\n",
(testMatches(compareTo._nearClip, _nearClip) ? "MATCHES " : "NO MATCH"),
compareTo._nearClip, _nearClip);
printLog("%s -- compareTo._farClip=%f _farClip=%f\n",
qDebug("%s -- compareTo._farClip=%f _farClip=%f\n",
(testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"),
compareTo._farClip, _farClip);
printLog("%s -- compareTo._eyeOffsetPosition=%f,%f,%f _eyeOffsetPosition=%f,%f,%f\n",
qDebug("%s -- compareTo._eyeOffsetPosition=%f,%f,%f _eyeOffsetPosition=%f,%f,%f\n",
(testMatches(compareTo._eyeOffsetPosition, _eyeOffsetPosition) ? "MATCHES " : "NO MATCH"),
compareTo._eyeOffsetPosition.x, compareTo._eyeOffsetPosition.y, compareTo._eyeOffsetPosition.z,
_eyeOffsetPosition.x, _eyeOffsetPosition.y, _eyeOffsetPosition.z);
printLog("%s -- compareTo._eyeOffsetOrientation=%f,%f,%f,%f _eyeOffsetOrientation=%f,%f,%f,%f\n",
qDebug("%s -- compareTo._eyeOffsetOrientation=%f,%f,%f,%f _eyeOffsetOrientation=%f,%f,%f,%f\n",
(testMatches(compareTo._eyeOffsetOrientation, _eyeOffsetOrientation) ? "MATCHES " : "NO MATCH"),
compareTo._eyeOffsetOrientation.x, compareTo._eyeOffsetOrientation.y,
compareTo._eyeOffsetOrientation.z, compareTo._eyeOffsetOrientation.w,
@ -419,17 +418,17 @@ void ViewFrustum::computeOffAxisFrustum(float& left, float& right, float& bottom
}
void ViewFrustum::printDebugDetails() const {
printLog("ViewFrustum::printDebugDetails()... \n");
printLog("_position=%f,%f,%f\n", _position.x, _position.y, _position.z );
printLog("_direction=%f,%f,%f\n", _direction.x, _direction.y, _direction.z );
printLog("_up=%f,%f,%f\n", _up.x, _up.y, _up.z );
printLog("_right=%f,%f,%f\n", _right.x, _right.y, _right.z );
printLog("_fieldOfView=%f\n", _fieldOfView);
printLog("_aspectRatio=%f\n", _aspectRatio);
printLog("_nearClip=%f\n", _nearClip);
printLog("_farClip=%f\n", _farClip);
printLog("_eyeOffsetPosition=%f,%f,%f\n", _eyeOffsetPosition.x, _eyeOffsetPosition.y, _eyeOffsetPosition.z );
printLog("_eyeOffsetOrientation=%f,%f,%f,%f\n", _eyeOffsetOrientation.x, _eyeOffsetOrientation.y, _eyeOffsetOrientation.z,
qDebug("ViewFrustum::printDebugDetails()... \n");
qDebug("_position=%f,%f,%f\n", _position.x, _position.y, _position.z );
qDebug("_direction=%f,%f,%f\n", _direction.x, _direction.y, _direction.z );
qDebug("_up=%f,%f,%f\n", _up.x, _up.y, _up.z );
qDebug("_right=%f,%f,%f\n", _right.x, _right.y, _right.z );
qDebug("_fieldOfView=%f\n", _fieldOfView);
qDebug("_aspectRatio=%f\n", _aspectRatio);
qDebug("_nearClip=%f\n", _nearClip);
qDebug("_farClip=%f\n", _farClip);
qDebug("_eyeOffsetPosition=%f,%f,%f\n", _eyeOffsetPosition.x, _eyeOffsetPosition.y, _eyeOffsetPosition.z );
qDebug("_eyeOffsetOrientation=%f,%f,%f,%f\n", _eyeOffsetOrientation.x, _eyeOffsetOrientation.y, _eyeOffsetOrientation.z,
_eyeOffsetOrientation.w );
}

View file

@ -3,18 +3,20 @@
// hifi
//
// Created by Brad Hefta-Gaub on 04/11/13.
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
//
// Simple view frustum class.
//
//
#ifndef __hifi__ViewFrustum__
#define __hifi__ViewFrustum__
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include "Plane.h"
#include "AABox.h"
#include "Plane.h"
#include "VoxelProjectedPolygon.h"
const float DEFAULT_KEYHOLE_RADIUS = 3.0f;
@ -135,7 +137,7 @@ private:
glm::vec3 _nearBottomLeft;
glm::vec3 _nearBottomRight;
enum { TOP_PLANE = 0, BOTTOM_PLANE, LEFT_PLANE, RIGHT_PLANE, NEAR_PLANE, FAR_PLANE };
Plane _planes[6]; // How will this be used?
::Plane _planes[6]; // How will this be used?
const char* debugPlaneName (int plane) const;

View file

@ -21,8 +21,10 @@ 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);
const bool LOW_RES_MONO = false; // while in "low res mode" do voxels switch to monochrome
const uint64_t CHANGE_FUDGE = 1000 * 200; // useconds of fudge in determining if we want to resend changed voxels
const int TREE_SCALE = 128;
const int TREE_SCALE = 128; // This is the number of meters of the 0.0 to 1.0 voxel universe
const float VOXEL_SIZE_SCALE = 50000.0f; // This controls the LOD bigger will make smaller voxels visible at greater distance
const int NUMBER_OF_CHILDREN = 8;
const int MAX_VOXEL_PACKET_SIZE = 1492;
@ -39,4 +41,4 @@ const glBufferIndex GLBUFFER_INDEX_UNKNOWN = ULONG_MAX;
const float SIXTY_FPS_IN_MILLISECONDS = 1000.0f / 60.0f;
const float VIEW_CULLING_RATE_IN_MILLISECONDS = 1000.0f; // once a second is fine
#endif
#endif

View file

@ -3,19 +3,21 @@
// hifi
//
// Created by Stephen Birarda on 3/13/13.
//
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
//
#include <stdio.h>
#include <cmath>
#include <cstring>
#include <stdio.h>
#include <QDebug>
#include "AABox.h"
#include "OctalCode.h"
#include "SharedUtil.h"
#include "Log.h"
#include "VoxelConstants.h"
#include "VoxelNode.h"
#include "VoxelTree.h"
#include "VoxelConstants.h"
#include "OctalCode.h"
#include "AABox.h"
VoxelNode::VoxelNode() {
unsigned char* rootCode = new unsigned char[1];
@ -52,6 +54,8 @@ void VoxelNode::init(unsigned char * octalCode) {
}
VoxelNode::~VoxelNode() {
notifyDeleteHooks();
delete[] _octalCode;
// delete all of this node's children
@ -257,7 +261,7 @@ bool VoxelNode::collapseIdenticalLeaves() {
// if no child, child isn't a leaf, or child doesn't have a color
if (!_children[i] || _children[i]->isStagedForDeletion() || !_children[i]->isLeaf() || !_children[i]->isColored()) {
allChildrenMatch=false;
//printLog("SADNESS child missing or not colored! i=%d\n",i);
//qDebug("SADNESS child missing or not colored! i=%d\n",i);
break;
} else {
if (i==0) {
@ -274,7 +278,7 @@ bool VoxelNode::collapseIdenticalLeaves() {
if (allChildrenMatch) {
//printLog("allChildrenMatch: pruning tree\n");
//qDebug("allChildrenMatch: pruning tree\n");
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
delete _children[i]; // delete all the child nodes
_children[i]=NULL; // set it to NULL
@ -308,13 +312,13 @@ void VoxelNode::printDebugDetails(const char* label) const {
}
}
printLog("%s - Voxel at corner=(%f,%f,%f) size=%f\n isLeaf=%s isColored=%s (%d,%d,%d,%d) isDirty=%s shouldRender=%s\n children=", label,
qDebug("%s - Voxel at corner=(%f,%f,%f) size=%f\n isLeaf=%s isColored=%s (%d,%d,%d,%d) isDirty=%s shouldRender=%s\n children=", label,
_box.getCorner().x, _box.getCorner().y, _box.getCorner().z, _box.getSize().x,
debug::valueOf(isLeaf()), debug::valueOf(isColored()), getColor()[0], getColor()[1], getColor()[2], getColor()[3],
debug::valueOf(isDirty()), debug::valueOf(getShouldRender()));
outputBits(childBits, false);
printLog("\n octalCode=");
qDebug("\n octalCode=");
printOctalCode(_octalCode);
}
@ -385,3 +389,44 @@ float VoxelNode::distanceToPoint(const glm::vec3& point) const {
float distance = sqrtf(glm::dot(temp, temp));
return distance;
}
VoxelNodeDeleteHook VoxelNode::_hooks[VOXEL_NODE_MAX_DELETE_HOOKS];
void* VoxelNode::_hooksExtraData[VOXEL_NODE_MAX_DELETE_HOOKS];
int VoxelNode::_hooksInUse = 0;
int VoxelNode::addDeleteHook(VoxelNodeDeleteHook hook, void* extraData) {
// If first use, initialize the _hooks array
if (_hooksInUse == 0) {
memset(_hooks, 0, sizeof(_hooks));
memset(_hooksExtraData, 0, sizeof(_hooksExtraData));
}
// find first available slot
for (int i = 0; i < VOXEL_NODE_MAX_DELETE_HOOKS; i++) {
if (!_hooks[i]) {
_hooks[i] = hook;
_hooksExtraData[i] = extraData;
_hooksInUse++;
return i;
}
}
// if we got here, then we're out of room in our hooks, return error
return VOXEL_NODE_NO_MORE_HOOKS_AVAILABLE;
}
void VoxelNode::removeDeleteHook(int hookID) {
if (_hooks[hookID]) {
_hooks[hookID] = NULL;
_hooksExtraData[hookID] = NULL;
_hooksInUse--;
}
}
void VoxelNode::notifyDeleteHooks() {
if (_hooksInUse > 0) {
for (int i = 0; i < VOXEL_NODE_MAX_DELETE_HOOKS; i++) {
if (_hooks[i]) {
_hooks[i](this, _hooksExtraData[i]);
}
}
}
}

View file

@ -15,33 +15,19 @@
#include "VoxelConstants.h"
class VoxelTree; // forward delclaration
class VoxelNode; // forward delclaration
typedef unsigned char colorPart;
typedef unsigned char nodeColor[4];
typedef unsigned char rgbColor[3];
// Callback function, for delete hook
typedef void (*VoxelNodeDeleteHook)(VoxelNode* node, void* extraData);
const int VOXEL_NODE_MAX_DELETE_HOOKS = 100;
const int VOXEL_NODE_NO_MORE_HOOKS_AVAILABLE = -1;
class VoxelNode {
private:
nodeColor _trueColor;
#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color
nodeColor _currentColor;
bool _falseColored;
#endif
glBufferIndex _glBufferIndex;
bool _isDirty;
uint64_t _lastChanged;
bool _shouldRender;
bool _isStagedForDeletion;
AABox _box;
unsigned char* _octalCode;
VoxelNode* _children[8];
int _childCount;
float _density; // If leaf: density = 1, if internal node: 0-1 density of voxels inside
void calculateAABox();
void init(unsigned char * octalCode);
public:
VoxelNode(); // root node constructor
VoxelNode(unsigned char * octalCode); // regular constructor
@ -85,6 +71,7 @@ public:
void clearDirtyBit() { _isDirty = false; };
bool hasChangedSince(uint64_t time) const { return (_lastChanged > time); };
void markWithChangedTime() { _lastChanged = usecTimestampNow(); };
uint64_t getLastChanged() const { return _lastChanged; };
void handleSubtreeChanged(VoxelTree* myTree);
glBufferIndex getBufferIndex() const { return _glBufferIndex; };
@ -117,6 +104,33 @@ public:
const nodeColor& getTrueColor() const { return _trueColor; };
const nodeColor& getColor() const { return _trueColor; };
#endif
static int addDeleteHook(VoxelNodeDeleteHook hook, void* extraData = NULL);
static void removeDeleteHook(int hookID);
private:
void calculateAABox();
void init(unsigned char * octalCode);
void notifyDeleteHooks();
nodeColor _trueColor;
#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color
nodeColor _currentColor;
bool _falseColored;
#endif
glBufferIndex _glBufferIndex;
bool _isDirty;
uint64_t _lastChanged;
bool _shouldRender;
bool _isStagedForDeletion;
AABox _box;
unsigned char* _octalCode;
VoxelNode* _children[8];
int _childCount;
float _density; // If leaf: density = 1, if internal node: 0-1 density of voxels inside
static VoxelNodeDeleteHook _hooks[VOXEL_NODE_MAX_DELETE_HOOKS];
static void* _hooksExtraData[VOXEL_NODE_MAX_DELETE_HOOKS];
static int _hooksInUse;
};
#endif /* defined(__hifi__VoxelNode__) */

View file

@ -9,7 +9,15 @@
#include "VoxelNodeBag.h"
#include <OctalCode.h>
VoxelNodeBag::VoxelNodeBag() :
_bagElements(NULL),
_elementsInUse(0),
_sizeOfElementsArray(0) {
_hookID = VoxelNode::addDeleteHook(voxelNodeDeleteHook, (void*)this);
};
VoxelNodeBag::~VoxelNodeBag() {
VoxelNode::removeDeleteHook(_hookID);
deleteAll();
}
@ -118,3 +126,9 @@ void VoxelNodeBag::remove(VoxelNode* node) {
}
}
void VoxelNodeBag::voxelNodeDeleteHook(VoxelNode* node, void* extraData) {
VoxelNodeBag* theBag = (VoxelNodeBag*)extraData;
theBag->remove(node); // note: remove can safely handle nodes that aren't in it, so we don't need to check contains()
}

View file

@ -19,11 +19,7 @@
class VoxelNodeBag {
public:
VoxelNodeBag() :
_bagElements(NULL),
_elementsInUse(0),
_sizeOfElementsArray(0) {};
VoxelNodeBag();
~VoxelNodeBag();
void insert(VoxelNode* node); // put a node into the bag
@ -36,11 +32,14 @@ public:
void deleteAll();
static void voxelNodeDeleteHook(VoxelNode* node, void* extraData);
private:
VoxelNode** _bagElements;
int _elementsInUse;
int _sizeOfElementsArray;
int _hookID;
};
#endif /* defined(__hifi__VoxelNodeBag__) */

View file

@ -6,10 +6,13 @@
//
#include <algorithm>
#include "VoxelProjectedPolygon.h"
#include <QDebug>
#include "GeometryUtil.h"
#include "Log.h"
#include "SharedUtil.h"
#include "VoxelProjectedPolygon.h"
glm::vec2 BoundingBox::getVertex(int vertexNumber) const {
switch (vertexNumber) {
@ -88,11 +91,11 @@ void BoundingBox::explandToInclude(const BoundingBox& box) {
void BoundingBox::printDebugDetails(const char* label) const {
if (label) {
printLog(label);
qDebug() << label;
} else {
printLog("BoundingBox");
qDebug("BoundingBox");
}
printLog("\n _set=%s\n corner=%f,%f size=%f,%f\n bounds=[(%f,%f) to (%f,%f)]\n",
qDebug("\n _set=%s\n corner=%f,%f size=%f,%f\n bounds=[(%f,%f) to (%f,%f)]\n",
debug::valueOf(_set), corner.x, corner.y, size.x, size.y, corner.x, corner.y, corner.x+size.x, corner.y+size.y);
}

View file

@ -9,33 +9,34 @@
#ifdef _WIN32
#define _USE_MATH_DEFINES
#endif
#include <cstring>
#include <cstdio>
#include <cmath>
#include "SharedUtil.h"
#include "Log.h"
#include "PacketHeaders.h"
#include "OctalCode.h"
#include "GeometryUtil.h"
#include "VoxelTree.h"
#include "VoxelNodeBag.h"
#include "ViewFrustum.h"
#include <fstream> // to load voxels from file
#include "VoxelConstants.h"
#include "CoverageMap.h"
#include "SquarePixelMap.h"
#include "Tags.h"
#include <glm/gtc/noise.hpp>
#include <QDebug>
#include "CoverageMap.h"
#include "GeometryUtil.h"
#include "OctalCode.h"
#include "PacketHeaders.h"
#include "SharedUtil.h"
#include "SquarePixelMap.h"
#include "Tags.h"
#include "ViewFrustum.h"
#include "VoxelConstants.h"
#include "VoxelNodeBag.h"
#include "VoxelTree.h"
float boundaryDistanceForRenderLevel(unsigned int renderLevel) {
const float voxelSizeScale = 50000.0f;
return voxelSizeScale / powf(2, renderLevel);
return ::VOXEL_SIZE_SCALE / powf(2, renderLevel);
}
float boundaryDistanceSquaredForRenderLevel(unsigned int renderLevel) {
const float voxelSizeScale = (50000.0f/TREE_SCALE) * (50000.0f/TREE_SCALE);
const float voxelSizeScale = (::VOXEL_SIZE_SCALE/TREE_SCALE) * (::VOXEL_SIZE_SCALE/TREE_SCALE);
return voxelSizeScale / powf(2, (2 * renderLevel));
}
@ -155,7 +156,7 @@ void VoxelTree::recurseNodeWithOperationDistanceSorted(VoxelNode* node, RecurseV
if (childNode) {
// chance to optimize, doesn't need to be actual distance!! Could be distance squared
float distanceSquared = childNode->distanceSquareToPoint(point);
//printLog("recurseNodeWithOperationDistanceSorted() CHECKING child[%d] point=%f,%f center=%f,%f distance=%f...\n", i, point.x, point.y, center.x, center.y, distance);
//qDebug("recurseNodeWithOperationDistanceSorted() CHECKING child[%d] point=%f,%f center=%f,%f distance=%f...\n", i, point.x, point.y, center.x, center.y, distance);
//childNode->printDebugDetails("");
currentCount = insertIntoSortedArrays((void*)childNode, distanceSquared, i,
(void**)&sortedChildren, (float*)&distancesToChildren,
@ -166,7 +167,7 @@ void VoxelTree::recurseNodeWithOperationDistanceSorted(VoxelNode* node, RecurseV
for (int i = 0; i < currentCount; i++) {
VoxelNode* childNode = sortedChildren[i];
if (childNode) {
//printLog("recurseNodeWithOperationDistanceSorted() PROCESSING child[%d] distance=%f...\n", i, distancesToChildren[i]);
//qDebug("recurseNodeWithOperationDistanceSorted() PROCESSING child[%d] distance=%f...\n", i, distancesToChildren[i]);
//childNode->printDebugDetails("");
recurseNodeWithOperationDistanceSorted(childNode, operation, point, extraData);
}
@ -371,7 +372,6 @@ void VoxelTree::deleteVoxelAt(float x, float y, float z, float s, bool stage) {
delete[] octalCode; // cleanup memory
}
class DeleteVoxelCodeFromTreeArgs {
public:
bool stage;
@ -458,7 +458,7 @@ void VoxelTree::deleteVoxelCodeFromTreeRecursion(VoxelNode* node, void* extraDat
// isn't a colored leaf, and the child branch doesn't exist, so there's nothing to do below and
// we can safely return, ending the recursion and unwinding
if (!childNode) {
//printLog("new___deleteVoxelCodeFromTree() child branch doesn't exist, but parent is not a leaf, just unwind\n");
//qDebug("new___deleteVoxelCodeFromTree() child branch doesn't exist, but parent is not a leaf, just unwind\n");
return;
}
@ -546,7 +546,7 @@ void VoxelTree::readCodeColorBufferToTreeRecursion(VoxelNode* node, void* extraD
}
} else {
if (!node->isLeaf()) {
printLog("WARNING! operation would require deleting children, add Voxel ignored!\n ");
qDebug("WARNING! operation would require deleting children, add Voxel ignored!\n ");
}
}
@ -619,13 +619,13 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) {
}
}
printLog("color mask: ");
qDebug("color mask: ");
outputBits(colorMask);
// output the colors we have
for (int j = 0; j < NUMBER_OF_CHILDREN; j++) {
if (startNode->getChildAtIndex(j) && startNode->getChildAtIndex(j)->isColored()) {
printLog("color %d : ",j);
qDebug("color %d : ",j);
for (int c = 0; c < 3; c++) {
outputBits(startNode->getChildAtIndex(j)->getTrueColor()[c],false);
}
@ -641,7 +641,7 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) {
}
}
printLog("child mask: ");
qDebug("child mask: ");
outputBits(childMask);
if (childMask > 0) {
@ -686,7 +686,7 @@ void VoxelTree::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) {
int totalBytesRead = 0;
if(file.is_open()) {
printLog("loading file...\n");
qDebug("loading file...\n");
bool bail = false;
while (!file.eof() && !bail) {
file.get(octets);
@ -711,14 +711,14 @@ void VoxelTree::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) {
file.get(colorRead);
blue = (unsigned char)colorRead;
printLog("voxel color from file red:%d, green:%d, blue:%d \n",red,green,blue);
qDebug("voxel color from file red:%d, green:%d, blue:%d \n",red,green,blue);
vCount++;
int colorRandomizer = wantColorRandomizer ? randIntInRange (-5, 5) : 0;
voxelData[lengthInBytes+1] = std::max(0,std::min(255,red + colorRandomizer));
voxelData[lengthInBytes+2] = std::max(0,std::min(255,green + colorRandomizer));
voxelData[lengthInBytes+3] = std::max(0,std::min(255,blue + colorRandomizer));
printLog("voxel color after rand red:%d, green:%d, blue:%d\n",
qDebug("voxel color after rand red:%d, green:%d, blue:%d\n",
voxelData[lengthInBytes+1], voxelData[lengthInBytes+2], voxelData[lengthInBytes+3]);
//printVoxelCode(voxelData);
@ -819,7 +819,7 @@ void VoxelTree::createSphere(float radius, float xc, float yc, float zc, float v
if (debug) {
int percentComplete = 100 * (thisRadius/radius);
printLog("percentComplete=%d\n",percentComplete);
qDebug("percentComplete=%d\n",percentComplete);
}
for (float theta=0.0; theta <= 2 * M_PI; theta += angleDelta) {
@ -835,7 +835,7 @@ void VoxelTree::createSphere(float radius, float xc, float yc, float zc, float v
// 2) In all modes, we will use our "outer" color to draw the voxels. Otherwise we will use the average color
if (lastLayer) {
if (false && debug) {
printLog("adding candy shell: theta=%f phi=%f thisRadius=%f radius=%f\n",
qDebug("adding candy shell: theta=%f phi=%f thisRadius=%f radius=%f\n",
theta, phi, thisRadius,radius);
}
switch (mode) {
@ -859,7 +859,7 @@ void VoxelTree::createSphere(float radius, float xc, float yc, float zc, float v
green = (unsigned char)std::min(255, std::max(0, (int)(g1 + ((g2 - g1) * gradient))));
blue = (unsigned char)std::min(255, std::max(0, (int)(b1 + ((b2 - b1) * gradient))));
if (debug) {
printLog("perlin=%f gradient=%f color=(%d,%d,%d)\n",perlin, gradient, red, green, blue);
qDebug("perlin=%f gradient=%f color=(%d,%d,%d)\n",perlin, gradient, red, green, blue);
}
} break;
}
@ -1003,17 +1003,18 @@ bool VoxelTree::findCapsulePenetration(const glm::vec3& start, const glm::vec3&
return args.found;
}
int VoxelTree::encodeTreeBitstream(VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag,
EncodeBitstreamParams& params) const {
// How many bytes have we written so far at this level;
int bytesWritten = 0;
// If we're at a node that is out of view, then we can return, because no nodes below us will be in view!
if (params.viewFrustum && !node->isInView(*params.viewFrustum)) {
return bytesWritten;
}
// write the octal code
int codeLength;
if (params.chopLevels) {
@ -1072,7 +1073,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
if (currentEncodeLevel >= params.maxEncodeLevel) {
return bytesAtThisLevel;
}
// caller can pass NULL as viewFrustum if they want everything
if (params.viewFrustum) {
float distance = node->distanceToCamera(*params.viewFrustum);
@ -1105,10 +1106,19 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
}
}
// If we were in view, then bail out early!
if (wasInView) {
// If we were previously in the view, then we normally will return out of here and stop recursing. But
// if we're in deltaViewFrustum mode, and this node has changed since it was last sent, then we do
// need to send it.
if (wasInView && !(params.deltaViewFrustum && node->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE))) {
return bytesAtThisLevel;
}
}
// If we're not in delta sending mode, and we weren't asked to do a force send, and the voxel hasn't changed,
// then we can also bail early and save bits
if (!params.forceSendScene && !params.deltaViewFrustum &&
!node->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE)) {
return bytesAtThisLevel;
}
// If the user also asked for occlusion culling, check if this node is occluded, but only if it's not a leaf.
// leaf occlusion is handled down below when we check child nodes
@ -1176,7 +1186,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
if (childNode) {
// chance to optimize, doesn't need to be actual distance!! Could be distance squared
//float distanceSquared = childNode->distanceSquareToPoint(point);
//printLog("recurseNodeWithOperationDistanceSorted() CHECKING child[%d] point=%f,%f center=%f,%f distance=%f...\n", i, point.x, point.y, center.x, center.y, distance);
//qDebug("recurseNodeWithOperationDistanceSorted() CHECKING child[%d] point=%f,%f center=%f,%f distance=%f...\n", i, point.x, point.y, center.x, center.y, distance);
//childNode->printDebugDetails("");
float distance = params.viewFrustum ? childNode->distanceToCamera(*params.viewFrustum) : 0;
@ -1268,8 +1278,12 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
}
}
// If our child wasn't in view (or we're ignoring wasInView) then we add it to our sending items
if (!childWasInView) {
// If our child wasn't in view (or we're ignoring wasInView) then we add it to our sending items.
// Or if we were previously in the view, but this node has changed since it was last sent, then we do
// need to send it.
if (!childWasInView ||
(params.deltaViewFrustum &&
childNode->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE))){
childrenColoredBits += (1 << (7 - originalIndex));
inViewWithColorCount++;
} else {
@ -1353,7 +1367,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
if (oneAtBit(childrenExistInPacketBits, originalIndex)) {
int thisLevel = currentEncodeLevel;
// remember this for reshuffling
recursiveSliceStarts[originalIndex] = outputBuffer;
@ -1432,7 +1445,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
bool VoxelTree::readFromSVOFile(const char* fileName) {
std::ifstream file(fileName, std::ios::in|std::ios::binary|std::ios::ate);
if(file.is_open()) {
printLog("loading file %s...\n", fileName);
qDebug("loading file %s...\n", fileName);
// get file length....
unsigned long fileLength = file.tellg();
@ -1460,14 +1473,14 @@ bool VoxelTree::readFromSchematicFile(const char *fileName) {
std::stringstream ss;
int err = retrieveData(fileName, ss);
if (err && ss.get() != TAG_Compound) {
printLog("[ERROR] Invalid schematic file.\n");
qDebug("[ERROR] Invalid schematic file.\n");
return false;
}
ss.get();
TagCompound schematics(ss);
if (!schematics.getBlocksId() || !schematics.getBlocksData()) {
printLog("[ERROR] Invalid schematic file.\n");
qDebug("[ERROR] Invalid schematic file.\n");
return false;
}
@ -1530,7 +1543,7 @@ bool VoxelTree::readFromSchematicFile(const char *fileName) {
}
}
printLog("Created %d voxels from minecraft import.\n", count);
qDebug("Created %d voxels from minecraft import.\n", count);
return true;
}
@ -1540,7 +1553,7 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) const {
std::ofstream file(fileName, std::ios::out|std::ios::binary);
if(file.is_open()) {
printLog("saving to file %s...\n", fileName);
qDebug("saving to file %s...\n", fileName);
VoxelNodeBag nodeBag;
// If we were given a specific node, start from there, otherwise start from root

View file

@ -35,6 +35,7 @@ typedef enum {GRADIENT, RANDOM, NATURAL} creationMode;
#define DONT_CHOP 0
#define NO_BOUNDARY_ADJUST 0
#define LOW_RES_MOVING_ADJUST 1
#define IGNORE_LAST_SENT 0
class EncodeBitstreamParams {
public:
@ -49,7 +50,8 @@ public:
bool wantOcclusionCulling;
long childWasInViewDiscarded;
int boundaryLevelAdjust;
uint64_t lastViewFrustumSent;
bool forceSendScene;
CoverageMap* map;
EncodeBitstreamParams(
@ -62,7 +64,9 @@ public:
const ViewFrustum* lastViewFrustum = IGNORE_VIEW_FRUSTUM,
bool wantOcclusionCulling= NO_OCCLUSION_CULLING,
CoverageMap* map = IGNORE_COVERAGE_MAP,
int boundaryLevelAdjust = NO_BOUNDARY_ADJUST) :
int boundaryLevelAdjust = NO_BOUNDARY_ADJUST,
uint64_t lastViewFrustumSent = IGNORE_LAST_SENT,
bool forceSendScene = true) :
maxEncodeLevel (maxEncodeLevel),
maxLevelReached (0),
viewFrustum (viewFrustum),
@ -74,6 +78,8 @@ public:
wantOcclusionCulling (wantOcclusionCulling),
childWasInViewDiscarded (0),
boundaryLevelAdjust (boundaryLevelAdjust),
lastViewFrustumSent (lastViewFrustumSent),
forceSendScene (forceSendScene),
map (map)
{}
};

View file

@ -6,7 +6,7 @@ set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
set(TARGET_NAME pairing-server)
include(${MACRO_DIR}/SetupHifiProject.cmake)
setup_hifi_project(${TARGET_NAME})
setup_hifi_project(${TARGET_NAME} TRUE)
# link the shared hifi library
include(${MACRO_DIR}/LinkHifiLibrary.cmake)

View file

@ -7,7 +7,7 @@ set(TARGET_NAME space-server)
include(${MACRO_DIR}/SetupHifiProject.cmake)
setup_hifi_project(${TARGET_NAME})
setup_hifi_project(${TARGET_NAME} TRUE)
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})

View file

@ -14,7 +14,7 @@ include_glm(${TARGET_NAME} ${ROOT_DIR})
include(${MACRO_DIR}/SetupHifiProject.cmake)
setup_hifi_project(${TARGET_NAME})
setup_hifi_project(${TARGET_NAME} TRUE)
# link in the shared library
include(${MACRO_DIR}/LinkHifiLibrary.cmake)

View file

@ -14,7 +14,7 @@ include_glm(${TARGET_NAME} ${ROOT_DIR})
include(${MACRO_DIR}/SetupHifiProject.cmake)
setup_hifi_project(${TARGET_NAME})
setup_hifi_project(${TARGET_NAME} TRUE)
# link in the shared library
include(${MACRO_DIR}/LinkHifiLibrary.cmake)

View file

@ -7,6 +7,7 @@
//
#include "PacketHeaders.h"
#include "SharedUtil.h"
#include "VoxelNodeData.h"
#include <cstring>
#include <cstdio>
@ -19,11 +20,11 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) :
_maxLevelReachedInLastSearch(1),
_lastTimeBagEmpty(0),
_viewFrustumChanging(false),
_viewFrustumJustStoppedChanging(true),
_currentPacketIsColor(true)
{
_voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE];
_voxelPacketAt = _voxelPacket;
resetVoxelPacket();
}
@ -69,10 +70,25 @@ bool VoxelNodeData::updateCurrentViewFrustum() {
_currentViewFrustum.calculate();
currentViewFrustumChanged = true;
}
// When we first detect that the view stopped changing, we record this.
// but we don't change it back to false until we've completely sent this
// scene.
if (_viewFrustumChanging && !currentViewFrustumChanged) {
_viewFrustumJustStoppedChanging = true;
}
_viewFrustumChanging = currentViewFrustumChanged;
return currentViewFrustumChanged;
}
void VoxelNodeData::setViewSent(bool viewSent) {
_viewSent = viewSent;
if (viewSent) {
_viewFrustumJustStoppedChanging = false;
}
}
void VoxelNodeData::updateLastKnownViewFrustum() {
bool frustumChanges = !_lastKnownViewFrustum.matches(_currentViewFrustum);
@ -80,5 +96,9 @@ void VoxelNodeData::updateLastKnownViewFrustum() {
// save our currentViewFrustum into our lastKnownViewFrustum
_lastKnownViewFrustum = _currentViewFrustum;
}
// save that we know the view has been sent.
uint64_t now = usecTimestampNow();
setLastTimeBagEmpty(now); // is this what we want? poor names
}

View file

@ -48,7 +48,11 @@ public:
void updateLastKnownViewFrustum();
bool getViewSent() const { return _viewSent; };
void setViewSent(bool viewSent) { _viewSent = viewSent; }
void setViewSent(bool viewSent);
bool getViewFrustumChanging() const { return _viewFrustumChanging; };
bool getViewFrustumJustStoppedChanging() const { return _viewFrustumJustStoppedChanging; };
uint64_t getLastTimeBagEmpty() const { return _lastTimeBagEmpty; };
void setLastTimeBagEmpty(uint64_t lastTimeBagEmpty) { _lastTimeBagEmpty = lastTimeBagEmpty; };
@ -69,6 +73,7 @@ private:
ViewFrustum _lastKnownViewFrustum;
uint64_t _lastTimeBagEmpty;
bool _viewFrustumChanging;
bool _viewFrustumJustStoppedChanging;
bool _currentPacketIsColor;
};

View file

@ -44,9 +44,9 @@ const int MIN_BRIGHTNESS = 64;
const float DEATH_STAR_RADIUS = 4.0;
const float MAX_CUBE = 0.05f;
const int VOXEL_SEND_INTERVAL_USECS = 100 * 1000;
int PACKETS_PER_CLIENT_PER_INTERVAL = 30;
const int SENDING_TIME_TO_SPARE = 20 * 1000; // usec of sending interval to spare for calculating voxels
const int VOXEL_SEND_INTERVAL_USECS = 17 * 1000; // approximately 60fps
int PACKETS_PER_CLIENT_PER_INTERVAL = 20;
const int SENDING_TIME_TO_SPARE = 5 * 1000; // usec of sending interval to spare for calculating voxels
const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4;
@ -173,10 +173,10 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
// If the current view frustum has changed OR we have nothing to send, then search against
// the current view frustum for things to send.
if (viewFrustumChanged || nodeData->nodeBag.isEmpty()) {
uint64_t now = usecTimestampNow();
if (::debugVoxelSending) {
printf("(viewFrustumChanged=%s || nodeData->nodeBag.isEmpty() =%s)...\n",
debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()));
uint64_t now = usecTimestampNow();
if (nodeData->getLastTimeBagEmpty() > 0) {
float elapsedSceneSend = (now - nodeData->getLastTimeBagEmpty()) / 1000000.0f;
if (viewFrustumChanged) {
@ -188,15 +188,24 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
debug::valueOf(nodeData->getWantOcclusionCulling()), debug::valueOf(wantDelta),
debug::valueOf(wantColor));
}
nodeData->setLastTimeBagEmpty(now); // huh? why is this inside debug? probably not what we want
}
// if our view has changed, we need to reset these things...
if (viewFrustumChanged) {
nodeData->nodeBag.deleteAll();
nodeData->map.erase();
}
if (!viewFrustumChanged && !nodeData->getWantDelta()) {
// only set our last sent time if we weren't resetting due to frustum change
uint64_t now = usecTimestampNow();
nodeData->setLastTimeBagEmpty(now);
if (::debugVoxelSending) {
printf("ENTIRE SCENE SENT! nodeData->setLastTimeBagEmpty(now=[%lld])\n", now);
}
}
// This is the start of "resending" the scene.
nodeData->nodeBag.insert(serverTree.rootNode);
}
@ -233,15 +242,13 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor,
WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum,
wantOcclusionCulling, coverageMap, boundaryLevelAdjust);
wantOcclusionCulling, coverageMap, boundaryLevelAdjust,
nodeData->getLastTimeBagEmpty(),
nodeData->getViewFrustumJustStoppedChanging());
bytesWritten = serverTree.encodeTreeBitstream(subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1,
nodeData->nodeBag, params);
if (::debugVoxelSending && wantDelta) {
printf("encodeTreeBitstream() childWasInViewDiscarded=%ld\n", params.childWasInViewDiscarded);
}
if (nodeData->getAvailable() >= bytesWritten) {
nodeData->writeToPacket(&tempOutputBuffer[0], bytesWritten);
} else {
@ -375,9 +382,10 @@ void attachVoxelNodeDataToNode(Node* newNode) {
}
int main(int argc, const char * argv[]) {
pthread_mutex_init(&::treeLock, NULL);
qInstallMsgHandler(sharedMessageHandler);
NodeList* nodeList = NodeList::createInstance(NODE_TYPE_VOXEL_SERVER, VOXEL_LISTEN_PORT);
setvbuf(stdout, NULL, _IOLBF, 0);