mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-07-24 10:53:45 +02:00
Merge branch 'master' of https://github.com/worklist/hifi into fixery
This commit is contained in:
commit
355321c8b5
12 changed files with 589 additions and 480 deletions
|
@ -85,7 +85,6 @@ const float MIRROR_FULLSCREEN_DISTANCE = 0.35f;
|
||||||
const float MIRROR_REARVIEW_DISTANCE = 0.65f;
|
const float MIRROR_REARVIEW_DISTANCE = 0.65f;
|
||||||
const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f;
|
const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f;
|
||||||
|
|
||||||
|
|
||||||
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message) {
|
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message) {
|
||||||
fprintf(stdout, "%s", message.toLocal8Bit().constData());
|
fprintf(stdout, "%s", message.toLocal8Bit().constData());
|
||||||
Application::getInstance()->getLogger()->addMessage(message.toLocal8Bit().constData());
|
Application::getInstance()->getLogger()->addMessage(message.toLocal8Bit().constData());
|
||||||
|
@ -142,7 +141,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
_resetRecentMaxPacketsSoon(true),
|
_resetRecentMaxPacketsSoon(true),
|
||||||
_swatch(NULL),
|
_swatch(NULL),
|
||||||
_pasteMode(false),
|
_pasteMode(false),
|
||||||
_logger(new FileLogger())
|
_logger(new FileLogger()),
|
||||||
|
_persistThread(NULL)
|
||||||
{
|
{
|
||||||
_applicationStartupTime = startup_time;
|
_applicationStartupTime = startup_time;
|
||||||
|
|
||||||
|
@ -177,7 +177,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
nodeList->addHook(&_voxels);
|
nodeList->addHook(&_voxels);
|
||||||
nodeList->addHook(this);
|
nodeList->addHook(this);
|
||||||
nodeList->addDomainListener(this);
|
nodeList->addDomainListener(this);
|
||||||
nodeList->addDomainListener(&_voxels);
|
|
||||||
|
|
||||||
// network receive thread and voxel parsing thread are both controlled by the --nonblocking command line
|
// network receive thread and voxel parsing thread are both controlled by the --nonblocking command line
|
||||||
_enableProcessVoxelsThread = _enableNetworkThread = !cmdOptionExists(argc, constArgv, "--nonblocking");
|
_enableProcessVoxelsThread = _enableNetworkThread = !cmdOptionExists(argc, constArgv, "--nonblocking");
|
||||||
|
@ -249,6 +248,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
|
|
||||||
// Set the sixense filtering
|
// Set the sixense filtering
|
||||||
_sixenseManager.setFilter(Menu::getInstance()->isOptionChecked(MenuOption::FilterSixense));
|
_sixenseManager.setFilter(Menu::getInstance()->isOptionChecked(MenuOption::FilterSixense));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Application::~Application() {
|
Application::~Application() {
|
||||||
|
@ -1434,6 +1434,8 @@ void Application::terminate() {
|
||||||
_voxelHideShowThread.terminate();
|
_voxelHideShowThread.terminate();
|
||||||
_voxelEditSender.terminate();
|
_voxelEditSender.terminate();
|
||||||
_particleEditSender.terminate();
|
_particleEditSender.terminate();
|
||||||
|
_persistThread->terminate();
|
||||||
|
_persistThread = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Avatar* processAvatarMessageHeader(unsigned char*& packetData, size_t& dataBytes) {
|
static Avatar* processAvatarMessageHeader(unsigned char*& packetData, size_t& dataBytes) {
|
||||||
|
@ -1933,6 +1935,9 @@ void Application::init() {
|
||||||
connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView()));
|
connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView()));
|
||||||
connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView()));
|
connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView()));
|
||||||
connect(_rearMirrorTools, SIGNAL(resetView()), SLOT(resetSensors()));
|
connect(_rearMirrorTools, SIGNAL(resetView()), SLOT(resetSensors()));
|
||||||
|
|
||||||
|
|
||||||
|
updateLocalOctreeCache(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::closeMirrorView() {
|
void Application::closeMirrorView() {
|
||||||
|
@ -2393,6 +2398,7 @@ void Application::updateThreads(float deltaTime) {
|
||||||
_voxelHideShowThread.threadRoutine();
|
_voxelHideShowThread.threadRoutine();
|
||||||
_voxelEditSender.threadRoutine();
|
_voxelEditSender.threadRoutine();
|
||||||
_particleEditSender.threadRoutine();
|
_particleEditSender.threadRoutine();
|
||||||
|
_persistThread->threadRoutine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4188,6 +4194,10 @@ void Application::domainChanged(QString domain) {
|
||||||
_voxelServerJurisdictions.clear();
|
_voxelServerJurisdictions.clear();
|
||||||
_octreeServerSceneStats.clear();
|
_octreeServerSceneStats.clear();
|
||||||
_particleServerJurisdictions.clear();
|
_particleServerJurisdictions.clear();
|
||||||
|
|
||||||
|
// reset our persist thread
|
||||||
|
qDebug() << "domainChanged()... domain=" << domain << " swapping persist cache\n";
|
||||||
|
updateLocalOctreeCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::nodeAdded(Node* node) {
|
void Application::nodeAdded(Node* node) {
|
||||||
|
@ -4523,3 +4533,47 @@ void Application::toggleLogDialog() {
|
||||||
_logDialog->close();
|
_logDialog->close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Application::initAvatarAndViewFrustum() {
|
||||||
|
updateAvatar(0.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Application::getLocalVoxelCacheFileName() {
|
||||||
|
QString fileName = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
||||||
|
QDir logDir(fileName);
|
||||||
|
if (!logDir.exists(fileName)) {
|
||||||
|
logDir.mkdir(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
fileName.append(QString("/hifi.voxelscache."));
|
||||||
|
fileName.append(_profile.getLastDomain());
|
||||||
|
fileName.append(QString(".svo"));
|
||||||
|
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Application::updateLocalOctreeCache(bool firstTime) {
|
||||||
|
// only do this if we've already got a persistThread or we're told this is the first time
|
||||||
|
if (firstTime || _persistThread) {
|
||||||
|
|
||||||
|
if (_persistThread) {
|
||||||
|
_persistThread->terminate();
|
||||||
|
_persistThread = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString localVoxelCacheFileName = getLocalVoxelCacheFileName();
|
||||||
|
const int LOCAL_CACHE_PERSIST_INTERVAL = 1000 * 10; // every 10 seconds
|
||||||
|
_persistThread = new OctreePersistThread(_voxels.getTree(),
|
||||||
|
localVoxelCacheFileName.toLocal8Bit().constData(),LOCAL_CACHE_PERSIST_INTERVAL);
|
||||||
|
|
||||||
|
qDebug() << "updateLocalOctreeCache()... localVoxelCacheFileName=" << localVoxelCacheFileName << "\n";
|
||||||
|
|
||||||
|
if (_persistThread) {
|
||||||
|
_voxels.beginLoadingLocalVoxelCache(); // while local voxels are importing, don't do individual node VBO updates
|
||||||
|
connect(_persistThread, SIGNAL(loadCompleted()), &_voxels, SLOT(localVoxelCacheLoaded()));
|
||||||
|
_persistThread->initialize(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#define __interface__Application__
|
#define __interface__Application__
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
@ -108,14 +108,14 @@ public:
|
||||||
~Application();
|
~Application();
|
||||||
|
|
||||||
void restoreSizeAndPosition();
|
void restoreSizeAndPosition();
|
||||||
void storeSizeAndPosition();
|
void storeSizeAndPosition();
|
||||||
void initializeGL();
|
void initializeGL();
|
||||||
void paintGL();
|
void paintGL();
|
||||||
void resizeGL(int width, int height);
|
void resizeGL(int width, int height);
|
||||||
|
|
||||||
void keyPressEvent(QKeyEvent* event);
|
void keyPressEvent(QKeyEvent* event);
|
||||||
void keyReleaseEvent(QKeyEvent* event);
|
void keyReleaseEvent(QKeyEvent* event);
|
||||||
|
|
||||||
void mouseMoveEvent(QMouseEvent* event);
|
void mouseMoveEvent(QMouseEvent* event);
|
||||||
void mousePressEvent(QMouseEvent* event);
|
void mousePressEvent(QMouseEvent* event);
|
||||||
void mouseReleaseEvent(QMouseEvent* event);
|
void mouseReleaseEvent(QMouseEvent* event);
|
||||||
|
@ -123,27 +123,27 @@ public:
|
||||||
void touchBeginEvent(QTouchEvent* event);
|
void touchBeginEvent(QTouchEvent* event);
|
||||||
void touchEndEvent(QTouchEvent* event);
|
void touchEndEvent(QTouchEvent* event);
|
||||||
void touchUpdateEvent(QTouchEvent* event);
|
void touchUpdateEvent(QTouchEvent* event);
|
||||||
|
|
||||||
void updateWindowTitle();
|
void updateWindowTitle();
|
||||||
|
|
||||||
void wheelEvent(QWheelEvent* event);
|
void wheelEvent(QWheelEvent* event);
|
||||||
|
|
||||||
void shootParticle(); // shoots a particle in the direction you're looking
|
void shootParticle(); // shoots a particle in the direction you're looking
|
||||||
ParticleEditHandle* newParticleEditHandle(uint32_t id = NEW_PARTICLE);
|
ParticleEditHandle* newParticleEditHandle(uint32_t id = NEW_PARTICLE);
|
||||||
ParticleEditHandle* makeParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity,
|
ParticleEditHandle* makeParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity,
|
||||||
glm::vec3 gravity, float damping, bool inHand, QString updateScript);
|
glm::vec3 gravity, float damping, bool inHand, QString updateScript);
|
||||||
|
|
||||||
void makeVoxel(glm::vec3 position,
|
void makeVoxel(glm::vec3 position,
|
||||||
float scale,
|
float scale,
|
||||||
unsigned char red,
|
unsigned char red,
|
||||||
unsigned char green,
|
unsigned char green,
|
||||||
unsigned char blue,
|
unsigned char blue,
|
||||||
bool isDestructive);
|
bool isDestructive);
|
||||||
|
|
||||||
void removeVoxel(glm::vec3 position, float scale);
|
void removeVoxel(glm::vec3 position, float scale);
|
||||||
|
|
||||||
const glm::vec3 getMouseVoxelWorldCoordinates(const VoxelDetail _mouseVoxel);
|
const glm::vec3 getMouseVoxelWorldCoordinates(const VoxelDetail _mouseVoxel);
|
||||||
|
|
||||||
QGLWidget* getGLWidget() { return _glWidget; }
|
QGLWidget* getGLWidget() { return _glWidget; }
|
||||||
MyAvatar* getAvatar() { return &_myAvatar; }
|
MyAvatar* getAvatar() { return &_myAvatar; }
|
||||||
Audio* getAudio() { return &_audio; }
|
Audio* getAudio() { return &_audio; }
|
||||||
|
@ -166,24 +166,24 @@ public:
|
||||||
NodeToVoxelSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; }
|
NodeToVoxelSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; }
|
||||||
void lockVoxelSceneStats() { _voxelSceneStatsLock.lockForRead(); }
|
void lockVoxelSceneStats() { _voxelSceneStatsLock.lockForRead(); }
|
||||||
void unlockVoxelSceneStats() { _voxelSceneStatsLock.unlock(); }
|
void unlockVoxelSceneStats() { _voxelSceneStatsLock.unlock(); }
|
||||||
|
|
||||||
QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; }
|
QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; }
|
||||||
GeometryCache* getGeometryCache() { return &_geometryCache; }
|
GeometryCache* getGeometryCache() { return &_geometryCache; }
|
||||||
TextureCache* getTextureCache() { return &_textureCache; }
|
TextureCache* getTextureCache() { return &_textureCache; }
|
||||||
GlowEffect* getGlowEffect() { return &_glowEffect; }
|
GlowEffect* getGlowEffect() { return &_glowEffect; }
|
||||||
|
|
||||||
Avatar* getLookatTargetAvatar() const { return _lookatTargetAvatar; }
|
Avatar* getLookatTargetAvatar() const { return _lookatTargetAvatar; }
|
||||||
|
|
||||||
Profile* getProfile() { return &_profile; }
|
Profile* getProfile() { return &_profile; }
|
||||||
void resetProfile(const QString& username);
|
void resetProfile(const QString& username);
|
||||||
|
|
||||||
static void controlledBroadcastToNodes(unsigned char* broadcastData, size_t dataBytes,
|
static void controlledBroadcastToNodes(unsigned char* broadcastData, size_t dataBytes,
|
||||||
const char* nodeTypes, int numNodeTypes);
|
const char* nodeTypes, int numNodeTypes);
|
||||||
|
|
||||||
void setupWorldLight();
|
void setupWorldLight();
|
||||||
|
|
||||||
void displaySide(Camera& whichCamera, bool selfAvatarOnly = false);
|
void displaySide(Camera& whichCamera, bool selfAvatarOnly = false);
|
||||||
|
|
||||||
/// Loads a view matrix that incorporates the specified model translation without the precision issues that can
|
/// Loads a view matrix that incorporates the specified model translation without the precision issues that can
|
||||||
/// result from matrix multiplication at high translation magnitudes.
|
/// result from matrix multiplication at high translation magnitudes.
|
||||||
void loadTranslatedViewMatrix(const glm::vec3& translation);
|
void loadTranslatedViewMatrix(const glm::vec3& translation);
|
||||||
|
@ -197,9 +197,9 @@ public:
|
||||||
virtual void nodeAdded(Node* node);
|
virtual void nodeAdded(Node* node);
|
||||||
virtual void nodeKilled(Node* node);
|
virtual void nodeKilled(Node* node);
|
||||||
virtual void packetSentNotification(ssize_t length);
|
virtual void packetSentNotification(ssize_t length);
|
||||||
|
|
||||||
virtual void domainChanged(QString domain);
|
virtual void domainChanged(QString domain);
|
||||||
|
|
||||||
VoxelShader& getVoxelShader() { return _voxelShader; }
|
VoxelShader& getVoxelShader() { return _voxelShader; }
|
||||||
PointShader& getPointShader() { return _pointShader; }
|
PointShader& getPointShader() { return _pointShader; }
|
||||||
FileLogger* getLogger() { return _logger; }
|
FileLogger* getLogger() { return _logger; }
|
||||||
|
@ -208,7 +208,7 @@ public:
|
||||||
NodeToJurisdictionMap& getVoxelServerJurisdictions() { return _voxelServerJurisdictions; }
|
NodeToJurisdictionMap& getVoxelServerJurisdictions() { return _voxelServerJurisdictions; }
|
||||||
NodeToJurisdictionMap& getParticleServerJurisdictions() { return _particleServerJurisdictions; }
|
NodeToJurisdictionMap& getParticleServerJurisdictions() { return _particleServerJurisdictions; }
|
||||||
void pasteVoxelsToOctalCode(const unsigned char* octalCodeDestination);
|
void pasteVoxelsToOctalCode(const unsigned char* octalCodeDestination);
|
||||||
|
|
||||||
/// set a voxel which is to be rendered with a highlight
|
/// set a voxel which is to be rendered with a highlight
|
||||||
void setHighlightVoxel(const VoxelDetail& highlightVoxel) { _highlightVoxel = highlightVoxel; }
|
void setHighlightVoxel(const VoxelDetail& highlightVoxel) { _highlightVoxel = highlightVoxel; }
|
||||||
void setIsHighlightVoxel(bool isHighlightVoxel) { _isHighlightVoxel = isHighlightVoxel; }
|
void setIsHighlightVoxel(bool isHighlightVoxel) { _isHighlightVoxel = isHighlightVoxel; }
|
||||||
|
@ -222,25 +222,26 @@ public slots:
|
||||||
void pasteVoxels();
|
void pasteVoxels();
|
||||||
void nudgeVoxels();
|
void nudgeVoxels();
|
||||||
void deleteVoxels();
|
void deleteVoxels();
|
||||||
|
|
||||||
void setRenderVoxels(bool renderVoxels);
|
void setRenderVoxels(bool renderVoxels);
|
||||||
void doKillLocalVoxels();
|
void doKillLocalVoxels();
|
||||||
void decreaseVoxelSize();
|
void decreaseVoxelSize();
|
||||||
void increaseVoxelSize();
|
void increaseVoxelSize();
|
||||||
void loadScript();
|
void loadScript();
|
||||||
void toggleLogDialog();
|
void toggleLogDialog();
|
||||||
|
void initAvatarAndViewFrustum();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void timer();
|
void timer();
|
||||||
void idle();
|
void idle();
|
||||||
void terminate();
|
void terminate();
|
||||||
|
|
||||||
void setFullscreen(bool fullscreen);
|
void setFullscreen(bool fullscreen);
|
||||||
|
|
||||||
void renderThrustAtVoxel(const glm::vec3& thrust);
|
void renderThrustAtVoxel(const glm::vec3& thrust);
|
||||||
void renderLineToTouchedVoxel();
|
void renderLineToTouchedVoxel();
|
||||||
|
|
||||||
void renderCoverageMap();
|
void renderCoverageMap();
|
||||||
void renderCoverageMapsRecursively(CoverageMap* map);
|
void renderCoverageMapsRecursively(CoverageMap* map);
|
||||||
|
|
||||||
|
@ -250,7 +251,7 @@ private slots:
|
||||||
glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint);
|
glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint);
|
||||||
|
|
||||||
void toggleFollowMode();
|
void toggleFollowMode();
|
||||||
|
|
||||||
void closeMirrorView();
|
void closeMirrorView();
|
||||||
void restoreMirrorView();
|
void restoreMirrorView();
|
||||||
void shrinkMirrorView();
|
void shrinkMirrorView();
|
||||||
|
@ -265,17 +266,17 @@ private:
|
||||||
static void processAvatarURLsMessage(unsigned char* packetData, size_t dataBytes);
|
static void processAvatarURLsMessage(unsigned char* packetData, size_t dataBytes);
|
||||||
static void processAvatarFaceVideoMessage(unsigned char* packetData, size_t dataBytes);
|
static void processAvatarFaceVideoMessage(unsigned char* packetData, size_t dataBytes);
|
||||||
static void sendPingPackets();
|
static void sendPingPackets();
|
||||||
|
|
||||||
void initDisplay();
|
void initDisplay();
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
void update(float deltaTime);
|
void update(float deltaTime);
|
||||||
|
|
||||||
// Various helper functions called during update()
|
// Various helper functions called during update()
|
||||||
void updateMouseRay(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection);
|
void updateMouseRay(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection);
|
||||||
void updateFaceshift();
|
void updateFaceshift();
|
||||||
void updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3& lookAtRayOrigin, glm::vec3& lookAtRayDirection);
|
void updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3& lookAtRayOrigin, glm::vec3& lookAtRayDirection);
|
||||||
void updateHoverVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
|
void updateHoverVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
|
||||||
float& distance, BoxFace& face);
|
float& distance, BoxFace& face);
|
||||||
void updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
|
void updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
|
||||||
float& distance, BoxFace& face);
|
float& distance, BoxFace& face);
|
||||||
|
@ -298,32 +299,32 @@ private:
|
||||||
Avatar* findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
Avatar* findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
||||||
glm::vec3& eyePosition, QUuid &nodeUUID);
|
glm::vec3& eyePosition, QUuid &nodeUUID);
|
||||||
bool isLookingAtMyAvatar(Avatar* avatar);
|
bool isLookingAtMyAvatar(Avatar* avatar);
|
||||||
|
|
||||||
void renderLookatIndicator(glm::vec3 pointOfInterest);
|
void renderLookatIndicator(glm::vec3 pointOfInterest);
|
||||||
void renderFollowIndicator();
|
void renderFollowIndicator();
|
||||||
void renderHighlightVoxel(VoxelDetail voxel);
|
void renderHighlightVoxel(VoxelDetail voxel);
|
||||||
|
|
||||||
void updateAvatar(float deltaTime);
|
void updateAvatar(float deltaTime);
|
||||||
void updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm::vec3 mouseRayDirection);
|
void updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm::vec3 mouseRayDirection);
|
||||||
void queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, NodeToJurisdictionMap& jurisdictions);
|
void queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, NodeToJurisdictionMap& jurisdictions);
|
||||||
void loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum);
|
void loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum);
|
||||||
|
|
||||||
glm::vec3 getSunDirection();
|
glm::vec3 getSunDirection();
|
||||||
|
|
||||||
void updateShadowMap();
|
void updateShadowMap();
|
||||||
void displayOverlay();
|
void displayOverlay();
|
||||||
void displayStats();
|
void displayStats();
|
||||||
void renderAvatars(bool forceRenderHead, bool selfAvatarOnly = false);
|
void renderAvatars(bool forceRenderHead, bool selfAvatarOnly = false);
|
||||||
void renderViewFrustum(ViewFrustum& viewFrustum);
|
void renderViewFrustum(ViewFrustum& viewFrustum);
|
||||||
|
|
||||||
void checkBandwidthMeterClick();
|
void checkBandwidthMeterClick();
|
||||||
|
|
||||||
bool maybeEditVoxelUnderCursor();
|
bool maybeEditVoxelUnderCursor();
|
||||||
void deleteVoxelUnderCursor();
|
void deleteVoxelUnderCursor();
|
||||||
void eyedropperVoxelUnderCursor();
|
void eyedropperVoxelUnderCursor();
|
||||||
|
|
||||||
void setMenuShortcutsEnabled(bool enabled);
|
void setMenuShortcutsEnabled(bool enabled);
|
||||||
|
|
||||||
static void attachNewHeadToNode(Node *newNode);
|
static void attachNewHeadToNode(Node *newNode);
|
||||||
static void* networkReceive(void* args); // network receive thread
|
static void* networkReceive(void* args); // network receive thread
|
||||||
|
|
||||||
|
@ -333,18 +334,18 @@ private:
|
||||||
|
|
||||||
QMainWindow* _window;
|
QMainWindow* _window;
|
||||||
QGLWidget* _glWidget;
|
QGLWidget* _glWidget;
|
||||||
|
|
||||||
QAction* _followMode;
|
QAction* _followMode;
|
||||||
|
|
||||||
BandwidthMeter _bandwidthMeter;
|
BandwidthMeter _bandwidthMeter;
|
||||||
|
|
||||||
SerialInterface _serialHeadSensor;
|
SerialInterface _serialHeadSensor;
|
||||||
QNetworkAccessManager* _networkAccessManager;
|
QNetworkAccessManager* _networkAccessManager;
|
||||||
QSettings* _settings;
|
QSettings* _settings;
|
||||||
bool _displayLevels;
|
bool _displayLevels;
|
||||||
|
|
||||||
glm::vec3 _gravity;
|
glm::vec3 _gravity;
|
||||||
|
|
||||||
// Frame Rate Measurement
|
// Frame Rate Measurement
|
||||||
int _frameCount;
|
int _frameCount;
|
||||||
float _fps;
|
float _fps;
|
||||||
|
@ -354,55 +355,55 @@ private:
|
||||||
bool _justStarted;
|
bool _justStarted;
|
||||||
|
|
||||||
Stars _stars;
|
Stars _stars;
|
||||||
|
|
||||||
Cloud _cloud;
|
Cloud _cloud;
|
||||||
|
|
||||||
VoxelSystem _voxels;
|
VoxelSystem _voxels;
|
||||||
VoxelTree _clipboard; // if I copy/paste
|
VoxelTree _clipboard; // if I copy/paste
|
||||||
VoxelImporter _voxelImporter;
|
VoxelImporter _voxelImporter;
|
||||||
VoxelSystem _sharedVoxelSystem;
|
VoxelSystem _sharedVoxelSystem;
|
||||||
ViewFrustum _sharedVoxelSystemViewFrustum;
|
ViewFrustum _sharedVoxelSystemViewFrustum;
|
||||||
|
|
||||||
ParticleTreeRenderer _particles;
|
ParticleTreeRenderer _particles;
|
||||||
ParticleCollisionSystem _particleCollisionSystem;
|
ParticleCollisionSystem _particleCollisionSystem;
|
||||||
|
|
||||||
QByteArray _voxelsFilename;
|
QByteArray _voxelsFilename;
|
||||||
bool _wantToKillLocalVoxels;
|
bool _wantToKillLocalVoxels;
|
||||||
|
|
||||||
MetavoxelSystem _metavoxels;
|
MetavoxelSystem _metavoxels;
|
||||||
|
|
||||||
ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc.
|
ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc.
|
||||||
|
|
||||||
Oscilloscope _audioScope;
|
Oscilloscope _audioScope;
|
||||||
|
|
||||||
VoxelQuery _voxelQuery; // NodeData derived class for querying voxels from voxel server
|
VoxelQuery _voxelQuery; // NodeData derived class for querying voxels from voxel server
|
||||||
|
|
||||||
MyAvatar _myAvatar; // The rendered avatar of oneself
|
MyAvatar _myAvatar; // The rendered avatar of oneself
|
||||||
Profile _profile; // The data-server linked profile for this user
|
Profile _profile; // The data-server linked profile for this user
|
||||||
|
|
||||||
Transmitter _myTransmitter; // Gets UDP data from transmitter app used to animate the avatar
|
Transmitter _myTransmitter; // Gets UDP data from transmitter app used to animate the avatar
|
||||||
|
|
||||||
Webcam _webcam; // The webcam interface
|
Webcam _webcam; // The webcam interface
|
||||||
|
|
||||||
Faceshift _faceshift;
|
Faceshift _faceshift;
|
||||||
|
|
||||||
SixenseManager _sixenseManager;
|
SixenseManager _sixenseManager;
|
||||||
|
|
||||||
Camera _myCamera; // My view onto the world
|
Camera _myCamera; // My view onto the world
|
||||||
Camera _viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode
|
Camera _viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode
|
||||||
Camera _mirrorCamera; // Cammera for mirror view
|
Camera _mirrorCamera; // Cammera for mirror view
|
||||||
QRect _mirrorViewRect;
|
QRect _mirrorViewRect;
|
||||||
RearMirrorTools* _rearMirrorTools;
|
RearMirrorTools* _rearMirrorTools;
|
||||||
|
|
||||||
glm::mat4 _untranslatedViewMatrix;
|
glm::mat4 _untranslatedViewMatrix;
|
||||||
glm::vec3 _viewMatrixTranslation;
|
glm::vec3 _viewMatrixTranslation;
|
||||||
|
|
||||||
glm::mat4 _shadowMatrix;
|
glm::mat4 _shadowMatrix;
|
||||||
|
|
||||||
Environment _environment;
|
Environment _environment;
|
||||||
|
|
||||||
int _headMouseX, _headMouseY;
|
int _headMouseX, _headMouseY;
|
||||||
|
|
||||||
int _mouseX;
|
int _mouseX;
|
||||||
int _mouseY;
|
int _mouseY;
|
||||||
int _mouseDragStartedX;
|
int _mouseDragStartedX;
|
||||||
|
@ -420,7 +421,7 @@ private:
|
||||||
bool _isTouchPressed; // true if multitouch has been pressed (clear when finished)
|
bool _isTouchPressed; // true if multitouch has been pressed (clear when finished)
|
||||||
float _yawFromTouch;
|
float _yawFromTouch;
|
||||||
float _pitchFromTouch;
|
float _pitchFromTouch;
|
||||||
|
|
||||||
VoxelDetail _mouseVoxelDragging;
|
VoxelDetail _mouseVoxelDragging;
|
||||||
bool _mousePressed; // true if mouse has been pressed (clear when finished)
|
bool _mousePressed; // true if mouse has been pressed (clear when finished)
|
||||||
|
|
||||||
|
@ -428,7 +429,7 @@ private:
|
||||||
bool _isHoverVoxel;
|
bool _isHoverVoxel;
|
||||||
bool _isHoverVoxelSounding;
|
bool _isHoverVoxelSounding;
|
||||||
nodeColor _hoverVoxelOriginalColor;
|
nodeColor _hoverVoxelOriginalColor;
|
||||||
|
|
||||||
VoxelDetail _mouseVoxel; // details of the voxel to be edited
|
VoxelDetail _mouseVoxel; // details of the voxel to be edited
|
||||||
float _mouseVoxelScale; // the scale for adding/removing voxels
|
float _mouseVoxelScale; // the scale for adding/removing voxels
|
||||||
bool _mouseVoxelScaleInitialized;
|
bool _mouseVoxelScaleInitialized;
|
||||||
|
@ -437,7 +438,7 @@ private:
|
||||||
|
|
||||||
VoxelDetail _highlightVoxel;
|
VoxelDetail _highlightVoxel;
|
||||||
bool _isHighlightVoxel;
|
bool _isHighlightVoxel;
|
||||||
|
|
||||||
VoxelDetail _nudgeVoxel; // details of the voxel to be nudged
|
VoxelDetail _nudgeVoxel; // details of the voxel to be nudged
|
||||||
bool _nudgeStarted;
|
bool _nudgeStarted;
|
||||||
bool _lookingAlongX;
|
bool _lookingAlongX;
|
||||||
|
@ -447,46 +448,46 @@ private:
|
||||||
Avatar* _lookatTargetAvatar;
|
Avatar* _lookatTargetAvatar;
|
||||||
glm::vec3 _lookatOtherPosition;
|
glm::vec3 _lookatOtherPosition;
|
||||||
float _lookatIndicatorScale;
|
float _lookatIndicatorScale;
|
||||||
|
|
||||||
glm::vec3 _transmitterPickStart;
|
glm::vec3 _transmitterPickStart;
|
||||||
glm::vec3 _transmitterPickEnd;
|
glm::vec3 _transmitterPickEnd;
|
||||||
|
|
||||||
bool _perfStatsOn; // Do we want to display perfStats?
|
bool _perfStatsOn; // Do we want to display perfStats?
|
||||||
|
|
||||||
ChatEntry _chatEntry; // chat entry field
|
ChatEntry _chatEntry; // chat entry field
|
||||||
bool _chatEntryOn; // Whether to show the chat entry
|
bool _chatEntryOn; // Whether to show the chat entry
|
||||||
|
|
||||||
GeometryCache _geometryCache;
|
GeometryCache _geometryCache;
|
||||||
TextureCache _textureCache;
|
TextureCache _textureCache;
|
||||||
|
|
||||||
GlowEffect _glowEffect;
|
GlowEffect _glowEffect;
|
||||||
AmbientOcclusionEffect _ambientOcclusionEffect;
|
AmbientOcclusionEffect _ambientOcclusionEffect;
|
||||||
VoxelShader _voxelShader;
|
VoxelShader _voxelShader;
|
||||||
PointShader _pointShader;
|
PointShader _pointShader;
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
Audio _audio;
|
Audio _audio;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool _enableNetworkThread;
|
bool _enableNetworkThread;
|
||||||
pthread_t _networkReceiveThread;
|
pthread_t _networkReceiveThread;
|
||||||
bool _stopNetworkReceiveThread;
|
bool _stopNetworkReceiveThread;
|
||||||
|
|
||||||
bool _enableProcessVoxelsThread;
|
bool _enableProcessVoxelsThread;
|
||||||
VoxelPacketProcessor _voxelProcessor;
|
VoxelPacketProcessor _voxelProcessor;
|
||||||
VoxelHideShowThread _voxelHideShowThread;
|
VoxelHideShowThread _voxelHideShowThread;
|
||||||
VoxelEditPacketSender _voxelEditSender;
|
VoxelEditPacketSender _voxelEditSender;
|
||||||
ParticleEditPacketSender _particleEditSender;
|
ParticleEditPacketSender _particleEditSender;
|
||||||
|
|
||||||
unsigned char _incomingPacket[MAX_PACKET_SIZE];
|
unsigned char _incomingPacket[MAX_PACKET_SIZE];
|
||||||
int _packetCount;
|
int _packetCount;
|
||||||
int _packetsPerSecond;
|
int _packetsPerSecond;
|
||||||
int _bytesPerSecond;
|
int _bytesPerSecond;
|
||||||
int _bytesCount;
|
int _bytesCount;
|
||||||
|
|
||||||
int _recentMaxPackets; // recent max incoming voxel packets to process
|
int _recentMaxPackets; // recent max incoming voxel packets to process
|
||||||
bool _resetRecentMaxPacketsSoon;
|
bool _resetRecentMaxPacketsSoon;
|
||||||
|
|
||||||
StDev _idleLoopStdev;
|
StDev _idleLoopStdev;
|
||||||
float _idleLoopMeasuredJitter;
|
float _idleLoopMeasuredJitter;
|
||||||
|
|
||||||
|
@ -496,22 +497,27 @@ private:
|
||||||
bool _pasteMode;
|
bool _pasteMode;
|
||||||
|
|
||||||
PieMenu _pieMenu;
|
PieMenu _pieMenu;
|
||||||
|
|
||||||
int parseOctreeStats(unsigned char* messageData, ssize_t messageLength, const HifiSockAddr& senderAddress);
|
int parseOctreeStats(unsigned char* messageData, ssize_t messageLength, const HifiSockAddr& senderAddress);
|
||||||
void trackIncomingVoxelPacket(unsigned char* messageData, ssize_t messageLength,
|
void trackIncomingVoxelPacket(unsigned char* messageData, ssize_t messageLength,
|
||||||
const HifiSockAddr& senderSockAddr, bool wasStatsPacket);
|
const HifiSockAddr& senderSockAddr, bool wasStatsPacket);
|
||||||
|
|
||||||
NodeToJurisdictionMap _voxelServerJurisdictions;
|
NodeToJurisdictionMap _voxelServerJurisdictions;
|
||||||
NodeToJurisdictionMap _particleServerJurisdictions;
|
NodeToJurisdictionMap _particleServerJurisdictions;
|
||||||
NodeToVoxelSceneStats _octreeServerSceneStats;
|
NodeToVoxelSceneStats _octreeServerSceneStats;
|
||||||
QReadWriteLock _voxelSceneStatsLock;
|
QReadWriteLock _voxelSceneStatsLock;
|
||||||
|
|
||||||
std::vector<VoxelFade> _voxelFades;
|
std::vector<VoxelFade> _voxelFades;
|
||||||
std::vector<Avatar*> _avatarFades;
|
std::vector<Avatar*> _avatarFades;
|
||||||
ControllerScriptingInterface _controllerScriptingInterface;
|
ControllerScriptingInterface _controllerScriptingInterface;
|
||||||
QPointer<LogDialog> _logDialog;
|
QPointer<LogDialog> _logDialog;
|
||||||
|
|
||||||
FileLogger* _logger;
|
FileLogger* _logger;
|
||||||
|
|
||||||
|
OctreePersistThread* _persistThread;
|
||||||
|
|
||||||
|
QString getLocalVoxelCacheFileName();
|
||||||
|
void updateLocalOctreeCache(bool firstTime = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__interface__Application__) */
|
#endif /* defined(__interface__Application__) */
|
||||||
|
|
|
@ -35,12 +35,12 @@ bool VoxelHideShowThread::process() {
|
||||||
if (showExtraDebugging && elapsed > USECS_PER_FRAME) {
|
if (showExtraDebugging && elapsed > USECS_PER_FRAME) {
|
||||||
qDebug() << "VoxelHideShowThread::process()... checkForCulling took " << elapsed << "\n";
|
qDebug() << "VoxelHideShowThread::process()... checkForCulling took " << elapsed << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isStillRunning()) {
|
if (isStillRunning()) {
|
||||||
if (elapsed < USECS_PER_FRAME) {
|
if (elapsed < USECS_PER_FRAME) {
|
||||||
uint64_t sleepFor = USECS_PER_FRAME - elapsed;
|
uint64_t sleepFor = USECS_PER_FRAME - elapsed;
|
||||||
usleep(sleepFor);
|
usleep(sleepFor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return isStillRunning(); // keep running till they terminate us
|
return isStillRunning(); // keep running till they terminate us
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,6 +18,7 @@
|
||||||
#include <NodeData.h>
|
#include <NodeData.h>
|
||||||
#include <ViewFrustum.h>
|
#include <ViewFrustum.h>
|
||||||
#include <VoxelTree.h>
|
#include <VoxelTree.h>
|
||||||
|
#include <OctreePersistThread.h>
|
||||||
|
|
||||||
#include "Camera.h"
|
#include "Camera.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
|
@ -36,8 +37,8 @@ struct VoxelShaderVBOData
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class VoxelSystem : public NodeData, public OctreeElementDeleteHook, public OctreeElementUpdateHook,
|
class VoxelSystem : public NodeData, public OctreeElementDeleteHook, public OctreeElementUpdateHook,
|
||||||
public NodeListHook, public DomainChangeListener {
|
public NodeListHook {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
friend class VoxelHideShowThread;
|
friend class VoxelHideShowThread;
|
||||||
|
@ -48,9 +49,9 @@ public:
|
||||||
|
|
||||||
void setDataSourceUUID(const QUuid& dataSourceUUID) { _dataSourceUUID = dataSourceUUID; }
|
void setDataSourceUUID(const QUuid& dataSourceUUID) { _dataSourceUUID = dataSourceUUID; }
|
||||||
const QUuid& getDataSourceUUID() const { return _dataSourceUUID; }
|
const QUuid& getDataSourceUUID() const { return _dataSourceUUID; }
|
||||||
|
|
||||||
int parseData(unsigned char* sourceBuffer, int numBytes);
|
int parseData(unsigned char* sourceBuffer, int numBytes);
|
||||||
|
|
||||||
virtual void init();
|
virtual void init();
|
||||||
void simulate(float deltaTime) { }
|
void simulate(float deltaTime) { }
|
||||||
void render(bool texture);
|
void render(bool texture);
|
||||||
|
@ -85,19 +86,19 @@ public:
|
||||||
virtual void hideOutOfView(bool forceFullFrustum = false);
|
virtual void hideOutOfView(bool forceFullFrustum = false);
|
||||||
bool hasViewChanged();
|
bool hasViewChanged();
|
||||||
bool isViewChanging();
|
bool isViewChanging();
|
||||||
|
|
||||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||||
VoxelDetail& detail, float& distance, BoxFace& face);
|
VoxelDetail& detail, float& distance, BoxFace& face);
|
||||||
|
|
||||||
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration);
|
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration);
|
||||||
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration);
|
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration);
|
||||||
|
|
||||||
void deleteVoxelAt(float x, float y, float z, float s);
|
void deleteVoxelAt(float x, float y, float z, float s);
|
||||||
VoxelTreeElement* getVoxelAt(float x, float y, float z, float s) const;
|
VoxelTreeElement* getVoxelAt(float x, float y, float z, float s) const;
|
||||||
void createVoxel(float x, float y, float z, float s,
|
void createVoxel(float x, float y, float z, float s,
|
||||||
unsigned char red, unsigned char green, unsigned char blue, bool destructive = false);
|
unsigned char red, unsigned char green, unsigned char blue, bool destructive = false);
|
||||||
void createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color, bool destructive = false);
|
void createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color, bool destructive = false);
|
||||||
void createSphere(float r,float xc, float yc, float zc, float s, bool solid,
|
void createSphere(float r,float xc, float yc, float zc, float s, bool solid,
|
||||||
creationMode mode, bool destructive = false, bool debug = false);
|
creationMode mode, bool destructive = false, bool debug = false);
|
||||||
|
|
||||||
void copySubTreeIntoNewTree(VoxelTreeElement* startNode, VoxelSystem* destinationTree, bool rebaseToRoot);
|
void copySubTreeIntoNewTree(VoxelTreeElement* startNode, VoxelSystem* destinationTree, bool rebaseToRoot);
|
||||||
|
@ -113,19 +114,18 @@ public:
|
||||||
virtual void elementUpdated(OctreeElement* element);
|
virtual void elementUpdated(OctreeElement* element);
|
||||||
virtual void nodeAdded(Node* node);
|
virtual void nodeAdded(Node* node);
|
||||||
virtual void nodeKilled(Node* node);
|
virtual void nodeKilled(Node* node);
|
||||||
virtual void domainChanged(QString domain);
|
|
||||||
|
|
||||||
bool treeIsBusy() const { return _treeIsBusy; }
|
bool treeIsBusy() const { return _treeIsBusy; }
|
||||||
|
|
||||||
VoxelTreeElement* getVoxelEnclosing(const glm::vec3& point);
|
VoxelTreeElement* getVoxelEnclosing(const glm::vec3& point);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void importSize(float x, float y, float z);
|
void importSize(float x, float y, float z);
|
||||||
void importProgress(int progress);
|
void importProgress(int progress);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void collectStatsForTreesAndVBOs();
|
void collectStatsForTreesAndVBOs();
|
||||||
|
|
||||||
// Methods that recurse tree
|
// Methods that recurse tree
|
||||||
void showAllLocalVoxels();
|
void showAllLocalVoxels();
|
||||||
void randomizeVoxelColors();
|
void randomizeVoxelColors();
|
||||||
|
@ -141,24 +141,27 @@ public slots:
|
||||||
void clearAllNodesBufferIndex();
|
void clearAllNodesBufferIndex();
|
||||||
|
|
||||||
void cancelImport();
|
void cancelImport();
|
||||||
|
|
||||||
void setDisableFastVoxelPipeline(bool disableFastVoxelPipeline);
|
void setDisableFastVoxelPipeline(bool disableFastVoxelPipeline);
|
||||||
void setUseVoxelShader(bool useVoxelShader);
|
void setUseVoxelShader(bool useVoxelShader);
|
||||||
void setVoxelsAsPoints(bool voxelsAsPoints);
|
void setVoxelsAsPoints(bool voxelsAsPoints);
|
||||||
|
|
||||||
|
void localVoxelCacheLoaded();
|
||||||
|
void beginLoadingLocalVoxelCache();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
float _treeScale;
|
float _treeScale;
|
||||||
int _maxVoxels;
|
int _maxVoxels;
|
||||||
VoxelTree* _tree;
|
VoxelTree* _tree;
|
||||||
|
|
||||||
void setupNewVoxelsForDrawing();
|
void setupNewVoxelsForDrawing();
|
||||||
static const bool DONT_BAIL_EARLY; // by default we will bail early, if you want to force not bailing, then use this
|
static const bool DONT_BAIL_EARLY; // by default we will bail early, if you want to force not bailing, then use this
|
||||||
void setupNewVoxelsForDrawingSingleNode(bool allowBailEarly = true);
|
void setupNewVoxelsForDrawingSingleNode(bool allowBailEarly = true);
|
||||||
void checkForCulling();
|
void checkForCulling();
|
||||||
|
|
||||||
glm::vec3 computeVoxelVertex(const glm::vec3& startVertex, float voxelScale, int index) const;
|
glm::vec3 computeVoxelVertex(const glm::vec3& startVertex, float voxelScale, int index) const;
|
||||||
|
|
||||||
|
|
||||||
virtual void updateArraysDetails(glBufferIndex nodeIndex, const glm::vec3& startVertex,
|
virtual void updateArraysDetails(glBufferIndex nodeIndex, const glm::vec3& startVertex,
|
||||||
float voxelScale, const nodeColor& color);
|
float voxelScale, const nodeColor& color);
|
||||||
virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd);
|
virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd);
|
||||||
|
@ -170,7 +173,7 @@ private:
|
||||||
// disallow copying of VoxelSystem objects
|
// disallow copying of VoxelSystem objects
|
||||||
VoxelSystem(const VoxelSystem&);
|
VoxelSystem(const VoxelSystem&);
|
||||||
VoxelSystem& operator= (const VoxelSystem&);
|
VoxelSystem& operator= (const VoxelSystem&);
|
||||||
|
|
||||||
bool _initialized;
|
bool _initialized;
|
||||||
int _callsToTreesToArrays;
|
int _callsToTreesToArrays;
|
||||||
OctreeElementBag _removedVoxels;
|
OctreeElementBag _removedVoxels;
|
||||||
|
@ -223,10 +226,10 @@ private:
|
||||||
unsigned long _voxelsInReadArrays;
|
unsigned long _voxelsInReadArrays;
|
||||||
unsigned long _voxelsInWriteArrays;
|
unsigned long _voxelsInWriteArrays;
|
||||||
unsigned long _abandonedVBOSlots;
|
unsigned long _abandonedVBOSlots;
|
||||||
|
|
||||||
bool _writeRenderFullVBO;
|
bool _writeRenderFullVBO;
|
||||||
bool _readRenderFullVBO;
|
bool _readRenderFullVBO;
|
||||||
|
|
||||||
int _setupNewVoxelsForDrawingLastElapsed;
|
int _setupNewVoxelsForDrawingLastElapsed;
|
||||||
uint64_t _setupNewVoxelsForDrawingLastFinished;
|
uint64_t _setupNewVoxelsForDrawingLastFinished;
|
||||||
uint64_t _lastViewCulling;
|
uint64_t _lastViewCulling;
|
||||||
|
@ -234,7 +237,7 @@ private:
|
||||||
uint64_t _lastAudit;
|
uint64_t _lastAudit;
|
||||||
int _lastViewCullingElapsed;
|
int _lastViewCullingElapsed;
|
||||||
bool _hasRecentlyChanged;
|
bool _hasRecentlyChanged;
|
||||||
|
|
||||||
void initVoxelMemory();
|
void initVoxelMemory();
|
||||||
void cleanupVoxelMemory();
|
void cleanupVoxelMemory();
|
||||||
|
|
||||||
|
@ -246,7 +249,7 @@ private:
|
||||||
GLuint _vboVoxelsIndicesID; /// when using voxel shader, we'll use this VBO for our indexes
|
GLuint _vboVoxelsIndicesID; /// when using voxel shader, we'll use this VBO for our indexes
|
||||||
VoxelShaderVBOData* _writeVoxelShaderData;
|
VoxelShaderVBOData* _writeVoxelShaderData;
|
||||||
VoxelShaderVBOData* _readVoxelShaderData;
|
VoxelShaderVBOData* _readVoxelShaderData;
|
||||||
|
|
||||||
GLuint _vboVerticesID;
|
GLuint _vboVerticesID;
|
||||||
GLuint _vboColorsID;
|
GLuint _vboColorsID;
|
||||||
|
|
||||||
|
@ -269,11 +272,11 @@ private:
|
||||||
|
|
||||||
void setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndices[]);
|
void setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndices[]);
|
||||||
|
|
||||||
int newTreeToArrays(VoxelTreeElement *currentNode);
|
int newTreeToArrays(VoxelTreeElement* currentNode);
|
||||||
void cleanupRemovedVoxels();
|
void cleanupRemovedVoxels();
|
||||||
|
|
||||||
void copyWrittenDataToReadArrays(bool fullVBOs);
|
void copyWrittenDataToReadArrays(bool fullVBOs);
|
||||||
|
|
||||||
void updateFullVBOs(); // all voxels in the VBO
|
void updateFullVBOs(); // all voxels in the VBO
|
||||||
void updatePartialVBOs(); // multiple segments, only dirty voxels
|
void updatePartialVBOs(); // multiple segments, only dirty voxels
|
||||||
|
|
||||||
|
@ -281,7 +284,7 @@ private:
|
||||||
|
|
||||||
static ProgramObject _perlinModulateProgram;
|
static ProgramObject _perlinModulateProgram;
|
||||||
static ProgramObject _shadowMapProgram;
|
static ProgramObject _shadowMapProgram;
|
||||||
|
|
||||||
int _hookID;
|
int _hookID;
|
||||||
std::vector<glBufferIndex> _freeIndexes;
|
std::vector<glBufferIndex> _freeIndexes;
|
||||||
pthread_mutex_t _freeIndexLock;
|
pthread_mutex_t _freeIndexLock;
|
||||||
|
@ -289,22 +292,22 @@ private:
|
||||||
void freeBufferIndex(glBufferIndex index);
|
void freeBufferIndex(glBufferIndex index);
|
||||||
void clearFreeBufferIndexes();
|
void clearFreeBufferIndexes();
|
||||||
glBufferIndex getNextBufferIndex();
|
glBufferIndex getNextBufferIndex();
|
||||||
|
|
||||||
bool _falseColorizeBySource;
|
bool _falseColorizeBySource;
|
||||||
QUuid _dataSourceUUID;
|
QUuid _dataSourceUUID;
|
||||||
|
|
||||||
int _voxelServerCount;
|
int _voxelServerCount;
|
||||||
unsigned long _memoryUsageRAM;
|
unsigned long _memoryUsageRAM;
|
||||||
unsigned long _memoryUsageVBO;
|
unsigned long _memoryUsageVBO;
|
||||||
unsigned long _initialMemoryUsageGPU;
|
unsigned long _initialMemoryUsageGPU;
|
||||||
bool _hasMemoryUsageGPU;
|
bool _hasMemoryUsageGPU;
|
||||||
|
|
||||||
bool _inSetupNewVoxelsForDrawing;
|
bool _inSetupNewVoxelsForDrawing;
|
||||||
bool _useFastVoxelPipeline;
|
bool _useFastVoxelPipeline;
|
||||||
|
|
||||||
bool _inhideOutOfView;
|
bool _inhideOutOfView;
|
||||||
bool _treeIsBusy; // is the tree mutex locked? if so, it's busy, and if you can avoid it, don't access the tree
|
bool _treeIsBusy; // is the tree mutex locked? if so, it's busy, and if you can avoid it, don't access the tree
|
||||||
|
|
||||||
void lockTree();
|
void lockTree();
|
||||||
void unlockTree();
|
void unlockTree();
|
||||||
};
|
};
|
||||||
|
|
|
@ -49,20 +49,22 @@ bool OctreeQueryNode::packetIsDuplicate() const {
|
||||||
// since our packets now include header information, like sequence number, and createTime, we can't just do a memcmp
|
// since our packets now include header information, like sequence number, and createTime, we can't just do a memcmp
|
||||||
// of the entire packet, we need to compare only the packet content...
|
// of the entire packet, we need to compare only the packet content...
|
||||||
if (_lastOctreePacketLength == getPacketLength()) {
|
if (_lastOctreePacketLength == getPacketLength()) {
|
||||||
return memcmp(_lastOctreePacket + OCTREE_PACKET_HEADER_SIZE,
|
if (memcmp(_lastOctreePacket + OCTREE_PACKET_HEADER_SIZE,
|
||||||
_octreePacket+OCTREE_PACKET_HEADER_SIZE , getPacketLength() - OCTREE_PACKET_HEADER_SIZE == 0);
|
_octreePacket + OCTREE_PACKET_HEADER_SIZE , getPacketLength() - OCTREE_PACKET_HEADER_SIZE) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OctreeQueryNode::shouldSuppressDuplicatePacket() {
|
bool OctreeQueryNode::shouldSuppressDuplicatePacket() {
|
||||||
bool shouldSuppress = false; // assume we won't suppress
|
bool shouldSuppress = false; // assume we won't suppress
|
||||||
|
|
||||||
// only consider duplicate packets
|
// only consider duplicate packets
|
||||||
if (packetIsDuplicate()) {
|
if (packetIsDuplicate()) {
|
||||||
_duplicatePacketCount++;
|
_duplicatePacketCount++;
|
||||||
|
|
||||||
// If this is the first suppressed packet, remember our time...
|
// If this is the first suppressed packet, remember our time...
|
||||||
if (_duplicatePacketCount == 1) {
|
if (_duplicatePacketCount == 1) {
|
||||||
_firstSuppressedPacket = usecTimestampNow();
|
_firstSuppressedPacket = usecTimestampNow();
|
||||||
}
|
}
|
||||||
|
@ -97,8 +99,8 @@ void OctreeQueryNode::resetOctreePacket(bool lastWasSurpressed) {
|
||||||
_lastOctreePacketLength = getPacketLength();
|
_lastOctreePacketLength = getPacketLength();
|
||||||
memcpy(_lastOctreePacket, _octreePacket, _lastOctreePacketLength);
|
memcpy(_lastOctreePacket, _octreePacket, _lastOctreePacketLength);
|
||||||
|
|
||||||
// If we're moving, and the client asked for low res, then we force monochrome, otherwise, use
|
// If we're moving, and the client asked for low res, then we force monochrome, otherwise, use
|
||||||
// the clients requested color state.
|
// the clients requested color state.
|
||||||
_currentPacketIsColor = getWantColor();
|
_currentPacketIsColor = getWantColor();
|
||||||
_currentPacketIsCompressed = getWantCompression();
|
_currentPacketIsCompressed = getWantCompression();
|
||||||
OCTREE_PACKET_FLAGS flags = 0;
|
OCTREE_PACKET_FLAGS flags = 0;
|
||||||
|
@ -152,7 +154,7 @@ void OctreeQueryNode::writeToPacket(const unsigned char* buffer, int bytes) {
|
||||||
_octreePacketAvailableBytes -= bytes;
|
_octreePacketAvailableBytes -= bytes;
|
||||||
_octreePacketAt += bytes;
|
_octreePacketAt += bytes;
|
||||||
_octreePacketWaiting = true;
|
_octreePacketWaiting = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OctreeQueryNode::~OctreeQueryNode() {
|
OctreeQueryNode::~OctreeQueryNode() {
|
||||||
|
@ -175,20 +177,20 @@ bool OctreeQueryNode::updateCurrentViewFrustum() {
|
||||||
// Also make sure it's got the correct lens details from the camera
|
// Also make sure it's got the correct lens details from the camera
|
||||||
float originalFOV = getCameraFov();
|
float originalFOV = getCameraFov();
|
||||||
float wideFOV = originalFOV + VIEW_FRUSTUM_FOV_OVERSEND;
|
float wideFOV = originalFOV + VIEW_FRUSTUM_FOV_OVERSEND;
|
||||||
|
|
||||||
newestViewFrustum.setFieldOfView(wideFOV); // hack
|
newestViewFrustum.setFieldOfView(wideFOV); // hack
|
||||||
newestViewFrustum.setAspectRatio(getCameraAspectRatio());
|
newestViewFrustum.setAspectRatio(getCameraAspectRatio());
|
||||||
newestViewFrustum.setNearClip(getCameraNearClip());
|
newestViewFrustum.setNearClip(getCameraNearClip());
|
||||||
newestViewFrustum.setFarClip(getCameraFarClip());
|
newestViewFrustum.setFarClip(getCameraFarClip());
|
||||||
newestViewFrustum.setEyeOffsetPosition(getCameraEyeOffsetPosition());
|
newestViewFrustum.setEyeOffsetPosition(getCameraEyeOffsetPosition());
|
||||||
|
|
||||||
// if there has been a change, then recalculate
|
// if there has been a change, then recalculate
|
||||||
if (!newestViewFrustum.isVerySimilar(_currentViewFrustum)) {
|
if (!newestViewFrustum.isVerySimilar(_currentViewFrustum)) {
|
||||||
_currentViewFrustum = newestViewFrustum;
|
_currentViewFrustum = newestViewFrustum;
|
||||||
_currentViewFrustum.calculate();
|
_currentViewFrustum.calculate();
|
||||||
currentViewFrustumChanged = true;
|
currentViewFrustumChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also check for LOD changes from the client
|
// Also check for LOD changes from the client
|
||||||
if (_lodInitialized) {
|
if (_lodInitialized) {
|
||||||
if (_lastClientBoundaryLevelAdjust != getBoundaryLevelAdjust()) {
|
if (_lastClientBoundaryLevelAdjust != getBoundaryLevelAdjust()) {
|
||||||
|
@ -205,7 +207,7 @@ bool OctreeQueryNode::updateCurrentViewFrustum() {
|
||||||
_lastClientBoundaryLevelAdjust = getBoundaryLevelAdjust();
|
_lastClientBoundaryLevelAdjust = getBoundaryLevelAdjust();
|
||||||
_lodChanged = false;
|
_lodChanged = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When we first detect that the view stopped changing, we record this.
|
// 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
|
// but we don't change it back to false until we've completely sent this
|
||||||
// scene.
|
// scene.
|
||||||
|
@ -216,8 +218,8 @@ bool OctreeQueryNode::updateCurrentViewFrustum() {
|
||||||
return currentViewFrustumChanged;
|
return currentViewFrustumChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OctreeQueryNode::setViewSent(bool viewSent) {
|
void OctreeQueryNode::setViewSent(bool viewSent) {
|
||||||
_viewSent = viewSent;
|
_viewSent = viewSent;
|
||||||
if (viewSent) {
|
if (viewSent) {
|
||||||
_viewFrustumJustStoppedChanging = false;
|
_viewFrustumJustStoppedChanging = false;
|
||||||
_lodChanged = false;
|
_lodChanged = false;
|
||||||
|
@ -226,12 +228,12 @@ void OctreeQueryNode::setViewSent(bool viewSent) {
|
||||||
|
|
||||||
void OctreeQueryNode::updateLastKnownViewFrustum() {
|
void OctreeQueryNode::updateLastKnownViewFrustum() {
|
||||||
bool frustumChanges = !_lastKnownViewFrustum.isVerySimilar(_currentViewFrustum);
|
bool frustumChanges = !_lastKnownViewFrustum.isVerySimilar(_currentViewFrustum);
|
||||||
|
|
||||||
if (frustumChanges) {
|
if (frustumChanges) {
|
||||||
// save our currentViewFrustum into our lastKnownViewFrustum
|
// save our currentViewFrustum into our lastKnownViewFrustum
|
||||||
_lastKnownViewFrustum = _currentViewFrustum;
|
_lastKnownViewFrustum = _currentViewFrustum;
|
||||||
}
|
}
|
||||||
|
|
||||||
// save that we know the view has been sent.
|
// save that we know the view has been sent.
|
||||||
uint64_t now = usecTimestampNow();
|
uint64_t now = usecTimestampNow();
|
||||||
setLastTimeBagEmpty(now); // is this what we want? poor names
|
setLastTimeBagEmpty(now); // is this what we want? poor names
|
||||||
|
@ -242,7 +244,7 @@ bool OctreeQueryNode::moveShouldDump() const {
|
||||||
glm::vec3 oldPosition = _lastKnownViewFrustum.getPosition();
|
glm::vec3 oldPosition = _lastKnownViewFrustum.getPosition();
|
||||||
glm::vec3 newPosition = _currentViewFrustum.getPosition();
|
glm::vec3 newPosition = _currentViewFrustum.getPosition();
|
||||||
|
|
||||||
// theoretically we could make this slightly larger but relative to avatar scale.
|
// theoretically we could make this slightly larger but relative to avatar scale.
|
||||||
const float MAXIMUM_MOVE_WITHOUT_DUMP = 0.0f;
|
const float MAXIMUM_MOVE_WITHOUT_DUMP = 0.0f;
|
||||||
if (glm::distance(newPosition, oldPosition) > MAXIMUM_MOVE_WITHOUT_DUMP) {
|
if (glm::distance(newPosition, oldPosition) > MAXIMUM_MOVE_WITHOUT_DUMP) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -43,7 +43,7 @@ Octree::Octree(bool shouldReaverage) :
|
||||||
_shouldReaverage(shouldReaverage),
|
_shouldReaverage(shouldReaverage),
|
||||||
_stopImport(false) {
|
_stopImport(false) {
|
||||||
_rootNode = NULL;
|
_rootNode = NULL;
|
||||||
|
|
||||||
pthread_mutex_init(&_encodeSetLock, NULL);
|
pthread_mutex_init(&_encodeSetLock, NULL);
|
||||||
pthread_mutex_init(&_deleteSetLock, NULL);
|
pthread_mutex_init(&_deleteSetLock, NULL);
|
||||||
pthread_mutex_init(&_deletePendingSetLock, NULL);
|
pthread_mutex_init(&_deletePendingSetLock, NULL);
|
||||||
|
@ -66,13 +66,13 @@ void Octree::recurseTreeWithOperation(RecurseOctreeOperation operation, void* ex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recurses voxel node with an operation function
|
// Recurses voxel node with an operation function
|
||||||
void Octree::recurseNodeWithOperation(OctreeElement* node, RecurseOctreeOperation operation, void* extraData,
|
void Octree::recurseNodeWithOperation(OctreeElement* node, RecurseOctreeOperation operation, void* extraData,
|
||||||
int recursionCount) {
|
int recursionCount) {
|
||||||
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
|
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
|
||||||
qDebug() << "Octree::recurseNodeWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!\n";
|
qDebug() << "Octree::recurseNodeWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (operation(node, extraData)) {
|
if (operation(node, extraData)) {
|
||||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||||
OctreeElement* child = node->getChildAtIndex(i);
|
OctreeElement* child = node->getChildAtIndex(i);
|
||||||
|
@ -92,7 +92,7 @@ void Octree::recurseTreeWithOperationDistanceSorted(RecurseOctreeOperation opera
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recurses voxel node with an operation function
|
// Recurses voxel node with an operation function
|
||||||
void Octree::recurseNodeWithOperationDistanceSorted(OctreeElement* node, RecurseOctreeOperation operation,
|
void Octree::recurseNodeWithOperationDistanceSorted(OctreeElement* node, RecurseOctreeOperation operation,
|
||||||
const glm::vec3& point, void* extraData, int recursionCount) {
|
const glm::vec3& point, void* extraData, int recursionCount) {
|
||||||
|
|
||||||
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
|
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
|
||||||
|
@ -138,7 +138,7 @@ OctreeElement* Octree::nodeForOctalCode(OctreeElement* ancestorNode,
|
||||||
if (needleCode == NULL) {
|
if (needleCode == NULL) {
|
||||||
return _rootNode;
|
return _rootNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// find the appropriate branch index based on this ancestorNode
|
// find the appropriate branch index based on this ancestorNode
|
||||||
if (*needleCode > 0) {
|
if (*needleCode > 0) {
|
||||||
int branchForNeedle = branchIndexWithDescendant(ancestorNode->getOctalCode(), needleCode);
|
int branchForNeedle = branchIndexWithDescendant(ancestorNode->getOctalCode(), needleCode);
|
||||||
|
@ -213,13 +213,13 @@ int Octree::readNodeData(OctreeElement* destinationNode, const unsigned char* no
|
||||||
nodeWasDirty = childNodeAt->isDirty();
|
nodeWasDirty = childNodeAt->isDirty();
|
||||||
bytesRead += childNodeAt->readElementDataFromBuffer(nodeData + bytesRead, bytesLeftToRead, args);
|
bytesRead += childNodeAt->readElementDataFromBuffer(nodeData + bytesRead, bytesLeftToRead, args);
|
||||||
childNodeAt->setSourceUUID(args.sourceUUID);
|
childNodeAt->setSourceUUID(args.sourceUUID);
|
||||||
|
|
||||||
// if we had a local version of the node already, it's possible that we have it already but
|
// if we had a local version of the node already, it's possible that we have it already but
|
||||||
// with the same color data, so this won't count as a change. To address this we check the following
|
// with the same color data, so this won't count as a change. To address this we check the following
|
||||||
if (!childNodeAt->isDirty() && childNodeAt->getShouldRender() && !childNodeAt->isRendered()) {
|
if (!childNodeAt->isDirty() && childNodeAt->getShouldRender() && !childNodeAt->isRendered()) {
|
||||||
childNodeAt->setDirtyBit(); // force dirty!
|
childNodeAt->setDirtyBit(); // force dirty!
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeIsDirty = childNodeAt->isDirty();
|
nodeIsDirty = childNodeAt->isDirty();
|
||||||
}
|
}
|
||||||
if (nodeIsDirty) {
|
if (nodeIsDirty) {
|
||||||
|
@ -299,8 +299,8 @@ void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long
|
||||||
int octalCodeBytes = bytesRequiredForCodeLength(*bitstreamAt);
|
int octalCodeBytes = bytesRequiredForCodeLength(*bitstreamAt);
|
||||||
int theseBytesRead = 0;
|
int theseBytesRead = 0;
|
||||||
theseBytesRead += octalCodeBytes;
|
theseBytesRead += octalCodeBytes;
|
||||||
|
|
||||||
theseBytesRead += readNodeData(bitstreamRootNode, bitstreamAt + octalCodeBytes,
|
theseBytesRead += readNodeData(bitstreamRootNode, bitstreamAt + octalCodeBytes,
|
||||||
bufferSizeBytes - (bytesRead + octalCodeBytes), args);
|
bufferSizeBytes - (bytesRead + octalCodeBytes), args);
|
||||||
|
|
||||||
// skip bitstream to new startPoint
|
// skip bitstream to new startPoint
|
||||||
|
@ -341,7 +341,7 @@ void Octree::deleteOctalCodeFromTree(const unsigned char* codeBuffer, bool colla
|
||||||
args.pathChanged = false;
|
args.pathChanged = false;
|
||||||
|
|
||||||
OctreeElement* node = _rootNode;
|
OctreeElement* node = _rootNode;
|
||||||
|
|
||||||
// We can't encode and delete nodes at the same time, so we guard against deleting any node that is actively
|
// We can't encode and delete nodes at the same time, so we guard against deleting any node that is actively
|
||||||
// being encoded. And we stick that code on our pendingDelete list.
|
// being encoded. And we stick that code on our pendingDelete list.
|
||||||
if (isEncoding(codeBuffer)) {
|
if (isEncoding(codeBuffer)) {
|
||||||
|
@ -380,15 +380,15 @@ void Octree::deleteOctalCodeFromTreeRecursion(OctreeElement* node, void* extraDa
|
||||||
OctreeElement* ancestorNode = node;
|
OctreeElement* ancestorNode = node;
|
||||||
while (true) {
|
while (true) {
|
||||||
int index = branchIndexWithDescendant(ancestorNode->getOctalCode(), args->codeBuffer);
|
int index = branchIndexWithDescendant(ancestorNode->getOctalCode(), args->codeBuffer);
|
||||||
|
|
||||||
// we end up with all the children, even the one we want to delete
|
// we end up with all the children, even the one we want to delete
|
||||||
ancestorNode->splitChildren();
|
ancestorNode->splitChildren();
|
||||||
|
|
||||||
int lengthOfAncestorNode = numberOfThreeBitSectionsInCode(ancestorNode->getOctalCode());
|
int lengthOfAncestorNode = numberOfThreeBitSectionsInCode(ancestorNode->getOctalCode());
|
||||||
|
|
||||||
// If we've reached the parent of the target, then stop breaking up children
|
// If we've reached the parent of the target, then stop breaking up children
|
||||||
if (lengthOfAncestorNode == (args->lengthOfCode - 1)) {
|
if (lengthOfAncestorNode == (args->lengthOfCode - 1)) {
|
||||||
|
|
||||||
// since we created all the children when we split, we need to delete this target one
|
// since we created all the children when we split, we need to delete this target one
|
||||||
ancestorNode->deleteChildAtIndex(index);
|
ancestorNode->deleteChildAtIndex(index);
|
||||||
break;
|
break;
|
||||||
|
@ -454,21 +454,21 @@ void Octree::processRemoveOctreeElementsBitstream(const unsigned char* bitstream
|
||||||
int numBytesPacketHeader = numBytesForPacketHeader(bitstream);
|
int numBytesPacketHeader = numBytesForPacketHeader(bitstream);
|
||||||
unsigned short int sequence = (*((unsigned short int*)(bitstream + numBytesPacketHeader)));
|
unsigned short int sequence = (*((unsigned short int*)(bitstream + numBytesPacketHeader)));
|
||||||
uint64_t sentAt = (*((uint64_t*)(bitstream + numBytesPacketHeader + sizeof(sequence))));
|
uint64_t sentAt = (*((uint64_t*)(bitstream + numBytesPacketHeader + sizeof(sequence))));
|
||||||
|
|
||||||
int atByte = numBytesPacketHeader + sizeof(sequence) + sizeof(sentAt);
|
int atByte = numBytesPacketHeader + sizeof(sequence) + sizeof(sentAt);
|
||||||
|
|
||||||
unsigned char* voxelCode = (unsigned char*)&bitstream[atByte];
|
unsigned char* voxelCode = (unsigned char*)&bitstream[atByte];
|
||||||
while (atByte < bufferSizeBytes) {
|
while (atByte < bufferSizeBytes) {
|
||||||
int maxSize = bufferSizeBytes - atByte;
|
int maxSize = bufferSizeBytes - atByte;
|
||||||
int codeLength = numberOfThreeBitSectionsInCode(voxelCode, maxSize);
|
int codeLength = numberOfThreeBitSectionsInCode(voxelCode, maxSize);
|
||||||
|
|
||||||
if (codeLength == OVERFLOWED_OCTCODE_BUFFER) {
|
if (codeLength == OVERFLOWED_OCTCODE_BUFFER) {
|
||||||
printf("WARNING! Got remove voxel bitstream that would overflow buffer in numberOfThreeBitSectionsInCode(), ");
|
printf("WARNING! Got remove voxel bitstream that would overflow buffer in numberOfThreeBitSectionsInCode(), ");
|
||||||
printf("bailing processing of packet!\n");
|
printf("bailing processing of packet!\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
int voxelDataSize = bytesRequiredForCodeLength(codeLength) + SIZE_OF_COLOR_DATA;
|
int voxelDataSize = bytesRequiredForCodeLength(codeLength) + SIZE_OF_COLOR_DATA;
|
||||||
|
|
||||||
if (atByte + voxelDataSize <= bufferSizeBytes) {
|
if (atByte + voxelDataSize <= bufferSizeBytes) {
|
||||||
deleteOctalCodeFromTree(voxelCode, COLLAPSE_EMPTY_TREE);
|
deleteOctalCodeFromTree(voxelCode, COLLAPSE_EMPTY_TREE);
|
||||||
voxelCode += voxelDataSize;
|
voxelCode += voxelDataSize;
|
||||||
|
@ -572,7 +572,7 @@ bool findRayIntersectionOp(OctreeElement* node, void* extraData) {
|
||||||
|
|
||||||
bool Octree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
bool Octree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||||
OctreeElement*& node, float& distance, BoxFace& face) {
|
OctreeElement*& node, float& distance, BoxFace& face) {
|
||||||
RayArgs args = { origin / static_cast<float>(TREE_SCALE), direction, node, distance, face };
|
RayArgs args = { origin / (float)(TREE_SCALE), direction, node, distance, face };
|
||||||
recurseTreeWithOperation(findRayIntersectionOp, &args);
|
recurseTreeWithOperation(findRayIntersectionOp, &args);
|
||||||
return args.found;
|
return args.found;
|
||||||
}
|
}
|
||||||
|
@ -600,21 +600,21 @@ bool findSpherePenetrationOp(OctreeElement* element, void* extraData) {
|
||||||
if (element->hasContent()) {
|
if (element->hasContent()) {
|
||||||
glm::vec3 elementPenetration;
|
glm::vec3 elementPenetration;
|
||||||
if (element->findSpherePenetration(args->center, args->radius, elementPenetration, &args->penetratedObject)) {
|
if (element->findSpherePenetration(args->center, args->radius, elementPenetration, &args->penetratedObject)) {
|
||||||
args->penetration = addPenetrations(args->penetration, elementPenetration * static_cast<float>(TREE_SCALE));
|
args->penetration = addPenetrations(args->penetration, elementPenetration * (float)(TREE_SCALE));
|
||||||
args->found = true;
|
args->found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Octree::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration,
|
bool Octree::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration,
|
||||||
void** penetratedObject) {
|
void** penetratedObject) {
|
||||||
|
|
||||||
SphereArgs args = {
|
SphereArgs args = {
|
||||||
center / static_cast<float>(TREE_SCALE),
|
center / (float)(TREE_SCALE),
|
||||||
radius / static_cast<float>(TREE_SCALE),
|
radius / (float)(TREE_SCALE),
|
||||||
penetration,
|
penetration,
|
||||||
false,
|
false,
|
||||||
NULL };
|
NULL };
|
||||||
penetration = glm::vec3(0.0f, 0.0f, 0.0f);
|
penetration = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||||
recurseTreeWithOperation(findSpherePenetrationOp, &args);
|
recurseTreeWithOperation(findSpherePenetrationOp, &args);
|
||||||
|
@ -647,7 +647,7 @@ bool findCapsulePenetrationOp(OctreeElement* node, void* extraData) {
|
||||||
if (node->hasContent()) {
|
if (node->hasContent()) {
|
||||||
glm::vec3 nodePenetration;
|
glm::vec3 nodePenetration;
|
||||||
if (box.findCapsulePenetration(args->start, args->end, args->radius, nodePenetration)) {
|
if (box.findCapsulePenetration(args->start, args->end, args->radius, nodePenetration)) {
|
||||||
args->penetration = addPenetrations(args->penetration, nodePenetration * static_cast<float>(TREE_SCALE));
|
args->penetration = addPenetrations(args->penetration, nodePenetration * (float)(TREE_SCALE));
|
||||||
args->found = true;
|
args->found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -655,17 +655,17 @@ bool findCapsulePenetrationOp(OctreeElement* node, void* extraData) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Octree::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) {
|
bool Octree::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) {
|
||||||
CapsuleArgs args = {
|
CapsuleArgs args = {
|
||||||
start / static_cast<float>(TREE_SCALE),
|
start / (float)(TREE_SCALE),
|
||||||
end / static_cast<float>(TREE_SCALE),
|
end / (float)(TREE_SCALE),
|
||||||
radius / static_cast<float>(TREE_SCALE),
|
radius / (float)(TREE_SCALE),
|
||||||
penetration };
|
penetration };
|
||||||
penetration = glm::vec3(0.0f, 0.0f, 0.0f);
|
penetration = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||||
recurseTreeWithOperation(findCapsulePenetrationOp, &args);
|
recurseTreeWithOperation(findCapsulePenetrationOp, &args);
|
||||||
return args.found;
|
return args.found;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Octree::encodeTreeBitstream(OctreeElement* node,
|
int Octree::encodeTreeBitstream(OctreeElement* node,
|
||||||
OctreePacketData* packetData, OctreeElementBag& bag,
|
OctreePacketData* packetData, OctreeElementBag& bag,
|
||||||
EncodeBitstreamParams& params) {
|
EncodeBitstreamParams& params) {
|
||||||
|
|
||||||
|
@ -680,7 +680,7 @@ int Octree::encodeTreeBitstream(OctreeElement* node,
|
||||||
}
|
}
|
||||||
|
|
||||||
startEncoding(node);
|
startEncoding(node);
|
||||||
|
|
||||||
// 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 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)) {
|
if (params.viewFrustum && !node->isInView(*params.viewFrustum)) {
|
||||||
doneEncoding(node);
|
doneEncoding(node);
|
||||||
|
@ -696,7 +696,7 @@ int Octree::encodeTreeBitstream(OctreeElement* node,
|
||||||
roomForOctalCode = packetData->startSubTree(newCode);
|
roomForOctalCode = packetData->startSubTree(newCode);
|
||||||
|
|
||||||
if (newCode) {
|
if (newCode) {
|
||||||
delete newCode;
|
delete newCode;
|
||||||
} else {
|
} else {
|
||||||
codeLength = 1;
|
codeLength = 1;
|
||||||
}
|
}
|
||||||
|
@ -712,23 +712,23 @@ int Octree::encodeTreeBitstream(OctreeElement* node,
|
||||||
params.stopReason = EncodeBitstreamParams::DIDNT_FIT;
|
params.stopReason = EncodeBitstreamParams::DIDNT_FIT;
|
||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytesWritten += codeLength; // keep track of byte count
|
bytesWritten += codeLength; // keep track of byte count
|
||||||
|
|
||||||
int currentEncodeLevel = 0;
|
int currentEncodeLevel = 0;
|
||||||
|
|
||||||
// record some stats, this is the one node that we won't record below in the recursion function, so we need to
|
// record some stats, this is the one node that we won't record below in the recursion function, so we need to
|
||||||
// track it here
|
// track it here
|
||||||
if (params.stats) {
|
if (params.stats) {
|
||||||
params.stats->traversed(node);
|
params.stats->traversed(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
int childBytesWritten = encodeTreeBitstreamRecursion(node, packetData, bag, params, currentEncodeLevel);
|
int childBytesWritten = encodeTreeBitstreamRecursion(node, packetData, bag, params, currentEncodeLevel);
|
||||||
|
|
||||||
// if childBytesWritten == 1 then something went wrong... that's not possible
|
// if childBytesWritten == 1 then something went wrong... that's not possible
|
||||||
assert(childBytesWritten != 1);
|
assert(childBytesWritten != 1);
|
||||||
|
|
||||||
// if includeColor and childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some
|
// if includeColor and childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some
|
||||||
// reason couldn't be written... so reset them here... This isn't true for the non-color included case
|
// reason couldn't be written... so reset them here... This isn't true for the non-color included case
|
||||||
if (params.includeColor && childBytesWritten == 2) {
|
if (params.includeColor && childBytesWritten == 2) {
|
||||||
childBytesWritten = 0;
|
childBytesWritten = 0;
|
||||||
|
@ -743,19 +743,19 @@ int Octree::encodeTreeBitstream(OctreeElement* node,
|
||||||
bytesWritten = 0;
|
bytesWritten = 0;
|
||||||
//params.stopReason = EncodeBitstreamParams::DIDNT_FIT;
|
//params.stopReason = EncodeBitstreamParams::DIDNT_FIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytesWritten == 0) {
|
if (bytesWritten == 0) {
|
||||||
packetData->discardSubTree();
|
packetData->discardSubTree();
|
||||||
} else {
|
} else {
|
||||||
packetData->endSubTree();
|
packetData->endSubTree();
|
||||||
}
|
}
|
||||||
|
|
||||||
doneEncoding(node);
|
doneEncoding(node);
|
||||||
|
|
||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Octree::encodeTreeBitstreamRecursion(OctreeElement* node,
|
int Octree::encodeTreeBitstreamRecursion(OctreeElement* node,
|
||||||
OctreePacketData* packetData, OctreeElementBag& bag,
|
OctreePacketData* packetData, OctreeElementBag& bag,
|
||||||
EncodeBitstreamParams& params, int& currentEncodeLevel) const {
|
EncodeBitstreamParams& params, int& currentEncodeLevel) const {
|
||||||
// How many bytes have we written so far at this level;
|
// How many bytes have we written so far at this level;
|
||||||
|
@ -770,7 +770,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node,
|
||||||
|
|
||||||
// Keep track of how deep we've encoded.
|
// Keep track of how deep we've encoded.
|
||||||
currentEncodeLevel++;
|
currentEncodeLevel++;
|
||||||
|
|
||||||
params.maxLevelReached = std::max(currentEncodeLevel,params.maxLevelReached);
|
params.maxLevelReached = std::max(currentEncodeLevel,params.maxLevelReached);
|
||||||
|
|
||||||
// If we've reached our max Search Level, then stop searching.
|
// If we've reached our max Search Level, then stop searching.
|
||||||
|
@ -788,11 +788,11 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node,
|
||||||
return bytesAtThisLevel;
|
return bytesAtThisLevel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// caller can pass NULL as viewFrustum if they want everything
|
// caller can pass NULL as viewFrustum if they want everything
|
||||||
if (params.viewFrustum) {
|
if (params.viewFrustum) {
|
||||||
float distance = node->distanceToCamera(*params.viewFrustum);
|
float distance = node->distanceToCamera(*params.viewFrustum);
|
||||||
float boundaryDistance = boundaryDistanceForRenderLevel(node->getLevel() + params.boundaryLevelAdjust,
|
float boundaryDistance = boundaryDistanceForRenderLevel(node->getLevel() + params.boundaryLevelAdjust,
|
||||||
params.octreeElementSizeScale);
|
params.octreeElementSizeScale);
|
||||||
|
|
||||||
// If we're too far away for our render level, then just return
|
// If we're too far away for our render level, then just return
|
||||||
|
@ -814,28 +814,28 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node,
|
||||||
params.stopReason = EncodeBitstreamParams::OUT_OF_VIEW;
|
params.stopReason = EncodeBitstreamParams::OUT_OF_VIEW;
|
||||||
return bytesAtThisLevel;
|
return bytesAtThisLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ok, we are in view, but if we're in delta mode, then we also want to make sure we weren't already in view
|
// Ok, we are in view, but if we're in delta mode, then we also want to make sure we weren't already in view
|
||||||
// because we don't send nodes from the previously know in view frustum.
|
// because we don't send nodes from the previously know in view frustum.
|
||||||
bool wasInView = false;
|
bool wasInView = false;
|
||||||
|
|
||||||
if (params.deltaViewFrustum && params.lastViewFrustum) {
|
if (params.deltaViewFrustum && params.lastViewFrustum) {
|
||||||
ViewFrustum::location location = node->inFrustum(*params.lastViewFrustum);
|
ViewFrustum::location location = node->inFrustum(*params.lastViewFrustum);
|
||||||
|
|
||||||
// If we're a leaf, then either intersect or inside is considered "formerly in view"
|
// If we're a leaf, then either intersect or inside is considered "formerly in view"
|
||||||
if (node->isLeaf()) {
|
if (node->isLeaf()) {
|
||||||
wasInView = location != ViewFrustum::OUTSIDE;
|
wasInView = location != ViewFrustum::OUTSIDE;
|
||||||
} else {
|
} else {
|
||||||
wasInView = location == ViewFrustum::INSIDE;
|
wasInView = location == ViewFrustum::INSIDE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we were in view, double check that we didn't switch LOD visibility... namely, the was in view doesn't
|
// If we were in view, double check that we didn't switch LOD visibility... namely, the was in view doesn't
|
||||||
// tell us if it was so small we wouldn't have rendered it. Which may be the case. And we may have moved closer
|
// tell us if it was so small we wouldn't have rendered it. Which may be the case. And we may have moved closer
|
||||||
// to it, and so therefore it may now be visible from an LOD perspective, in which case we don't consider it
|
// to it, and so therefore it may now be visible from an LOD perspective, in which case we don't consider it
|
||||||
// as "was in view"...
|
// as "was in view"...
|
||||||
if (wasInView) {
|
if (wasInView) {
|
||||||
float distance = node->distanceToCamera(*params.lastViewFrustum);
|
float distance = node->distanceToCamera(*params.lastViewFrustum);
|
||||||
float boundaryDistance = boundaryDistanceForRenderLevel(node->getLevel() + params.boundaryLevelAdjust,
|
float boundaryDistance = boundaryDistanceForRenderLevel(node->getLevel() + params.boundaryLevelAdjust,
|
||||||
params.octreeElementSizeScale);
|
params.octreeElementSizeScale);
|
||||||
if (distance >= boundaryDistance) {
|
if (distance >= boundaryDistance) {
|
||||||
// This would have been invisible... but now should be visible (we wouldn't be here otherwise)...
|
// This would have been invisible... but now should be visible (we wouldn't be here otherwise)...
|
||||||
|
@ -855,9 +855,9 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node,
|
||||||
return bytesAtThisLevel;
|
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,
|
// 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
|
// then we can also bail early and save bits
|
||||||
if (!params.forceSendScene && !params.deltaViewFrustum &&
|
if (!params.forceSendScene && !params.deltaViewFrustum &&
|
||||||
!node->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE)) {
|
!node->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE)) {
|
||||||
if (params.stats) {
|
if (params.stats) {
|
||||||
params.stats->skippedNoChange(node);
|
params.stats->skippedNoChange(node);
|
||||||
|
@ -896,9 +896,9 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node,
|
||||||
bool keepDiggingDeeper = true; // Assuming we're in view we have a great work ethic, we're always ready for more!
|
bool keepDiggingDeeper = true; // Assuming we're in view we have a great work ethic, we're always ready for more!
|
||||||
|
|
||||||
// At any given point in writing the bitstream, the largest minimum we might need to flesh out the current level
|
// At any given point in writing the bitstream, the largest minimum we might need to flesh out the current level
|
||||||
// is 1 byte for child colors + 3*NUMBER_OF_CHILDREN bytes for the actual colors + 1 byte for child trees.
|
// is 1 byte for child colors + 3*NUMBER_OF_CHILDREN bytes for the actual colors + 1 byte for child trees.
|
||||||
// There could be sub trees below this point, which might take many more bytes, but that's ok, because we can
|
// There could be sub trees below this point, which might take many more bytes, but that's ok, because we can
|
||||||
// always mark our subtrees as not existing and stop the packet at this point, then start up with a new packet
|
// always mark our subtrees as not existing and stop the packet at this point, then start up with a new packet
|
||||||
// for the remaining sub trees.
|
// for the remaining sub trees.
|
||||||
unsigned char childrenExistInTreeBits = 0;
|
unsigned char childrenExistInTreeBits = 0;
|
||||||
unsigned char childrenExistInPacketBits = 0;
|
unsigned char childrenExistInPacketBits = 0;
|
||||||
|
@ -972,7 +972,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node,
|
||||||
// Before we determine consider this further, let's see if it's in our LOD scope...
|
// Before we determine consider this further, let's see if it's in our LOD scope...
|
||||||
float distance = distancesToChildren[i]; // params.viewFrustum ? childNode->distanceToCamera(*params.viewFrustum) : 0;
|
float distance = distancesToChildren[i]; // params.viewFrustum ? childNode->distanceToCamera(*params.viewFrustum) : 0;
|
||||||
float boundaryDistance = !params.viewFrustum ? 1 :
|
float boundaryDistance = !params.viewFrustum ? 1 :
|
||||||
boundaryDistanceForRenderLevel(childNode->getLevel() + params.boundaryLevelAdjust,
|
boundaryDistanceForRenderLevel(childNode->getLevel() + params.boundaryLevelAdjust,
|
||||||
params.octreeElementSizeScale);
|
params.octreeElementSizeScale);
|
||||||
|
|
||||||
if (!(distance < boundaryDistance)) {
|
if (!(distance < boundaryDistance)) {
|
||||||
|
@ -1024,12 +1024,12 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node,
|
||||||
} // wants occlusion culling & isLeaf()
|
} // wants occlusion culling & isLeaf()
|
||||||
|
|
||||||
|
|
||||||
bool shouldRender = !params.viewFrustum
|
bool shouldRender = !params.viewFrustum
|
||||||
? true
|
? true
|
||||||
: childNode->calculateShouldRender(params.viewFrustum,
|
: childNode->calculateShouldRender(params.viewFrustum,
|
||||||
params.octreeElementSizeScale, params.boundaryLevelAdjust);
|
params.octreeElementSizeScale, params.boundaryLevelAdjust);
|
||||||
|
|
||||||
// track some stats
|
// track some stats
|
||||||
if (params.stats) {
|
if (params.stats) {
|
||||||
// don't need to check childNode here, because we can't get here with no childNode
|
// don't need to check childNode here, because we can't get here with no childNode
|
||||||
if (!shouldRender && childNode->isLeaf()) {
|
if (!shouldRender && childNode->isLeaf()) {
|
||||||
|
@ -1040,29 +1040,29 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node,
|
||||||
params.stats->skippedOccluded(childNode);
|
params.stats->skippedOccluded(childNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// track children with actual color, only if the child wasn't previously in view!
|
// track children with actual color, only if the child wasn't previously in view!
|
||||||
if (shouldRender && !childIsOccluded) {
|
if (shouldRender && !childIsOccluded) {
|
||||||
bool childWasInView = false;
|
bool childWasInView = false;
|
||||||
|
|
||||||
if (childNode && params.deltaViewFrustum && params.lastViewFrustum) {
|
if (childNode && params.deltaViewFrustum && params.lastViewFrustum) {
|
||||||
ViewFrustum::location location = childNode->inFrustum(*params.lastViewFrustum);
|
ViewFrustum::location location = childNode->inFrustum(*params.lastViewFrustum);
|
||||||
|
|
||||||
// If we're a leaf, then either intersect or inside is considered "formerly in view"
|
// If we're a leaf, then either intersect or inside is considered "formerly in view"
|
||||||
if (childNode->isLeaf()) {
|
if (childNode->isLeaf()) {
|
||||||
childWasInView = location != ViewFrustum::OUTSIDE;
|
childWasInView = location != ViewFrustum::OUTSIDE;
|
||||||
} else {
|
} else {
|
||||||
childWasInView = location == ViewFrustum::INSIDE;
|
childWasInView = location == ViewFrustum::INSIDE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If our child wasn't in view (or we're ignoring wasInView) then we add it to our sending items.
|
// 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
|
// 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.
|
// need to send it.
|
||||||
if (!childWasInView ||
|
if (!childWasInView ||
|
||||||
(params.deltaViewFrustum &&
|
(params.deltaViewFrustum &&
|
||||||
childNode->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE))){
|
childNode->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE))){
|
||||||
|
|
||||||
childrenColoredBits += (1 << (7 - originalIndex));
|
childrenColoredBits += (1 << (7 - originalIndex));
|
||||||
inViewWithColorCount++;
|
inViewWithColorCount++;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1080,10 +1080,10 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool continueThisLevel = true;
|
bool continueThisLevel = true;
|
||||||
continueThisLevel = packetData->appendBitMask(childrenColoredBits);
|
continueThisLevel = packetData->appendBitMask(childrenColoredBits);
|
||||||
|
|
||||||
if (continueThisLevel) {
|
if (continueThisLevel) {
|
||||||
bytesAtThisLevel += sizeof(childrenColoredBits); // keep track of byte count
|
bytesAtThisLevel += sizeof(childrenColoredBits); // keep track of byte count
|
||||||
if (params.stats) {
|
if (params.stats) {
|
||||||
|
@ -1100,11 +1100,11 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node,
|
||||||
int bytesBeforeChild = packetData->getUncompressedSize();
|
int bytesBeforeChild = packetData->getUncompressedSize();
|
||||||
continueThisLevel = childNode->appendElementData(packetData);
|
continueThisLevel = childNode->appendElementData(packetData);
|
||||||
int bytesAfterChild = packetData->getUncompressedSize();
|
int bytesAfterChild = packetData->getUncompressedSize();
|
||||||
|
|
||||||
if (!continueThisLevel) {
|
if (!continueThisLevel) {
|
||||||
break; // no point in continuing
|
break; // no point in continuing
|
||||||
}
|
}
|
||||||
|
|
||||||
bytesAtThisLevel += (bytesAfterChild - bytesBeforeChild); // keep track of byte count for this child
|
bytesAtThisLevel += (bytesAfterChild - bytesBeforeChild); // keep track of byte count for this child
|
||||||
|
|
||||||
// don't need to check childNode here, because we can't get here with no childNode
|
// don't need to check childNode here, because we can't get here with no childNode
|
||||||
|
@ -1138,7 +1138,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We only need to keep digging, if there is at least one child that is inView, and not a leaf.
|
// We only need to keep digging, if there is at least one child that is inView, and not a leaf.
|
||||||
keepDiggingDeeper = (inViewNotLeafCount > 0);
|
keepDiggingDeeper = (inViewNotLeafCount > 0);
|
||||||
|
|
||||||
|
@ -1181,7 +1181,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node,
|
||||||
// XXXBHG - Note, this seems like the correct logic here, if we included the color in this packet, then
|
// XXXBHG - Note, this seems like the correct logic here, if we included the color in this packet, then
|
||||||
// the LOD logic determined that the child nodes would not be visible... and if so, we shouldn't recurse
|
// the LOD logic determined that the child nodes would not be visible... and if so, we shouldn't recurse
|
||||||
// them further. But... for some time now the code has included and recursed into these child nodes, which
|
// them further. But... for some time now the code has included and recursed into these child nodes, which
|
||||||
// would likely still send the child content, even though the client wouldn't render it. This change is
|
// would likely still send the child content, even though the client wouldn't render it. This change is
|
||||||
// a major savings (~30%) and it seems to work correctly. But I want us to discuss as a group when we do
|
// a major savings (~30%) and it seems to work correctly. But I want us to discuss as a group when we do
|
||||||
// a voxel protocol review.
|
// a voxel protocol review.
|
||||||
//
|
//
|
||||||
|
@ -1232,7 +1232,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node,
|
||||||
|
|
||||||
// repair the child exists mask
|
// repair the child exists mask
|
||||||
continueThisLevel = packetData->updatePriorBitMask(childExistsPlaceHolder, childrenExistInPacketBits);
|
continueThisLevel = packetData->updatePriorBitMask(childExistsPlaceHolder, childrenExistInPacketBits);
|
||||||
|
|
||||||
// If this is the last of the child exists bits, then we're actually be rolling out the entire tree
|
// If this is the last of the child exists bits, then we're actually be rolling out the entire tree
|
||||||
if (params.stats && childrenExistInPacketBits == 0) {
|
if (params.stats && childrenExistInPacketBits == 0) {
|
||||||
params.stats->childBitsRemoved(params.includeExistsBits, params.includeColor);
|
params.stats->childBitsRemoved(params.includeExistsBits, params.includeColor);
|
||||||
|
@ -1241,7 +1241,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node,
|
||||||
if (!continueThisLevel) {
|
if (!continueThisLevel) {
|
||||||
break; // can't continue...
|
break; // can't continue...
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: no need to move the pointer, cause we already stored this
|
// Note: no need to move the pointer, cause we already stored this
|
||||||
} // end if (childTreeBytesOut == 0)
|
} // end if (childTreeBytesOut == 0)
|
||||||
} // end if (oneAtBit(childrenExistInPacketBits, originalIndex))
|
} // end if (oneAtBit(childrenExistInPacketBits, originalIndex))
|
||||||
|
@ -1282,14 +1282,14 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node,
|
||||||
printf("\n");
|
printf("\n");
|
||||||
**/
|
**/
|
||||||
|
|
||||||
// if we were unable to fit this level in our packet, then rewind and add it to the node bag for
|
// if we were unable to fit this level in our packet, then rewind and add it to the node bag for
|
||||||
// sending later...
|
// sending later...
|
||||||
if (continueThisLevel) {
|
if (continueThisLevel) {
|
||||||
continueThisLevel = packetData->endLevel(thisLevelKey);
|
continueThisLevel = packetData->endLevel(thisLevelKey);
|
||||||
} else {
|
} else {
|
||||||
packetData->discardLevel(thisLevelKey);
|
packetData->discardLevel(thisLevelKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!continueThisLevel) {
|
if (!continueThisLevel) {
|
||||||
bag.insert(node);
|
bag.insert(node);
|
||||||
|
|
||||||
|
@ -1325,7 +1325,7 @@ bool Octree::readFromSVOFile(const char* fileName) {
|
||||||
|
|
||||||
unsigned char* dataAt = entireFile;
|
unsigned char* dataAt = entireFile;
|
||||||
unsigned long dataLength = fileLength;
|
unsigned long dataLength = fileLength;
|
||||||
|
|
||||||
// before reading the file, check to see if this version of the Octree supports file versions
|
// before reading the file, check to see if this version of the Octree supports file versions
|
||||||
if (getWantSVOfileVersions()) {
|
if (getWantSVOfileVersions()) {
|
||||||
// if so, read the first byte of the file and see if it matches the expected version code
|
// if so, read the first byte of the file and see if it matches the expected version code
|
||||||
|
@ -1368,7 +1368,7 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* node) {
|
||||||
|
|
||||||
if(file.is_open()) {
|
if(file.is_open()) {
|
||||||
qDebug("saving to file %s...\n", fileName);
|
qDebug("saving to file %s...\n", fileName);
|
||||||
|
|
||||||
// before reading the file, check to see if this version of the Octree supports file versions
|
// before reading the file, check to see if this version of the Octree supports file versions
|
||||||
if (getWantSVOfileVersions()) {
|
if (getWantSVOfileVersions()) {
|
||||||
// if so, read the first byte of the file and see if it matches the expected version code
|
// if so, read the first byte of the file and see if it matches the expected version code
|
||||||
|
@ -1377,7 +1377,7 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* node) {
|
||||||
file.write(&expectedType, sizeof(expectedType));
|
file.write(&expectedType, sizeof(expectedType));
|
||||||
file.write(&expectedVersion, sizeof(expectedType));
|
file.write(&expectedVersion, sizeof(expectedType));
|
||||||
}
|
}
|
||||||
|
|
||||||
OctreeElementBag nodeBag;
|
OctreeElementBag nodeBag;
|
||||||
// If we were given a specific node, start from there, otherwise start from root
|
// If we were given a specific node, start from there, otherwise start from root
|
||||||
if (node) {
|
if (node) {
|
||||||
|
@ -1392,7 +1392,7 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* node) {
|
||||||
|
|
||||||
while (!nodeBag.isEmpty()) {
|
while (!nodeBag.isEmpty()) {
|
||||||
OctreeElement* subTree = nodeBag.extract();
|
OctreeElement* subTree = nodeBag.extract();
|
||||||
|
|
||||||
lockForRead(); // do tree locking down here so that we have shorter slices and less thread contention
|
lockForRead(); // do tree locking down here so that we have shorter slices and less thread contention
|
||||||
EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS);
|
EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS);
|
||||||
bytesWritten = encodeTreeBitstream(subTree, &packetData, nodeBag, params);
|
bytesWritten = encodeTreeBitstream(subTree, &packetData, nodeBag, params);
|
||||||
|
@ -1480,7 +1480,7 @@ void Octree::copyFromTreeIntoSubTree(Octree* sourceTree, OctreeElement* destinat
|
||||||
|
|
||||||
while (!nodeBag.isEmpty()) {
|
while (!nodeBag.isEmpty()) {
|
||||||
OctreeElement* subTree = nodeBag.extract();
|
OctreeElement* subTree = nodeBag.extract();
|
||||||
|
|
||||||
packetData.reset(); // reset between usage
|
packetData.reset(); // reset between usage
|
||||||
|
|
||||||
// ask our tree to write a bitsteam
|
// ask our tree to write a bitsteam
|
||||||
|
@ -1513,7 +1513,7 @@ void Octree::doneEncoding(OctreeElement* node) {
|
||||||
pthread_mutex_lock(&_encodeSetLock);
|
pthread_mutex_lock(&_encodeSetLock);
|
||||||
_codesBeingEncoded.erase(node->getOctalCode());
|
_codesBeingEncoded.erase(node->getOctalCode());
|
||||||
pthread_mutex_unlock(&_encodeSetLock);
|
pthread_mutex_unlock(&_encodeSetLock);
|
||||||
|
|
||||||
// if we have any pending delete codes, then delete them now.
|
// if we have any pending delete codes, then delete them now.
|
||||||
emptyDeleteQueue();
|
emptyDeleteQueue();
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,8 @@
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
|
||||||
#include "OctreePersistThread.h"
|
#include "OctreePersistThread.h"
|
||||||
#include "OctreeServer.h"
|
|
||||||
|
|
||||||
OctreePersistThread::OctreePersistThread(Octree* tree, const char* filename, int persistInterval) :
|
OctreePersistThread::OctreePersistThread(Octree* tree, const QString& filename, int persistInterval) :
|
||||||
_tree(tree),
|
_tree(tree),
|
||||||
_filename(filename),
|
_filename(filename),
|
||||||
_persistInterval(persistInterval),
|
_persistInterval(persistInterval),
|
||||||
|
@ -27,65 +26,67 @@ bool OctreePersistThread::process() {
|
||||||
|
|
||||||
if (!_initialLoadComplete) {
|
if (!_initialLoadComplete) {
|
||||||
uint64_t loadStarted = usecTimestampNow();
|
uint64_t loadStarted = usecTimestampNow();
|
||||||
qDebug("loading Octrees from file: %s...\n", _filename);
|
qDebug() << "loading Octrees from file: " << _filename << "...\n";
|
||||||
|
|
||||||
bool persistantFileRead;
|
bool persistantFileRead;
|
||||||
|
|
||||||
_tree->lockForWrite();
|
_tree->lockForWrite();
|
||||||
{
|
{
|
||||||
PerformanceWarning warn(true, "Loading Octree File", true);
|
PerformanceWarning warn(true, "Loading Octree File", true);
|
||||||
persistantFileRead = _tree->readFromSVOFile(_filename);
|
persistantFileRead = _tree->readFromSVOFile(_filename.toLocal8Bit().constData());
|
||||||
}
|
}
|
||||||
_tree->unlock();
|
_tree->unlock();
|
||||||
|
|
||||||
_loadCompleted = time(0);
|
_loadCompleted = time(0);
|
||||||
uint64_t loadDone = usecTimestampNow();
|
uint64_t loadDone = usecTimestampNow();
|
||||||
_loadTimeUSecs = loadDone - loadStarted;
|
_loadTimeUSecs = loadDone - loadStarted;
|
||||||
|
|
||||||
_tree->clearDirtyBit(); // the tree is clean since we just loaded it
|
_tree->clearDirtyBit(); // the tree is clean since we just loaded it
|
||||||
qDebug("DONE loading Octrees from file... fileRead=%s\n", debug::valueOf(persistantFileRead));
|
qDebug("DONE loading Octrees from file... fileRead=%s\n", debug::valueOf(persistantFileRead));
|
||||||
|
|
||||||
unsigned long nodeCount = OctreeElement::getNodeCount();
|
unsigned long nodeCount = OctreeElement::getNodeCount();
|
||||||
unsigned long internalNodeCount = OctreeElement::getInternalNodeCount();
|
unsigned long internalNodeCount = OctreeElement::getInternalNodeCount();
|
||||||
unsigned long leafNodeCount = OctreeElement::getLeafNodeCount();
|
unsigned long leafNodeCount = OctreeElement::getLeafNodeCount();
|
||||||
qDebug("Nodes after loading scene %lu nodes %lu internal %lu leaves\n", nodeCount, internalNodeCount, leafNodeCount);
|
qDebug("Nodes after loading scene %lu nodes %lu internal %lu leaves\n", nodeCount, internalNodeCount, leafNodeCount);
|
||||||
|
|
||||||
double usecPerGet = (double)OctreeElement::getGetChildAtIndexTime() / (double)OctreeElement::getGetChildAtIndexCalls();
|
double usecPerGet = (double)OctreeElement::getGetChildAtIndexTime() / (double)OctreeElement::getGetChildAtIndexCalls();
|
||||||
qDebug() << "getChildAtIndexCalls=" << OctreeElement::getGetChildAtIndexCalls()
|
qDebug() << "getChildAtIndexCalls=" << OctreeElement::getGetChildAtIndexCalls()
|
||||||
<< " getChildAtIndexTime=" << OctreeElement::getGetChildAtIndexTime() << " perGet=" << usecPerGet << " \n";
|
<< " getChildAtIndexTime=" << OctreeElement::getGetChildAtIndexTime() << " perGet=" << usecPerGet << " \n";
|
||||||
|
|
||||||
double usecPerSet = (double)OctreeElement::getSetChildAtIndexTime() / (double)OctreeElement::getSetChildAtIndexCalls();
|
double usecPerSet = (double)OctreeElement::getSetChildAtIndexTime() / (double)OctreeElement::getSetChildAtIndexCalls();
|
||||||
qDebug() << "setChildAtIndexCalls=" << OctreeElement::getSetChildAtIndexCalls()
|
qDebug() << "setChildAtIndexCalls=" << OctreeElement::getSetChildAtIndexCalls()
|
||||||
<< " setChildAtIndexTime=" << OctreeElement::getSetChildAtIndexTime() << " perset=" << usecPerSet << " \n";
|
<< " setChildAtIndexTime=" << OctreeElement::getSetChildAtIndexTime() << " perset=" << usecPerSet << " \n";
|
||||||
|
|
||||||
_initialLoadComplete = true;
|
_initialLoadComplete = true;
|
||||||
_lastCheck = usecTimestampNow(); // we just loaded, no need to save again
|
_lastCheck = usecTimestampNow(); // we just loaded, no need to save again
|
||||||
|
|
||||||
|
emit loadCompleted();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isStillRunning()) {
|
if (isStillRunning()) {
|
||||||
uint64_t MSECS_TO_USECS = 1000;
|
uint64_t MSECS_TO_USECS = 1000;
|
||||||
uint64_t USECS_TO_SLEEP = 10 * MSECS_TO_USECS; // every 10ms
|
uint64_t USECS_TO_SLEEP = 10 * MSECS_TO_USECS; // every 10ms
|
||||||
usleep(USECS_TO_SLEEP);
|
usleep(USECS_TO_SLEEP);
|
||||||
|
|
||||||
// do our updates then check to save...
|
// do our updates then check to save...
|
||||||
_tree->lockForWrite();
|
_tree->lockForWrite();
|
||||||
_tree->update();
|
_tree->update();
|
||||||
_tree->unlock();
|
_tree->unlock();
|
||||||
|
|
||||||
uint64_t now = usecTimestampNow();
|
uint64_t now = usecTimestampNow();
|
||||||
uint64_t sinceLastSave = now - _lastCheck;
|
uint64_t sinceLastSave = now - _lastCheck;
|
||||||
uint64_t intervalToCheck = _persistInterval * MSECS_TO_USECS;
|
uint64_t intervalToCheck = _persistInterval * MSECS_TO_USECS;
|
||||||
|
|
||||||
if (sinceLastSave > intervalToCheck) {
|
if (sinceLastSave > intervalToCheck) {
|
||||||
// check the dirty bit and persist here...
|
// check the dirty bit and persist here...
|
||||||
_lastCheck = usecTimestampNow();
|
_lastCheck = usecTimestampNow();
|
||||||
if (_tree->isDirty()) {
|
if (_tree->isDirty()) {
|
||||||
qDebug("saving Octrees to file %s...\n",_filename);
|
qDebug() << "saving Octrees to file " << _filename << "...\n";
|
||||||
_tree->writeToSVOFile(_filename);
|
_tree->writeToSVOFile(_filename.toLocal8Bit().constData());
|
||||||
_tree->clearDirtyBit(); // tree is clean after saving
|
_tree->clearDirtyBit(); // tree is clean after saving
|
||||||
qDebug("DONE saving Octrees to file...\n");
|
qDebug("DONE saving Octrees to file...\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return isStillRunning(); // keep running till they terminate us
|
return isStillRunning(); // keep running till they terminate us
|
||||||
}
|
}
|
|
@ -11,27 +11,32 @@
|
||||||
#ifndef __Octree_server__OctreePersistThread__
|
#ifndef __Octree_server__OctreePersistThread__
|
||||||
#define __Octree_server__OctreePersistThread__
|
#define __Octree_server__OctreePersistThread__
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
#include <GenericThread.h>
|
#include <GenericThread.h>
|
||||||
#include <Octree.h>
|
#include "Octree.h"
|
||||||
|
|
||||||
/// Generalized threaded processor for handling received inbound packets.
|
/// Generalized threaded processor for handling received inbound packets.
|
||||||
class OctreePersistThread : public virtual GenericThread {
|
class OctreePersistThread : public GenericThread {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
static const int DEFAULT_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds
|
static const int DEFAULT_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds
|
||||||
|
|
||||||
OctreePersistThread(Octree* tree, const char* filename, int persistInterval = DEFAULT_PERSIST_INTERVAL);
|
OctreePersistThread(Octree* tree, const QString& filename, int persistInterval = DEFAULT_PERSIST_INTERVAL);
|
||||||
|
|
||||||
bool isInitialLoadComplete() const { return _initialLoadComplete; }
|
bool isInitialLoadComplete() const { return _initialLoadComplete; }
|
||||||
|
|
||||||
time_t* getLoadCompleted() { return &_loadCompleted; }
|
time_t* getLoadCompleted() { return &_loadCompleted; }
|
||||||
uint64_t getLoadElapsedTime() const { return _loadTimeUSecs; }
|
uint64_t getLoadElapsedTime() const { return _loadTimeUSecs; }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void loadCompleted();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Implements generic processing behavior for this thread.
|
/// Implements generic processing behavior for this thread.
|
||||||
virtual bool process();
|
virtual bool process();
|
||||||
private:
|
private:
|
||||||
Octree* _tree;
|
Octree* _tree;
|
||||||
const char* _filename;
|
QString _filename;
|
||||||
int _persistInterval;
|
int _persistInterval;
|
||||||
bool _initialLoadComplete;
|
bool _initialLoadComplete;
|
||||||
|
|
|
@ -67,8 +67,8 @@ void ParticleCollisionSystem::checkParticle(Particle* particle) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParticleCollisionSystem::updateCollisionWithVoxels(Particle* particle) {
|
void ParticleCollisionSystem::updateCollisionWithVoxels(Particle* particle) {
|
||||||
glm::vec3 center = particle->getPosition() * static_cast<float>(TREE_SCALE);
|
glm::vec3 center = particle->getPosition() * (float)(TREE_SCALE);
|
||||||
float radius = particle->getRadius() * static_cast<float>(TREE_SCALE);
|
float radius = particle->getRadius() * (float)(TREE_SCALE);
|
||||||
const float ELASTICITY = 0.4f;
|
const float ELASTICITY = 0.4f;
|
||||||
const float DAMPING = 0.0f;
|
const float DAMPING = 0.0f;
|
||||||
const float COLLISION_FREQUENCY = 0.5f;
|
const float COLLISION_FREQUENCY = 0.5f;
|
||||||
|
@ -79,7 +79,7 @@ void ParticleCollisionSystem::updateCollisionWithVoxels(Particle* particle) {
|
||||||
// let the particles run their collision scripts if they have them
|
// let the particles run their collision scripts if they have them
|
||||||
particle->collisionWithVoxel(voxelDetails);
|
particle->collisionWithVoxel(voxelDetails);
|
||||||
|
|
||||||
penetration /= static_cast<float>(TREE_SCALE);
|
penetration /= (float)(TREE_SCALE);
|
||||||
updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
|
updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
|
||||||
applyHardCollision(particle, penetration, ELASTICITY, DAMPING);
|
applyHardCollision(particle, penetration, ELASTICITY, DAMPING);
|
||||||
|
|
||||||
|
@ -88,8 +88,8 @@ void ParticleCollisionSystem::updateCollisionWithVoxels(Particle* particle) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particle) {
|
void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particle) {
|
||||||
glm::vec3 center = particle->getPosition() * static_cast<float>(TREE_SCALE);
|
glm::vec3 center = particle->getPosition() * (float)(TREE_SCALE);
|
||||||
float radius = particle->getRadius() * static_cast<float>(TREE_SCALE);
|
float radius = particle->getRadius() * (float)(TREE_SCALE);
|
||||||
const float ELASTICITY = 1.4f;
|
const float ELASTICITY = 1.4f;
|
||||||
const float DAMPING = 0.0f;
|
const float DAMPING = 0.0f;
|
||||||
const float COLLISION_FREQUENCY = 0.5f;
|
const float COLLISION_FREQUENCY = 0.5f;
|
||||||
|
@ -101,7 +101,7 @@ void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particle) {
|
||||||
particle->collisionWithParticle(penetratedParticle);
|
particle->collisionWithParticle(penetratedParticle);
|
||||||
penetratedParticle->collisionWithParticle(particle);
|
penetratedParticle->collisionWithParticle(particle);
|
||||||
|
|
||||||
penetration /= static_cast<float>(TREE_SCALE);
|
penetration /= (float)(TREE_SCALE);
|
||||||
updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
|
updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
|
||||||
|
|
||||||
// apply a hard collision to both particles of half the penetration each
|
// apply a hard collision to both particles of half the penetration each
|
||||||
|
@ -133,8 +133,8 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//printf("updateCollisionWithAvatars()...\n");
|
//printf("updateCollisionWithAvatars()...\n");
|
||||||
glm::vec3 center = particle->getPosition() * static_cast<float>(TREE_SCALE);
|
glm::vec3 center = particle->getPosition() * (float)(TREE_SCALE);
|
||||||
float radius = particle->getRadius() * static_cast<float>(TREE_SCALE);
|
float radius = particle->getRadius() * (float)(TREE_SCALE);
|
||||||
const float ELASTICITY = 0.4f;
|
const float ELASTICITY = 0.4f;
|
||||||
const float DAMPING = 0.0f;
|
const float DAMPING = 0.0f;
|
||||||
const float COLLISION_FREQUENCY = 0.5f;
|
const float COLLISION_FREQUENCY = 0.5f;
|
||||||
|
@ -156,13 +156,13 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
|
||||||
if (handData->findSpherePenetration(center, radius, penetration, collidingPalm)) {
|
if (handData->findSpherePenetration(center, radius, penetration, collidingPalm)) {
|
||||||
// TODO: dot collidingPalm and hand velocities and skip collision when they are moving apart.
|
// TODO: dot collidingPalm and hand velocities and skip collision when they are moving apart.
|
||||||
// apply a hard collision when ball collides with hand
|
// apply a hard collision when ball collides with hand
|
||||||
penetration /= static_cast<float>(TREE_SCALE);
|
penetration /= (float)(TREE_SCALE);
|
||||||
updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
|
updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
|
||||||
|
|
||||||
// determine if the palm that collided was moving, if so, then we add that palm velocity as well...
|
// determine if the palm that collided was moving, if so, then we add that palm velocity as well...
|
||||||
glm::vec3 addedVelocity = NO_ADDED_VELOCITY;
|
glm::vec3 addedVelocity = NO_ADDED_VELOCITY;
|
||||||
if (collidingPalm) {
|
if (collidingPalm) {
|
||||||
glm::vec3 palmVelocity = collidingPalm->getVelocity() / static_cast<float>(TREE_SCALE);
|
glm::vec3 palmVelocity = collidingPalm->getVelocity() / (float)(TREE_SCALE);
|
||||||
//printf("collidingPalm Velocity=%f,%f,%f\n", palmVelocity.x, palmVelocity.y, palmVelocity.z);
|
//printf("collidingPalm Velocity=%f,%f,%f\n", palmVelocity.x, palmVelocity.y, palmVelocity.z);
|
||||||
addedVelocity = palmVelocity;
|
addedVelocity = palmVelocity;
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,7 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
|
||||||
applyHardCollision(particle, penetration, ELASTICITY, DAMPING, addedVelocity);
|
applyHardCollision(particle, penetration, ELASTICITY, DAMPING, addedVelocity);
|
||||||
} else if (avatar->findSpherePenetration(center, radius, penetration)) {
|
} else if (avatar->findSpherePenetration(center, radius, penetration)) {
|
||||||
// apply hard collision when particle collides with avatar
|
// apply hard collision when particle collides with avatar
|
||||||
penetration /= static_cast<float>(TREE_SCALE);
|
penetration /= (float)(TREE_SCALE);
|
||||||
updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
|
updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
|
||||||
glm::vec3 addedVelocity = avatar->getVelocity();
|
glm::vec3 addedVelocity = avatar->getVelocity();
|
||||||
applyHardCollision(particle, penetration, ELASTICITY, DAMPING, addedVelocity);
|
applyHardCollision(particle, penetration, ELASTICITY, DAMPING, addedVelocity);
|
||||||
|
@ -191,13 +191,13 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
|
||||||
|
|
||||||
if (handData->findSpherePenetration(center, radius, penetration, collidingPalm)) {
|
if (handData->findSpherePenetration(center, radius, penetration, collidingPalm)) {
|
||||||
// apply a hard collision when ball collides with hand
|
// apply a hard collision when ball collides with hand
|
||||||
penetration /= static_cast<float>(TREE_SCALE);
|
penetration /= (float)(TREE_SCALE);
|
||||||
updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
|
updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
|
||||||
|
|
||||||
// determine if the palm that collided was moving, if so, then we add that palm velocity as well...
|
// determine if the palm that collided was moving, if so, then we add that palm velocity as well...
|
||||||
glm::vec3 addedVelocity = NO_ADDED_VELOCITY;
|
glm::vec3 addedVelocity = NO_ADDED_VELOCITY;
|
||||||
if (collidingPalm) {
|
if (collidingPalm) {
|
||||||
glm::vec3 palmVelocity = collidingPalm->getVelocity() / static_cast<float>(TREE_SCALE);
|
glm::vec3 palmVelocity = collidingPalm->getVelocity() / (float)(TREE_SCALE);
|
||||||
//printf("collidingPalm Velocity=%f,%f,%f\n", palmVelocity.x, palmVelocity.y, palmVelocity.z);
|
//printf("collidingPalm Velocity=%f,%f,%f\n", palmVelocity.x, palmVelocity.y, palmVelocity.z);
|
||||||
addedVelocity = palmVelocity;
|
addedVelocity = palmVelocity;
|
||||||
}
|
}
|
||||||
|
@ -205,7 +205,7 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
|
||||||
applyHardCollision(particle, penetration, ELASTICITY, DAMPING, addedVelocity);
|
applyHardCollision(particle, penetration, ELASTICITY, DAMPING, addedVelocity);
|
||||||
|
|
||||||
} else if (avatar->findSpherePenetration(center, radius, penetration)) {
|
} else if (avatar->findSpherePenetration(center, radius, penetration)) {
|
||||||
penetration /= static_cast<float>(TREE_SCALE);
|
penetration /= (float)(TREE_SCALE);
|
||||||
updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
|
updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
|
||||||
glm::vec3 addedVelocity = avatar->getVelocity();
|
glm::vec3 addedVelocity = avatar->getVelocity();
|
||||||
applyHardCollision(particle, penetration, ELASTICITY, DAMPING, addedVelocity);
|
applyHardCollision(particle, penetration, ELASTICITY, DAMPING, addedVelocity);
|
||||||
|
@ -231,7 +231,7 @@ void ParticleCollisionSystem::applyHardCollision(Particle* particle, const glm::
|
||||||
float velocityDotPenetration = glm::dot(velocity, penetration);
|
float velocityDotPenetration = glm::dot(velocity, penetration);
|
||||||
if (velocityDotPenetration > EPSILON) {
|
if (velocityDotPenetration > EPSILON) {
|
||||||
position -= penetration;
|
position -= penetration;
|
||||||
static float HALTING_VELOCITY = 0.2f / static_cast<float>(TREE_SCALE);
|
static float HALTING_VELOCITY = 0.2f / (float)(TREE_SCALE);
|
||||||
// cancel out the velocity component in the direction of penetration
|
// cancel out the velocity component in the direction of penetration
|
||||||
|
|
||||||
float penetrationLength = glm::length(penetration);
|
float penetrationLength = glm::length(penetration);
|
||||||
|
@ -263,12 +263,12 @@ void ParticleCollisionSystem::updateCollisionSound(Particle* particle, const glm
|
||||||
const float COLLISION_LOUDNESS = 1.f;
|
const float COLLISION_LOUDNESS = 1.f;
|
||||||
const float DURATION_SCALING = 0.004f;
|
const float DURATION_SCALING = 0.004f;
|
||||||
const float NOISE_SCALING = 0.1f;
|
const float NOISE_SCALING = 0.1f;
|
||||||
glm::vec3 velocity = particle->getVelocity() * static_cast<float>(TREE_SCALE);
|
glm::vec3 velocity = particle->getVelocity() * (float)(TREE_SCALE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// how do we want to handle this??
|
// how do we want to handle this??
|
||||||
//
|
//
|
||||||
glm::vec3 gravity = particle->getGravity() * static_cast<float>(TREE_SCALE);
|
glm::vec3 gravity = particle->getGravity() * (float)(TREE_SCALE);
|
||||||
|
|
||||||
if (glm::length(gravity) > EPSILON) {
|
if (glm::length(gravity) > EPSILON) {
|
||||||
// If gravity is on, remove the effect of gravity on velocity for this
|
// If gravity is on, remove the effect of gravity on velocity for this
|
||||||
|
|
|
@ -11,22 +11,25 @@
|
||||||
#ifndef __shared__GenericThread__
|
#ifndef __shared__GenericThread__
|
||||||
#define __shared__GenericThread__
|
#define __shared__GenericThread__
|
||||||
|
|
||||||
|
#include <QtCore/QObject>
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
/// A basic generic "thread" class. Handles a single thread of control within the application. Can operate in non-threaded
|
/// A basic generic "thread" class. Handles a single thread of control within the application. Can operate in non-threaded
|
||||||
/// mode but caller must regularly call threadRoutine() method.
|
/// mode but caller must regularly call threadRoutine() method.
|
||||||
class GenericThread {
|
class GenericThread : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
GenericThread();
|
GenericThread();
|
||||||
virtual ~GenericThread();
|
virtual ~GenericThread();
|
||||||
|
|
||||||
/// Call to start the thread.
|
/// Call to start the thread.
|
||||||
/// \param bool isThreaded true by default. false for non-threaded mode and caller must call threadRoutine() regularly.
|
/// \param bool isThreaded true by default. false for non-threaded mode and caller must call threadRoutine() regularly.
|
||||||
void initialize(bool isThreaded = true);
|
void initialize(bool isThreaded = true);
|
||||||
|
|
||||||
/// Call to stop the thread
|
/// Call to stop the thread
|
||||||
void terminate();
|
void terminate();
|
||||||
|
|
||||||
/// If you're running in non-threaded mode, you must call this regularly
|
/// If you're running in non-threaded mode, you must call this regularly
|
||||||
void* threadRoutine();
|
void* threadRoutine();
|
||||||
|
|
||||||
|
@ -42,7 +45,7 @@ protected:
|
||||||
|
|
||||||
/// Unlocks all the resources of the thread.
|
/// Unlocks all the resources of the thread.
|
||||||
void unlock() { pthread_mutex_unlock(&_mutex); }
|
void unlock() { pthread_mutex_unlock(&_mutex); }
|
||||||
|
|
||||||
bool isStillRunning() const { return !_stopThread; }
|
bool isStillRunning() const { return !_stopThread; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include "VoxelTreeElement.h"
|
#include "VoxelTreeElement.h"
|
||||||
#include "VoxelTree.h"
|
#include "VoxelTree.h"
|
||||||
|
|
||||||
VoxelTreeElement::VoxelTreeElement(unsigned char* octalCode) : OctreeElement() {
|
VoxelTreeElement::VoxelTreeElement(unsigned char* octalCode) : OctreeElement() {
|
||||||
init(octalCode);
|
init(octalCode);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ VoxelTreeElement::~VoxelTreeElement() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This will be called primarily on addChildAt(), which means we're adding a child of our
|
// This will be called primarily on addChildAt(), which means we're adding a child of our
|
||||||
// own type to our own tree. This means we should initialize that child with any tree and type
|
// own type to our own tree. This means we should initialize that child with any tree and type
|
||||||
// specific settings that our children must have. One example is out VoxelSystem, which
|
// specific settings that our children must have. One example is out VoxelSystem, which
|
||||||
// we know must match ours.
|
// we know must match ours.
|
||||||
OctreeElement* VoxelTreeElement::createNewElement(unsigned char* octalCode) const {
|
OctreeElement* VoxelTreeElement::createNewElement(unsigned char* octalCode) const {
|
||||||
|
@ -63,10 +63,10 @@ bool VoxelTreeElement::appendElementData(OctreePacketData* packetData) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int VoxelTreeElement::readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
int VoxelTreeElement::readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||||
ReadBitstreamToTreeParams& args) {
|
ReadBitstreamToTreeParams& args) {
|
||||||
const int BYTES_PER_COLOR = 3;
|
const int BYTES_PER_COLOR = 3;
|
||||||
|
|
||||||
// pull the color for this child
|
// pull the color for this child
|
||||||
nodeColor newColor = { 128, 128, 128, 1};
|
nodeColor newColor = { 128, 128, 128, 1};
|
||||||
if (args.includeColor) {
|
if (args.includeColor) {
|
||||||
|
@ -82,11 +82,11 @@ uint8_t VoxelTreeElement::_nextIndex = INDEX_FOR_NULL + 1; // start at 1, 0 is r
|
||||||
std::map<VoxelSystem*, uint8_t> VoxelTreeElement::_mapVoxelSystemPointersToIndex;
|
std::map<VoxelSystem*, uint8_t> VoxelTreeElement::_mapVoxelSystemPointersToIndex;
|
||||||
std::map<uint8_t, VoxelSystem*> VoxelTreeElement::_mapIndexToVoxelSystemPointers;
|
std::map<uint8_t, VoxelSystem*> VoxelTreeElement::_mapIndexToVoxelSystemPointers;
|
||||||
|
|
||||||
VoxelSystem* VoxelTreeElement::getVoxelSystem() const {
|
VoxelSystem* VoxelTreeElement::getVoxelSystem() const {
|
||||||
if (_voxelSystemIndex > INDEX_FOR_NULL) {
|
if (_voxelSystemIndex > INDEX_FOR_NULL) {
|
||||||
if (_mapIndexToVoxelSystemPointers.end() != _mapIndexToVoxelSystemPointers.find(_voxelSystemIndex)) {
|
if (_mapIndexToVoxelSystemPointers.end() != _mapIndexToVoxelSystemPointers.find(_voxelSystemIndex)) {
|
||||||
|
|
||||||
VoxelSystem* voxelSystem = _mapIndexToVoxelSystemPointers[_voxelSystemIndex];
|
VoxelSystem* voxelSystem = _mapIndexToVoxelSystemPointers[_voxelSystemIndex];
|
||||||
return voxelSystem;
|
return voxelSystem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ void VoxelTreeElement::setFalseColored(bool isFalseColored) {
|
||||||
if (_falseColored && !isFalseColored) {
|
if (_falseColored && !isFalseColored) {
|
||||||
memcpy(&_currentColor,&_trueColor,sizeof(nodeColor));
|
memcpy(&_currentColor,&_trueColor,sizeof(nodeColor));
|
||||||
}
|
}
|
||||||
_falseColored = isFalseColored;
|
_falseColored = isFalseColored;
|
||||||
_isDirty = true;
|
_isDirty = true;
|
||||||
_density = 1.0f; // If color set, assume leaf, re-averaging will update density if needed.
|
_density = 1.0f; // If color set, assume leaf, re-averaging will update density if needed.
|
||||||
markWithChangedTime();
|
markWithChangedTime();
|
||||||
|
@ -167,7 +167,7 @@ void VoxelTreeElement::calculateAverageFromChildren() {
|
||||||
density += childAt->getDensity();
|
density += childAt->getDensity();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
density /= (float) NUMBER_OF_CHILDREN;
|
density /= (float) NUMBER_OF_CHILDREN;
|
||||||
//
|
//
|
||||||
// The VISIBLE_ABOVE_DENSITY sets the density of matter above which an averaged color voxel will
|
// The VISIBLE_ABOVE_DENSITY sets the density of matter above which an averaged color voxel will
|
||||||
// be set. It is an important physical constant in our universe. A number below 0.5 will cause
|
// be set. It is an important physical constant in our universe. A number below 0.5 will cause
|
||||||
|
@ -175,9 +175,9 @@ void VoxelTreeElement::calculateAverageFromChildren() {
|
||||||
// less data, which is (probably) going to be preferable because it gives a sense that there is
|
// less data, which is (probably) going to be preferable because it gives a sense that there is
|
||||||
// something out there to go investigate. A number above 0.5 would cause the world to become
|
// something out there to go investigate. A number above 0.5 would cause the world to become
|
||||||
// more 'empty' at a distance. Exactly 0.5 would match the physical world, at least for materials
|
// more 'empty' at a distance. Exactly 0.5 would match the physical world, at least for materials
|
||||||
// that are not shiny and have equivalent ambient reflectance.
|
// that are not shiny and have equivalent ambient reflectance.
|
||||||
//
|
//
|
||||||
const float VISIBLE_ABOVE_DENSITY = 0.10f;
|
const float VISIBLE_ABOVE_DENSITY = 0.10f;
|
||||||
nodeColor newColor = { 0, 0, 0, 0};
|
nodeColor newColor = { 0, 0, 0, 0};
|
||||||
if (density > VISIBLE_ABOVE_DENSITY) {
|
if (density > VISIBLE_ABOVE_DENSITY) {
|
||||||
// The density of material in the space of the voxel sets whether it is actually colored
|
// The density of material in the space of the voxel sets whether it is actually colored
|
||||||
|
@ -188,14 +188,14 @@ void VoxelTreeElement::calculateAverageFromChildren() {
|
||||||
// set the alpha to 1 to indicate that this isn't transparent
|
// set the alpha to 1 to indicate that this isn't transparent
|
||||||
newColor[3] = 1;
|
newColor[3] = 1;
|
||||||
}
|
}
|
||||||
// Set the color from the average of the child colors, and update the density
|
// Set the color from the average of the child colors, and update the density
|
||||||
setColor(newColor);
|
setColor(newColor);
|
||||||
setDensity(density);
|
setDensity(density);
|
||||||
}
|
}
|
||||||
|
|
||||||
// will detect if children are leaves AND the same color
|
// will detect if children are leaves AND the same color
|
||||||
// and in that case will delete the children and make this node
|
// and in that case will delete the children and make this node
|
||||||
// a leaf, returns TRUE if all the leaves are collapsed into a
|
// a leaf, returns TRUE if all the leaves are collapsed into a
|
||||||
// single node
|
// single node
|
||||||
bool VoxelTreeElement::collapseChildren() {
|
bool VoxelTreeElement::collapseChildren() {
|
||||||
// scan children, verify that they are ALL present and accounted for
|
// scan children, verify that they are ALL present and accounted for
|
||||||
|
@ -213,15 +213,15 @@ bool VoxelTreeElement::collapseChildren() {
|
||||||
red = childAt->getColor()[0];
|
red = childAt->getColor()[0];
|
||||||
green = childAt->getColor()[1];
|
green = childAt->getColor()[1];
|
||||||
blue = childAt->getColor()[2];
|
blue = childAt->getColor()[2];
|
||||||
} else if (red != childAt->getColor()[0] ||
|
} else if (red != childAt->getColor()[0] ||
|
||||||
green != childAt->getColor()[1] || blue != childAt->getColor()[2]) {
|
green != childAt->getColor()[1] || blue != childAt->getColor()[2]) {
|
||||||
allChildrenMatch=false;
|
allChildrenMatch=false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (allChildrenMatch) {
|
if (allChildrenMatch) {
|
||||||
//qDebug("allChildrenMatch: pruning tree\n");
|
//qDebug("allChildrenMatch: pruning tree\n");
|
||||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||||
|
@ -230,9 +230,9 @@ bool VoxelTreeElement::collapseChildren() {
|
||||||
setChildAtIndex(i, NULL); // set it to NULL
|
setChildAtIndex(i, NULL); // set it to NULL
|
||||||
}
|
}
|
||||||
nodeColor collapsedColor;
|
nodeColor collapsedColor;
|
||||||
collapsedColor[0]=red;
|
collapsedColor[0]=red;
|
||||||
collapsedColor[1]=green;
|
collapsedColor[1]=green;
|
||||||
collapsedColor[2]=blue;
|
collapsedColor[2]=blue;
|
||||||
collapsedColor[3]=1; // color is set
|
collapsedColor[3]=1; // color is set
|
||||||
setColor(collapsedColor);
|
setColor(collapsedColor);
|
||||||
}
|
}
|
||||||
|
@ -240,7 +240,7 @@ bool VoxelTreeElement::collapseChildren() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool VoxelTreeElement::findSpherePenetration(const glm::vec3& center, float radius,
|
bool VoxelTreeElement::findSpherePenetration(const glm::vec3& center, float radius,
|
||||||
glm::vec3& penetration, void** penetratedObject) const {
|
glm::vec3& penetration, void** penetratedObject) const {
|
||||||
if (_box.findSpherePenetration(center, radius, penetration)) {
|
if (_box.findSpherePenetration(center, radius, penetration)) {
|
||||||
|
|
||||||
|
@ -254,7 +254,7 @@ bool VoxelTreeElement::findSpherePenetration(const glm::vec3& center, float radi
|
||||||
voxelDetails->red = getTrueColor()[RED_INDEX];
|
voxelDetails->red = getTrueColor()[RED_INDEX];
|
||||||
voxelDetails->green = getTrueColor()[GREEN_INDEX];
|
voxelDetails->green = getTrueColor()[GREEN_INDEX];
|
||||||
voxelDetails->blue = getTrueColor()[BLUE_INDEX];
|
voxelDetails->blue = getTrueColor()[BLUE_INDEX];
|
||||||
|
|
||||||
*penetratedObject = (void*)voxelDetails;
|
*penetratedObject = (void*)voxelDetails;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
Loading…
Reference in a new issue