mirror of
https://github.com/overte-org/overte.git
synced 2025-08-04 16:30:10 +02:00
Merge pull request #1095 from ZappoMan/keep_local_voxels
Keep local voxels
This commit is contained in:
commit
c354b4a063
11 changed files with 525 additions and 138 deletions
|
@ -356,8 +356,9 @@ void Application::initializeGL() {
|
|||
|
||||
void Application::paintGL() {
|
||||
PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings));
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::paintGL()");
|
||||
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::paintGL()");
|
||||
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
|
||||
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||
|
@ -545,6 +546,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
}
|
||||
|
||||
bool isShifted = event->modifiers().testFlag(Qt::ShiftModifier);
|
||||
bool isMeta = event->modifiers().testFlag(Qt::ControlModifier);
|
||||
switch (event->key()) {
|
||||
case Qt::Key_Shift:
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelSelectMode)) {
|
||||
|
@ -619,8 +621,10 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
break;
|
||||
|
||||
case Qt::Key_S:
|
||||
if (isShifted) {
|
||||
if (isShifted && !isMeta) {
|
||||
_voxels.collectStatsForTreesAndVBOs();
|
||||
} else if (isShifted && isMeta) {
|
||||
Menu::getInstance()->triggerOption(MenuOption::SuppressShortTimings);
|
||||
} else if (_nudgeStarted) {
|
||||
if (_lookingAlongX) {
|
||||
if (_lookingAwayFromOrigin) {
|
||||
|
@ -1238,6 +1242,8 @@ static glm::vec3 getFaceVector(BoxFace face) {
|
|||
}
|
||||
|
||||
void Application::idle() {
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::idle()");
|
||||
|
||||
timeval check;
|
||||
gettimeofday(&check, NULL);
|
||||
|
@ -1252,7 +1258,7 @@ void Application::idle() {
|
|||
_glWidget->updateGL();
|
||||
_lastTimeUpdated = check;
|
||||
_idleLoopStdev.addValue(timeSinceLastUpdate);
|
||||
|
||||
|
||||
// Record standard deviation and reset counter if needed
|
||||
const int STDEV_SAMPLES = 500;
|
||||
if (_idleLoopStdev.getSamples() > STDEV_SAMPLES) {
|
||||
|
@ -1783,7 +1789,28 @@ void Application::renderFollowIndicator() {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm::vec3 mouseRayDirection) {
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateAvatars()");
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
node->lock();
|
||||
if (node->getLinkedData() != NULL) {
|
||||
Avatar *avatar = (Avatar *)node->getLinkedData();
|
||||
if (!avatar->isInitialized()) {
|
||||
avatar->init();
|
||||
}
|
||||
avatar->simulate(deltaTime, NULL);
|
||||
avatar->setMouseRay(mouseRayOrigin, mouseRayDirection);
|
||||
}
|
||||
node->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::update(float deltaTime) {
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::update()");
|
||||
|
||||
// Use Transmitter Hand to move hand if connected, else use mouse
|
||||
if (_myTransmitter.isConnected()) {
|
||||
|
@ -1884,6 +1911,8 @@ void Application::update(float deltaTime) {
|
|||
(fabs(_myAvatar.getVelocity().x) +
|
||||
fabs(_myAvatar.getVelocity().y) +
|
||||
fabs(_myAvatar.getVelocity().z)) / 3 < MAX_AVATAR_EDIT_VELOCITY) {
|
||||
PerformanceWarning warn(showWarnings, "Application::update()... findRayIntersection()");
|
||||
|
||||
if (_voxels.findRayIntersection(mouseRayOrigin, mouseRayDirection, _mouseVoxel, distance, face)) {
|
||||
if (distance < MAX_VOXEL_EDIT_DISTANCE) {
|
||||
// find the nearest voxel with the desired scale
|
||||
|
@ -1991,22 +2020,11 @@ void Application::update(float deltaTime) {
|
|||
_voxelProcessor.threadRoutine();
|
||||
_voxelEditSender.threadRoutine();
|
||||
}
|
||||
|
||||
|
||||
//loop through all the other avatars and simulate them...
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
node->lock();
|
||||
if (node->getLinkedData() != NULL) {
|
||||
Avatar *avatar = (Avatar *)node->getLinkedData();
|
||||
if (!avatar->isInitialized()) {
|
||||
avatar->init();
|
||||
}
|
||||
avatar->simulate(deltaTime, NULL);
|
||||
avatar->setMouseRay(mouseRayOrigin, mouseRayDirection);
|
||||
}
|
||||
node->unlock();
|
||||
}
|
||||
|
||||
updateAvatars(deltaTime, mouseRayOrigin, mouseRayDirection);
|
||||
|
||||
// Simulate myself
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Gravity)) {
|
||||
_myAvatar.setGravity(_environment.getGravity(_myAvatar.getPosition()));
|
||||
|
@ -2041,6 +2059,7 @@ void Application::update(float deltaTime) {
|
|||
if (_voxels.findRayIntersection(_transmitterPickStart, direction, detail, distance, face)) {
|
||||
minDistance = min(minDistance, distance);
|
||||
}
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
node->lock();
|
||||
if (node->getLinkedData() != NULL) {
|
||||
|
@ -2134,6 +2153,8 @@ void Application::update(float deltaTime) {
|
|||
}
|
||||
|
||||
void Application::updateAvatar(float deltaTime) {
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateAvatar()");
|
||||
|
||||
// rotate body yaw for yaw received from multitouch
|
||||
_myAvatar.setOrientation(_myAvatar.getOrientation()
|
||||
|
@ -2990,51 +3011,54 @@ void Application::displayStats() {
|
|||
std::stringstream voxelStats;
|
||||
voxelStats.precision(4);
|
||||
voxelStats << "Voxels Rendered: " << _voxels.getVoxelsRendered() / 1000.f << "K " <<
|
||||
"Written: " << _voxels.getVoxelsWritten()/1000.f << "K " <<
|
||||
"Updated: " << _voxels.getVoxelsUpdated()/1000.f << "K " <<
|
||||
"Max: " << _voxels.getMaxVoxels()/1000.f << "K ";
|
||||
statsVerticalOffset += PELS_PER_LINE;
|
||||
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str());
|
||||
|
||||
voxelStats.str("");
|
||||
voxelStats <<
|
||||
"Voxels Memory Nodes: " << VoxelNode::getVoxelMemoryUsage() / 1000000.f << "MB "
|
||||
"Octcodes: " << VoxelNode::getOctcodeMemoryUsage() / 1000000.f << "MB "
|
||||
"Voxels Memory Nodes: " << VoxelNode::getTotalMemoryUsage() / 1000000.f << "MB "
|
||||
"Geometry RAM: " << _voxels.getVoxelMemoryUsageRAM() / 1000000.f << "MB " <<
|
||||
"VBO: " << _voxels.getVoxelMemoryUsageVBO() / 1000000.f << "MB ";
|
||||
if (_voxels.hasVoxelMemoryUsageGPU()) {
|
||||
voxelStats << "GPU: " << _voxels.getVoxelMemoryUsageGPU() / 1000000.f << "MB ";
|
||||
}
|
||||
|
||||
// Some debugging for memory usage of VoxelNodes
|
||||
//voxelStats << "VoxelNode size: " << sizeof(VoxelNode) << " bytes ";
|
||||
//voxelStats << "AABox size: " << sizeof(AABox) << " bytes ";
|
||||
|
||||
statsVerticalOffset += PELS_PER_LINE;
|
||||
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str());
|
||||
|
||||
voxelStats.str("");
|
||||
voxelStats <<
|
||||
"Local Voxels Total: " << VoxelNode::getNodeCount() << ", " <<
|
||||
"Internal: " << VoxelNode::getInternalNodeCount() << " , " <<
|
||||
"Leaves: " << VoxelNode::getLeafNodeCount() << "";
|
||||
statsVerticalOffset += PELS_PER_LINE;
|
||||
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str());
|
||||
|
||||
voxelStats.str("");
|
||||
char* voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_VOXELS);
|
||||
voxelStats << "Voxels Sent from Server: " << voxelDetails;
|
||||
statsVerticalOffset += PELS_PER_LINE;
|
||||
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str());
|
||||
|
||||
voxelStats.str("");
|
||||
voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_ELAPSED);
|
||||
voxelStats << "Scene Send Time from Server: " << voxelDetails;
|
||||
statsVerticalOffset += PELS_PER_LINE;
|
||||
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str());
|
||||
|
||||
voxelStats.str("");
|
||||
voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_ENCODE);
|
||||
voxelStats << "Encode Time on Server: " << voxelDetails;
|
||||
statsVerticalOffset += PELS_PER_LINE;
|
||||
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str());
|
||||
|
||||
voxelStats.str("");
|
||||
voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_MODE);
|
||||
voxelStats << "Sending Mode: " << voxelDetails;
|
||||
statsVerticalOffset += PELS_PER_LINE;
|
||||
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str());
|
||||
|
||||
Node *avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
|
||||
char avatarMixerStats[200];
|
||||
|
@ -3049,7 +3073,7 @@ void Application::displayStats() {
|
|||
statsVerticalOffset += PELS_PER_LINE;
|
||||
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, avatarMixerStats);
|
||||
statsVerticalOffset += PELS_PER_LINE;
|
||||
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char *)LeapManager::statusString().c_str());
|
||||
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)LeapManager::statusString().c_str());
|
||||
|
||||
if (_perfStatsOn) {
|
||||
// Get the PerfStats group details. We need to allocate and array of char* long enough to hold 1+groups
|
||||
|
@ -3235,7 +3259,6 @@ void Application::renderCoverageMapsRecursively(CoverageMap* map) {
|
|||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// renderViewFrustum()
|
||||
//
|
||||
// Description: this will render the view frustum bounds for EITHER the head
|
||||
|
@ -3317,7 +3340,7 @@ void Application::renderViewFrustum(ViewFrustum& viewFrustum) {
|
|||
|| Menu::getInstance()->getFrustumDrawMode() == FRUSTUM_DRAW_MODE_PLANES
|
||||
|| Menu::getInstance()->getFrustumDrawMode() == FRUSTUM_DRAW_MODE_FAR_PLANE) {
|
||||
// viewFrustum.getFar plane - bottom edge
|
||||
glColor3f(0,1,0); // GREEN!!!
|
||||
glColor3f(0,1,0);
|
||||
glVertex3f(viewFrustum.getFarBottomLeft().x, viewFrustum.getFarBottomLeft().y, viewFrustum.getFarBottomLeft().z);
|
||||
glVertex3f(viewFrustum.getFarBottomRight().x, viewFrustum.getFarBottomRight().y, viewFrustum.getFarBottomRight().z);
|
||||
|
||||
|
@ -3685,6 +3708,9 @@ int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLeng
|
|||
|
||||
// Receive packets from other nodes/servers and decide what to do with them!
|
||||
void* Application::networkReceive(void* args) {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::networkReceive()");
|
||||
|
||||
sockaddr senderAddress;
|
||||
ssize_t bytesReceived;
|
||||
|
||||
|
@ -3712,6 +3738,9 @@ void* Application::networkReceive(void* args) {
|
|||
case PACKET_TYPE_ERASE_VOXEL:
|
||||
case PACKET_TYPE_VOXEL_STATS:
|
||||
case PACKET_TYPE_ENVIRONMENT_DATA: {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::networkReceive()... _voxelProcessor.queueReceivedPacket()");
|
||||
|
||||
// add this packet to our list of voxel packets and process them on the voxel processing
|
||||
app->_voxelProcessor.queueReceivedPacket(senderAddress, app->_incomingPacket, bytesReceived);
|
||||
break;
|
||||
|
|
|
@ -216,6 +216,7 @@ private:
|
|||
void renderLookatIndicator(glm::vec3 pointOfInterest, Camera& whichCamera);
|
||||
void renderFollowIndicator();
|
||||
void updateAvatar(float deltaTime);
|
||||
void updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm::vec3 mouseRayDirection);
|
||||
void loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum);
|
||||
|
||||
void displayOculus(Camera& whichCamera);
|
||||
|
|
|
@ -275,16 +275,25 @@ Menu::Menu() :
|
|||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelsAsPoints, 0,
|
||||
false, appInstance->getVoxels(), SLOT(setVoxelsAsPoints(bool)));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::FastVoxelPipeline, 0,
|
||||
false, appInstance->getVoxels(), SLOT(setUseFastVoxelPipeline(bool)));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontRemoveOutOfView);
|
||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::HideOutOfView);
|
||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::ConstantCulling);
|
||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AutomaticallyAuditTree);
|
||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures);
|
||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion);
|
||||
|
||||
|
||||
QMenu* cullingOptionsMenu = voxelOptionsMenu->addMenu("Culling Options");
|
||||
addDisabledActionAndSeparator(cullingOptionsMenu, "Standard Settings");
|
||||
addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::OldVoxelCullingMode, 0,
|
||||
false, this, SLOT(setOldVoxelCullingMode(bool)));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::NewVoxelCullingMode, 0,
|
||||
false, this, SLOT(setNewVoxelCullingMode(bool)));
|
||||
|
||||
addDisabledActionAndSeparator(cullingOptionsMenu, "Individual Option Settings");
|
||||
addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::FastVoxelPipeline, 0,
|
||||
false, appInstance->getVoxels(), SLOT(setUseFastVoxelPipeline(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::DontRemoveOutOfView);
|
||||
addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::HideOutOfView);
|
||||
addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::UseDeltaFrustumInHide);
|
||||
addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::ConstantCulling);
|
||||
|
||||
|
||||
QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options");
|
||||
|
||||
|
@ -377,8 +386,17 @@ Menu::Menu() :
|
|||
|
||||
|
||||
QMenu* renderDebugMenu = developerMenu->addMenu("Render Debugging Tools");
|
||||
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::PipelineWarnings);
|
||||
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::SuppressShortTimings);
|
||||
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::PipelineWarnings, Qt::CTRL | Qt::SHIFT | Qt::Key_P);
|
||||
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::SuppressShortTimings, Qt::CTRL | Qt::SHIFT | Qt::Key_S);
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::AutomaticallyAuditTree);
|
||||
|
||||
|
||||
addActionToQMenuAndActionHash(renderDebugMenu,
|
||||
MenuOption::ShowAllLocalVoxels,
|
||||
Qt::CTRL | Qt::Key_A,
|
||||
appInstance->getVoxels(),
|
||||
SLOT(showAllLocalVoxels()));
|
||||
|
||||
addActionToQMenuAndActionHash(renderDebugMenu,
|
||||
MenuOption::KillLocalVoxels,
|
||||
|
@ -1085,4 +1103,30 @@ void Menu::updateFrustumRenderModeAction() {
|
|||
}
|
||||
}
|
||||
|
||||
void Menu::setOldVoxelCullingMode(bool oldMode) {
|
||||
setVoxelCullingMode(oldMode);
|
||||
}
|
||||
|
||||
void Menu::setNewVoxelCullingMode(bool newMode) {
|
||||
setVoxelCullingMode(!newMode);
|
||||
}
|
||||
|
||||
/// This will switch on or off several different individual settings options all at once based on choosing with Old or New
|
||||
/// voxel culling mode.
|
||||
void Menu::setVoxelCullingMode(bool oldMode) {
|
||||
const QString menus[] = { MenuOption::FastVoxelPipeline, MenuOption::DontRemoveOutOfView, MenuOption::HideOutOfView,
|
||||
MenuOption::UseDeltaFrustumInHide, MenuOption::ConstantCulling};
|
||||
bool oldModeValue[] = { false, false, false, false, false };
|
||||
bool newModeValue[] = { true, true, true, true, true };
|
||||
|
||||
for (int i = 0; i < sizeof(menus) / sizeof(menus[0]); i++) {
|
||||
bool desiredValue = oldMode ? oldModeValue[i] : newModeValue[i];
|
||||
if (isOptionChecked(menus[i]) != desiredValue) {
|
||||
triggerOption(menus[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// set the checkmarks accordingly...
|
||||
_actionHash.value(MenuOption::OldVoxelCullingMode)->setChecked(oldMode);
|
||||
_actionHash.value(MenuOption::NewVoxelCullingMode)->setChecked(!oldMode);
|
||||
}
|
||||
|
|
|
@ -81,6 +81,8 @@ private slots:
|
|||
void chooseVoxelPaintColor();
|
||||
void runTests();
|
||||
void resetSwatchColors();
|
||||
void setOldVoxelCullingMode(bool oldMode);
|
||||
void setNewVoxelCullingMode(bool newMode);
|
||||
|
||||
private:
|
||||
static Menu* _instance;
|
||||
|
@ -108,6 +110,7 @@ private:
|
|||
const char* member = NULL);
|
||||
|
||||
void updateFrustumRenderModeAction();
|
||||
void setVoxelCullingMode(bool oldMode);
|
||||
|
||||
QHash<QString, QAction*> _actionHash;
|
||||
int _audioJitterBufferSamples; /// number of extra samples to wait before starting audio playback
|
||||
|
@ -182,9 +185,11 @@ namespace MenuOption {
|
|||
const QString LookAtVectors = "Look-at Vectors";
|
||||
const QString LowRes = "Lower Resolution While Moving";
|
||||
const QString Mirror = "Mirror";
|
||||
const QString NewVoxelCullingMode = "New Voxel Culling Mode";
|
||||
const QString NudgeVoxels = "Nudge";
|
||||
const QString OcclusionCulling = "Occlusion Culling";
|
||||
const QString OffAxisProjection = "Off-Axis Projection";
|
||||
const QString OldVoxelCullingMode = "Old Voxel Culling Mode";
|
||||
const QString TurnWithHead = "Turn using Head";
|
||||
const QString Oscilloscope = "Audio Oscilloscope";
|
||||
const QString Pair = "Pair";
|
||||
|
@ -198,6 +203,7 @@ namespace MenuOption {
|
|||
const QString SendVoxelColors = "Colored Voxels";
|
||||
const QString SettingsImport = "Import Settings";
|
||||
const QString SettingsExport = "Export Settings";
|
||||
const QString ShowAllLocalVoxels = "Show All Local Voxels";
|
||||
const QString ShowTrueColors = "Show TRUE Colors";
|
||||
const QString SimulateLeapHand = "Simulate Leap Hand";
|
||||
const QString SkeletonTracking = "Skeleton Tracking";
|
||||
|
@ -210,6 +216,7 @@ namespace MenuOption {
|
|||
const QString TreeStats = "Calculate Tree Stats";
|
||||
const QString TransmitterDrive = "Transmitter Drive";
|
||||
const QString Quit = "Quit";
|
||||
const QString UseDeltaFrustumInHide = "Use Delta View Frustums when Culling";
|
||||
const QString UseVoxelShader = "Use Voxel Shader";
|
||||
const QString VoxelsAsPoints = "Draw Voxels as Points";
|
||||
const QString Voxels = "Voxels";
|
||||
|
|
|
@ -17,6 +17,11 @@
|
|||
void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"VoxelPacketProcessor::processPacket()");
|
||||
|
||||
const int WAY_BEHIND = 300;
|
||||
if (packetsToProcessCount() > WAY_BEHIND && Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) {
|
||||
qDebug("VoxelPacketProcessor::processPacket() packets to process=%d\n", packetsToProcessCount());
|
||||
}
|
||||
ssize_t messageLength = packetLength;
|
||||
|
||||
Application* app = Application::getInstance();
|
||||
|
|
|
@ -73,6 +73,7 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels)
|
|||
_writeRenderFullVBO = true;
|
||||
_readRenderFullVBO = true;
|
||||
_tree = new VoxelTree();
|
||||
|
||||
_tree->rootNode->setVoxelSystem(this);
|
||||
pthread_mutex_init(&_bufferWriteLock, NULL);
|
||||
pthread_mutex_init(&_treeLock, NULL);
|
||||
|
@ -106,6 +107,8 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels)
|
|||
|
||||
_inSetupNewVoxelsForDrawing = false;
|
||||
_useFastVoxelPipeline = false;
|
||||
|
||||
_culledOnce = false;
|
||||
}
|
||||
|
||||
void VoxelSystem::voxelDeleted(VoxelNode* node) {
|
||||
|
@ -133,7 +136,7 @@ void VoxelSystem::voxelUpdated(VoxelNode* node) {
|
|||
}
|
||||
|
||||
if (node->getVoxelSystem() == this) {
|
||||
bool shouldRender = false; // assume we don't need to render it
|
||||
bool shouldRender = false; // assume we don't need to render it
|
||||
// if it's colored, we might need to render it!
|
||||
shouldRender = node->calculateShouldRender(_viewFrustum);
|
||||
|
||||
|
@ -228,16 +231,21 @@ void VoxelSystem::freeBufferIndex(glBufferIndex index) {
|
|||
|
||||
// This will run through the list of _freeIndexes and reset their VBO array values to be "invisible".
|
||||
void VoxelSystem::clearFreeBufferIndexes() {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "###### clearFreeBufferIndexes()");
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "clearFreeBufferIndexes()");
|
||||
_voxelsInWriteArrays = 0; // reset our VBO
|
||||
_abandonedVBOSlots = 0;
|
||||
|
||||
// clear out freeIndexes
|
||||
pthread_mutex_lock(&_freeIndexLock);
|
||||
_freeIndexes.clear();
|
||||
{
|
||||
PerformanceWarning warn(showWarnings,"clearFreeBufferIndexes() : pthread_mutex_lock(&_freeIndexLock)");
|
||||
pthread_mutex_lock(&_freeIndexLock);
|
||||
}
|
||||
{
|
||||
PerformanceWarning warn(showWarnings,"clearFreeBufferIndexes() : _freeIndexes.clear()");
|
||||
_freeIndexes.clear();
|
||||
}
|
||||
pthread_mutex_unlock(&_freeIndexLock);
|
||||
|
||||
clearAllNodesBufferIndex();
|
||||
}
|
||||
|
||||
VoxelSystem::~VoxelSystem() {
|
||||
|
@ -744,7 +752,6 @@ void VoxelSystem::checkForCulling() {
|
|||
&& !isViewChanging()
|
||||
)
|
||||
) {
|
||||
|
||||
_lastViewCulling = start;
|
||||
|
||||
// When we call removeOutOfView() voxels, we don't actually remove the voxels from the VBOs, but we do remove
|
||||
|
@ -949,6 +956,12 @@ int VoxelSystem::forceRemoveNodeFromArrays(VoxelNode* node) {
|
|||
int VoxelSystem::updateNodeInArrays(VoxelNode* node, bool reuseIndex, bool forceDraw) {
|
||||
// If we've run out of room, then just bail...
|
||||
if (_voxelsInWriteArrays >= _maxVoxels) {
|
||||
// We need to think about what else we can do in this case. This basically means that all of our available
|
||||
// VBO slots are used up, but we're trying to render more voxels. At this point, if this happens we'll just
|
||||
// not render these Voxels. We need to think about ways to keep the entire scene intact but maybe lower quality
|
||||
// possibly shifting down to lower LOD or something. This debug message is to help identify, if/when/how this
|
||||
// state actually occurs.
|
||||
qDebug("OHHHH NOOOOOO!!!! updateNodeInArrays() BAILING (_voxelsInWriteArrays >= _maxVoxels)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1061,10 +1074,24 @@ void VoxelSystem::changeTree(VoxelTree* newTree) {
|
|||
}
|
||||
|
||||
void VoxelSystem::updateFullVBOs() {
|
||||
updateVBOSegment(0, _voxelsInReadArrays);
|
||||
bool outputWarning = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(outputWarning, "updateFullVBOs()");
|
||||
|
||||
{
|
||||
static char buffer[128] = { 0 };
|
||||
if (outputWarning) {
|
||||
sprintf(buffer, "updateFullVBOs() : updateVBOSegment(0, _voxelsInReadArrays=%lu);", _voxelsInReadArrays);
|
||||
};
|
||||
|
||||
PerformanceWarning warn(outputWarning,buffer);
|
||||
updateVBOSegment(0, _voxelsInReadArrays);
|
||||
}
|
||||
|
||||
// consider the _readVoxelDirtyArray[] clean!
|
||||
memset(_readVoxelDirtyArray, false, _voxelsInReadArrays * sizeof(bool));
|
||||
{
|
||||
PerformanceWarning warn(outputWarning,"updateFullVBOs() : memset(_readVoxelDirtyArray...)");
|
||||
// consider the _readVoxelDirtyArray[] clean!
|
||||
memset(_readVoxelDirtyArray, false, _voxelsInReadArrays * sizeof(bool));
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelSystem::updatePartialVBOs() {
|
||||
|
@ -1116,6 +1143,9 @@ void VoxelSystem::updateVBOs() {
|
|||
}
|
||||
|
||||
void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd) {
|
||||
bool showWarning = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarning, "updateVBOSegment()");
|
||||
|
||||
if (_useVoxelShader) {
|
||||
int segmentLength = (segmentEnd - segmentStart) + 1;
|
||||
GLintptr segmentStartAt = segmentStart * sizeof(VoxelShaderVBOData);
|
||||
|
@ -1130,18 +1160,36 @@ void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex seg
|
|||
GLintptr segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLfloat);
|
||||
GLsizeiptr segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLfloat);
|
||||
GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * vertexPointsPerVoxel);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);
|
||||
|
||||
{
|
||||
PerformanceWarning warn(showWarning, "updateVBOSegment() : glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);");
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceWarning warn(showWarning, "updateVBOSegment() : glBufferSubData() _vboVerticesID);");
|
||||
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);
|
||||
}
|
||||
|
||||
segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLubyte);
|
||||
segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLubyte);
|
||||
GLubyte* readColorsFrom = _readColorsArray + (segmentStart * vertexPointsPerVoxel);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom);
|
||||
|
||||
{
|
||||
PerformanceWarning warn(showWarning, "updateVBOSegment() : glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);");
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceWarning warn(showWarning, "updateVBOSegment() : glBufferSubData() _vboColorsID);");
|
||||
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelSystem::render(bool texture) {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "render()");
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "render()");
|
||||
|
||||
// If we got here and we're not initialized then bail!
|
||||
if (!_initialized) {
|
||||
|
@ -1153,8 +1201,7 @@ void VoxelSystem::render(bool texture) {
|
|||
bool dontCallOpenGLDraw = Menu::getInstance()->isOptionChecked(MenuOption::DontCallOpenGLForVoxels);
|
||||
// if not don't... then do...
|
||||
if (_useVoxelShader) {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"render().. _useVoxelShader openGL..");
|
||||
PerformanceWarning warn(showWarnings,"render().. _useVoxelShader openGL..");
|
||||
|
||||
|
||||
//Define this somewhere in your header file
|
||||
|
@ -1200,68 +1247,78 @@ void VoxelSystem::render(bool texture) {
|
|||
glDisableVertexAttribArray(attributeLocation);
|
||||
}
|
||||
} else {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "render().. openGL...");
|
||||
PerformanceWarning warn(showWarnings, "render().. TRIANGLES...");
|
||||
|
||||
// tell OpenGL where to find vertex and color information
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
{
|
||||
PerformanceWarning warn(showWarnings,"render().. setup before glDrawRangeElementsEXT()...");
|
||||
|
||||
// tell OpenGL where to find vertex and color information
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||
glVertexPointer(3, GL_FLOAT, 0, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||
glVertexPointer(3, GL_FLOAT, 0, 0);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||
glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||
glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
|
||||
|
||||
applyScaleAndBindProgram(texture);
|
||||
applyScaleAndBindProgram(texture);
|
||||
|
||||
// for performance, enable backface culling
|
||||
glEnable(GL_CULL_FACE);
|
||||
// for performance, enable backface culling
|
||||
glEnable(GL_CULL_FACE);
|
||||
}
|
||||
|
||||
// draw voxels in 6 passes
|
||||
|
||||
if (!dontCallOpenGLDraw) {
|
||||
PerformanceWarning warn(showWarnings, "render().. glDrawRangeElementsEXT()...");
|
||||
|
||||
glNormal3f(0,1.0f,0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesTop);
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
|
||||
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glNormal3f(0,-1.0f,0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBottom);
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
|
||||
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glNormal3f(-1.0f,0,0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesLeft);
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
|
||||
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glNormal3f(1.0f,0,0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesRight);
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
|
||||
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glNormal3f(0,0,-1.0f);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesFront);
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
|
||||
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glNormal3f(0,0,1.0f);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBack);
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
|
||||
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||
}
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
{
|
||||
PerformanceWarning warn(showWarnings, "render().. cleanup after glDrawRangeElementsEXT()...");
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
removeScaleAndReleaseProgram(texture);
|
||||
removeScaleAndReleaseProgram(texture);
|
||||
|
||||
// deactivate vertex and color arrays after drawing
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
// deactivate vertex and color arrays after drawing
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
// bind with 0 to switch back to normal operation
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
// bind with 0 to switch back to normal operation
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1526,11 +1583,11 @@ public:
|
|||
VoxelSystem* thisVoxelSystem;
|
||||
ViewFrustum thisViewFrustum;
|
||||
VoxelNodeBag dontRecurseBag;
|
||||
unsigned long nodesScanned;
|
||||
unsigned long nodesRemoved;
|
||||
unsigned long nodesInside;
|
||||
unsigned long nodesIntersect;
|
||||
unsigned long nodesOutside;
|
||||
unsigned long nodesScanned;
|
||||
unsigned long nodesRemoved;
|
||||
unsigned long nodesInside;
|
||||
unsigned long nodesIntersect;
|
||||
unsigned long nodesOutside;
|
||||
VoxelNode* insideRoot;
|
||||
VoxelNode* outsideRoot;
|
||||
|
||||
|
@ -1611,10 +1668,10 @@ bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) {
|
|||
bool VoxelSystem::isViewChanging() {
|
||||
bool result = false; // assume the best
|
||||
|
||||
// If our viewFrustum has changed since our _lastKnowViewFrustum
|
||||
if (!_lastKnowViewFrustum.matches(_viewFrustum)) {
|
||||
// If our viewFrustum has changed since our _lastKnownViewFrustum
|
||||
if (!_lastKnownViewFrustum.matches(_viewFrustum)) {
|
||||
result = true;
|
||||
_lastKnowViewFrustum = *_viewFrustum; // save last known
|
||||
_lastKnownViewFrustum = *_viewFrustum; // save last known
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -1627,7 +1684,7 @@ bool VoxelSystem::hasViewChanged() {
|
|||
return false;
|
||||
}
|
||||
|
||||
// If our viewFrustum has changed since our _lastKnowViewFrustum
|
||||
// If our viewFrustum has changed since our _lastKnownViewFrustum
|
||||
if (!_lastStableViewFrustum.matches(_viewFrustum)) {
|
||||
result = true;
|
||||
_lastStableViewFrustum = *_viewFrustum; // save last stable
|
||||
|
@ -1652,27 +1709,92 @@ void VoxelSystem::removeOutOfView() {
|
|||
}
|
||||
}
|
||||
|
||||
// combines the removeOutOfView args into a single class
|
||||
class showAllLocalVoxelsArgs {
|
||||
public:
|
||||
VoxelSystem* thisVoxelSystem;
|
||||
ViewFrustum thisViewFrustum;
|
||||
unsigned long nodesScanned;
|
||||
|
||||
showAllLocalVoxelsArgs(VoxelSystem* voxelSystem) :
|
||||
thisVoxelSystem(voxelSystem),
|
||||
thisViewFrustum(*voxelSystem->getViewFrustum()),
|
||||
nodesScanned(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void VoxelSystem::showAllLocalVoxels() {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "showAllLocalVoxels()");
|
||||
showAllLocalVoxelsArgs args(this);
|
||||
_tree->recurseTreeWithOperation(showAllLocalVoxelsOperation,(void*)&args);
|
||||
|
||||
bool showRemoveDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
if (showRemoveDebugDetails) {
|
||||
qDebug("showAllLocalVoxels() scanned=%ld \n",args.nodesScanned );
|
||||
}
|
||||
}
|
||||
|
||||
bool VoxelSystem::showAllLocalVoxelsOperation(VoxelNode* node, void* extraData) {
|
||||
showAllLocalVoxelsArgs* args = (showAllLocalVoxelsArgs*)extraData;
|
||||
|
||||
args->nodesScanned++;
|
||||
|
||||
bool shouldRender = true; // node->calculateShouldRender(&args->thisViewFrustum);
|
||||
node->setShouldRender(shouldRender);
|
||||
|
||||
if (shouldRender) {
|
||||
bool falseColorize = false;
|
||||
if (falseColorize) {
|
||||
node->setFalseColor(0,0,255); // false colorize
|
||||
}
|
||||
// These are both needed to force redraw...
|
||||
node->setDirtyBit();
|
||||
node->markWithChangedTime();
|
||||
}
|
||||
|
||||
return true; // keep recursing!
|
||||
}
|
||||
|
||||
|
||||
// combines the removeOutOfView args into a single class
|
||||
class hideOutOfViewArgs {
|
||||
public:
|
||||
VoxelSystem* thisVoxelSystem;
|
||||
VoxelTree* tree;
|
||||
ViewFrustum thisViewFrustum;
|
||||
unsigned long nodesScanned;
|
||||
unsigned long nodesRemoved;
|
||||
unsigned long nodesInside;
|
||||
unsigned long nodesIntersect;
|
||||
unsigned long nodesOutside;
|
||||
VoxelSystem* thisVoxelSystem;
|
||||
VoxelTree* tree;
|
||||
ViewFrustum thisViewFrustum;
|
||||
ViewFrustum lastViewFrustum;
|
||||
bool culledOnce;
|
||||
bool wantDeltaFrustums;
|
||||
unsigned long nodesScanned;
|
||||
unsigned long nodesRemoved;
|
||||
unsigned long nodesInside;
|
||||
unsigned long nodesIntersect;
|
||||
unsigned long nodesOutside;
|
||||
unsigned long nodesInsideInside;
|
||||
unsigned long nodesIntersectInside;
|
||||
unsigned long nodesOutsideInside;
|
||||
unsigned long nodesInsideOutside;
|
||||
unsigned long nodesOutsideOutside;
|
||||
|
||||
hideOutOfViewArgs(VoxelSystem* voxelSystem, VoxelTree* tree, bool widenViewFrustum = true) :
|
||||
hideOutOfViewArgs(VoxelSystem* voxelSystem, VoxelTree* tree,
|
||||
bool culledOnce, bool widenViewFrustum, bool wantDeltaFrustums) :
|
||||
thisVoxelSystem(voxelSystem),
|
||||
tree(tree),
|
||||
thisViewFrustum(*voxelSystem->getViewFrustum()),
|
||||
lastViewFrustum(*voxelSystem->getLastCulledViewFrustum()),
|
||||
culledOnce(culledOnce),
|
||||
wantDeltaFrustums(wantDeltaFrustums),
|
||||
nodesScanned(0),
|
||||
nodesRemoved(0),
|
||||
nodesInside(0),
|
||||
nodesIntersect(0),
|
||||
nodesOutside(0)
|
||||
nodesOutside(0),
|
||||
nodesInsideInside(0),
|
||||
nodesIntersectInside(0),
|
||||
nodesOutsideInside(0),
|
||||
nodesInsideOutside(0),
|
||||
nodesOutsideOutside(0)
|
||||
{
|
||||
// Widen the FOV for trimming
|
||||
if (widenViewFrustum) {
|
||||
|
@ -1685,34 +1807,88 @@ public:
|
|||
};
|
||||
|
||||
void VoxelSystem::hideOutOfView() {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "hideOutOfView()");
|
||||
hideOutOfViewArgs args(this, this->_tree, true); // widen to match server!
|
||||
bool showDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showDebugDetails, "hideOutOfView()", showDebugDetails);
|
||||
bool widenFrustum = true;
|
||||
bool wantDeltaFrustums = false; // Menu::getInstance()->isOptionChecked(MenuOption::UseDeltaFrustumInHide);
|
||||
hideOutOfViewArgs args(this, this->_tree, _culledOnce, widenFrustum, wantDeltaFrustums);
|
||||
|
||||
const bool wantViewFrustumDebugging = false; // change to true for additional debugging
|
||||
if (wantViewFrustumDebugging) {
|
||||
args.thisViewFrustum.printDebugDetails();
|
||||
if (_culledOnce) {
|
||||
args.lastViewFrustum.printDebugDetails();
|
||||
}
|
||||
}
|
||||
|
||||
if (_culledOnce && args.lastViewFrustum.matches(args.thisViewFrustum)) {
|
||||
//printf("view frustum hasn't changed BAIL!!!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Changed hideOutOfView() to support "delta" view frustums and only hide/show items that are in the difference
|
||||
// between the two view frustums. There are some potential problems with this idea...
|
||||
//
|
||||
// 1) This might work well for rotating, but what about moving forward?
|
||||
// in the move forward case, you'll get new voxel details, but those
|
||||
// new voxels will be in the last view... does that work? This works
|
||||
// ok for now because voxel server resends them and so they get redisplayed,
|
||||
// but this will not work if we update the voxel server to send less data.
|
||||
//
|
||||
// 2) what about voxels coming in from the network that are OUTSIDE of the view
|
||||
// frustum... they don't get hidden... and so we can't assume they are correctly
|
||||
// hidden... we could solve this with checking in view on voxelUpdated...
|
||||
//
|
||||
_tree->recurseTreeWithOperation(hideOutOfViewOperation,(void*)&args);
|
||||
_lastCulledViewFrustum = args.thisViewFrustum; // save last stable
|
||||
_culledOnce = true;
|
||||
|
||||
if (args.nodesRemoved) {
|
||||
_tree->setDirtyBit();
|
||||
setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY);
|
||||
}
|
||||
|
||||
|
||||
bool showRemoveDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
if (showRemoveDebugDetails) {
|
||||
if (showDebugDetails) {
|
||||
qDebug("hideOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld\n",
|
||||
args.nodesScanned, args.nodesRemoved, args.nodesInside,
|
||||
args.nodesIntersect, args.nodesOutside
|
||||
);
|
||||
qDebug(" inside/inside=%ld intersect/inside=%ld outside/outside=%ld\n",
|
||||
args.nodesInsideInside, args.nodesIntersectInside, args.nodesOutsideOutside
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
bool VoxelSystem::hideAllSubTreeOperation(VoxelNode* node, void* extraData) {
|
||||
hideOutOfViewArgs* args = (hideOutOfViewArgs*)extraData;
|
||||
|
||||
// If we've culled at least once, then we will use the status of this voxel in the last culled frustum to determine
|
||||
// how to proceed. If we've never culled, then we just consider all these voxels to be UNKNOWN so that we will not
|
||||
// consider that case.
|
||||
ViewFrustum::location inLastCulledFrustum;
|
||||
|
||||
if (args->culledOnce && args->wantDeltaFrustums) {
|
||||
inLastCulledFrustum = node->inFrustum(args->lastViewFrustum);
|
||||
|
||||
// if this node is fully OUTSIDE our last culled view frustum, then we don't need to recurse further
|
||||
if (inLastCulledFrustum == ViewFrustum::OUTSIDE) {
|
||||
args->nodesOutsideOutside++;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
args->nodesOutside++;
|
||||
if (node->isKnownBufferIndex()) {
|
||||
args->nodesRemoved++;
|
||||
VoxelSystem* thisVoxelSystem = args->thisVoxelSystem;
|
||||
thisVoxelSystem->_voxelsUpdated += thisVoxelSystem->forceRemoveNodeFromArrays(node);
|
||||
thisVoxelSystem->setupNewVoxelsForDrawingSingleNode();
|
||||
bool falseColorize = false;
|
||||
if (falseColorize) {
|
||||
node->setFalseColor(255,0,0); // false colorize
|
||||
} else {
|
||||
VoxelSystem* thisVoxelSystem = args->thisVoxelSystem;
|
||||
thisVoxelSystem->_voxelsUpdated += thisVoxelSystem->forceRemoveNodeFromArrays(node);
|
||||
thisVoxelSystem->setupNewVoxelsForDrawingSingleNode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1721,17 +1897,39 @@ bool VoxelSystem::hideAllSubTreeOperation(VoxelNode* node, void* extraData) {
|
|||
bool VoxelSystem::showAllSubTreeOperation(VoxelNode* node, void* extraData) {
|
||||
hideOutOfViewArgs* args = (hideOutOfViewArgs*)extraData;
|
||||
|
||||
// If we've culled at least once, then we will use the status of this voxel in the last culled frustum to determine
|
||||
// how to proceed. If we've never culled, then we just consider all these voxels to be UNKNOWN so that we will not
|
||||
// consider that case.
|
||||
ViewFrustum::location inLastCulledFrustum;
|
||||
|
||||
if (args->culledOnce && args->wantDeltaFrustums) {
|
||||
inLastCulledFrustum = node->inFrustum(args->lastViewFrustum);
|
||||
|
||||
// if this node is fully inside our last culled view frustum, then we don't need to recurse further
|
||||
if (inLastCulledFrustum == ViewFrustum::INSIDE) {
|
||||
args->nodesInsideInside++;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
args->nodesInside++;
|
||||
|
||||
if (node->getShouldRender() && !node->isKnownBufferIndex()) {
|
||||
node->setDirtyBit(); // will this make it draw!
|
||||
bool shouldRender = node->calculateShouldRender(&args->thisViewFrustum);
|
||||
node->setShouldRender(shouldRender);
|
||||
|
||||
if (shouldRender && !node->isKnownBufferIndex()) {
|
||||
bool falseColorize = false;
|
||||
if (falseColorize) {
|
||||
node->setFalseColor(0,0,255); // false colorize
|
||||
}
|
||||
// These are both needed to force redraw...
|
||||
node->setDirtyBit();
|
||||
node->markWithChangedTime();
|
||||
}
|
||||
|
||||
return true; // keep recursing!
|
||||
}
|
||||
|
||||
|
||||
|
||||
// "hide" voxels in the VBOs that are still in the tree that but not in view.
|
||||
// We don't remove them from the tree, we don't delete them, we do remove them
|
||||
// from the VBOs and mark them as such in the tree.
|
||||
|
@ -1741,26 +1939,66 @@ bool VoxelSystem::hideOutOfViewOperation(VoxelNode* node, void* extraData) {
|
|||
// If we're still recursing the tree using this operator, then we don't know if we're inside or outside...
|
||||
// so before we move forward we need to determine our frustum location
|
||||
ViewFrustum::location inFrustum = node->inFrustum(args->thisViewFrustum);
|
||||
|
||||
// If we've culled at least once, then we will use the status of this voxel in the last culled frustum to determine
|
||||
// how to proceed. If we've never culled, then we just consider all these voxels to be UNKNOWN so that we will not
|
||||
// consider that case.
|
||||
ViewFrustum::location inLastCulledFrustum;
|
||||
|
||||
if (args->culledOnce && args->wantDeltaFrustums) {
|
||||
inLastCulledFrustum = node->inFrustum(args->lastViewFrustum);
|
||||
}
|
||||
|
||||
// ok, now do some processing for this node...
|
||||
switch (inFrustum) {
|
||||
case ViewFrustum::OUTSIDE: {
|
||||
// if this node is fully OUTSIDE the view, then we know that ALL of it's children are also fully OUTSIDE
|
||||
// so we can recurse the children and simply mark them as hidden
|
||||
|
||||
// If this node is outside the current view, then we might want to hide it... unless it was previously OUTSIDE,
|
||||
// if it was previously outside, then we can safely assume it's already hidden, and we can also safely assume
|
||||
// that all of it's children are outside both of our views, in which case we can just stop recursing...
|
||||
if (args->culledOnce && args->wantDeltaFrustums && inLastCulledFrustum == ViewFrustum::OUTSIDE) {
|
||||
args->nodesScanned++;
|
||||
args->nodesOutsideOutside++;
|
||||
return false; // stop recursing this branch!
|
||||
}
|
||||
|
||||
// if this node is fully OUTSIDE the view, but previously intersected and/or was inside the last view, then
|
||||
// we need to hide it. Additionally we know that ALL of it's children are also fully OUTSIDE so we can recurse
|
||||
// the children and simply mark them as hidden
|
||||
args->tree->recurseNodeWithOperation(node, hideAllSubTreeOperation, args );
|
||||
|
||||
return false;
|
||||
|
||||
} break;
|
||||
case ViewFrustum::INSIDE: {
|
||||
// if this node is fully INSIDE the view, then we know that ALL of it's children are also fully INSIDE
|
||||
// so we can recurse the children and simply mark them as visible (as appropriate based on LOD)
|
||||
args->tree->recurseNodeWithOperation(node, showAllSubTreeOperation, args );
|
||||
|
||||
// If this node is INSIDE the current view, then we might want to show it... unless it was previously INSIDE,
|
||||
// if it was previously INSIDE, then we can safely assume it's already shown, and we can also safely assume
|
||||
// that all of it's children are INSIDE both of our views, in which case we can just stop recursing...
|
||||
if (args->culledOnce && args->wantDeltaFrustums && inLastCulledFrustum == ViewFrustum::INSIDE) {
|
||||
args->nodesScanned++;
|
||||
args->nodesInsideInside++;
|
||||
return false; // stop recursing this branch!
|
||||
}
|
||||
|
||||
// if this node is fully INSIDE the view, but previously INTERSECTED and/or was OUTSIDE the last view, then
|
||||
// we need to show it. Additionally we know that ALL of it's children are also fully INSIDE so we can recurse
|
||||
// the children and simply mark them as visible (as appropriate based on LOD)
|
||||
args->tree->recurseNodeWithOperation(node, showAllSubTreeOperation, args);
|
||||
|
||||
return false;
|
||||
} break;
|
||||
case ViewFrustum::INTERSECT: {
|
||||
args->nodesScanned++;
|
||||
|
||||
// If this node INTERSECTS the current view, then we might want to show it... unless it was previously INSIDE
|
||||
// the last known view, in which case it will already be visible, and we know that all it's children are also
|
||||
// previously INSIDE and visible. So in this case stop recursing
|
||||
if (args->culledOnce && args->wantDeltaFrustums && inLastCulledFrustum == ViewFrustum::INSIDE) {
|
||||
args->nodesIntersectInside++;
|
||||
return false; // stop recursing this branch!
|
||||
}
|
||||
|
||||
args->nodesIntersect++;
|
||||
|
||||
// if the child node INTERSECTs the view, then we want to check to see if it thinks it should render
|
||||
|
@ -1886,6 +2124,7 @@ public:
|
|||
};
|
||||
|
||||
bool VoxelSystem::collectStatsForTreesAndVBOsOperation(VoxelNode* node, void* extraData) {
|
||||
|
||||
collectStatsForTreesAndVBOsArgs* args = (collectStatsForTreesAndVBOsArgs*)extraData;
|
||||
args->totalNodes++;
|
||||
|
||||
|
|
|
@ -59,6 +59,9 @@ public:
|
|||
void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; }
|
||||
unsigned long getVoxelsUpdated() const { return _voxelsUpdated; }
|
||||
unsigned long getVoxelsRendered() const { return _voxelsInReadArrays; }
|
||||
unsigned long getVoxelsWritten() const { return _voxelsInWriteArrays; }
|
||||
|
||||
ViewFrustum* getLastCulledViewFrustum() { return &_lastCulledViewFrustum; }
|
||||
|
||||
void loadVoxelsFile(const char* fileName,bool wantColorRandomizer);
|
||||
void writeToSVOFile(const char* filename, VoxelNode* node) const;
|
||||
|
@ -123,6 +126,7 @@ public slots:
|
|||
void collectStatsForTreesAndVBOs();
|
||||
|
||||
// Methods that recurse tree
|
||||
void showAllLocalVoxels();
|
||||
void randomizeVoxelColors();
|
||||
void falseColorizeRandom();
|
||||
void trueColorize();
|
||||
|
@ -192,6 +196,7 @@ private:
|
|||
static bool hideOutOfViewUnrollOperation(VoxelNode* node, void* extraData);
|
||||
static bool hideAllSubTreeOperation(VoxelNode* node, void* extraData);
|
||||
static bool showAllSubTreeOperation(VoxelNode* node, void* extraData);
|
||||
static bool showAllLocalVoxelsOperation(VoxelNode* node, void* extraData);
|
||||
|
||||
int updateNodeInArrays(VoxelNode* node, bool reuseIndex, bool forceDraw);
|
||||
int forceRemoveNodeFromArrays(VoxelNode* node);
|
||||
|
@ -252,10 +257,13 @@ private:
|
|||
pthread_mutex_t _bufferWriteLock;
|
||||
pthread_mutex_t _treeLock;
|
||||
|
||||
ViewFrustum _lastKnowViewFrustum;
|
||||
ViewFrustum _lastKnownViewFrustum;
|
||||
ViewFrustum _lastStableViewFrustum;
|
||||
ViewFrustum* _viewFrustum;
|
||||
|
||||
ViewFrustum _lastCulledViewFrustum; // used for hide/show visible passes
|
||||
bool _culledOnce;
|
||||
|
||||
void setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndices[]);
|
||||
|
||||
int newTreeToArrays(VoxelNode *currentNode);
|
||||
|
|
|
@ -94,7 +94,8 @@ private:
|
|||
static bool _suppressShortTimings;
|
||||
public:
|
||||
|
||||
PerformanceWarning(bool renderWarnings, const char* message, bool alwaysDisplay = false, uint64_t* runningTotal = NULL, uint64_t* totalCalls = NULL) :
|
||||
PerformanceWarning(bool renderWarnings, const char* message, bool alwaysDisplay = false,
|
||||
uint64_t* runningTotal = NULL, uint64_t* totalCalls = NULL) :
|
||||
_start(usecTimestampNow()),
|
||||
_message(message),
|
||||
_renderWarningsOn(renderWarnings),
|
||||
|
|
|
@ -79,6 +79,7 @@ void VoxelNode::init(unsigned char * octalCode) {
|
|||
|
||||
_unknownBufferIndex = true;
|
||||
setBufferIndex(GLBUFFER_INDEX_UNKNOWN);
|
||||
|
||||
setVoxelSystem(NULL);
|
||||
_isDirty = true;
|
||||
_shouldRender = false;
|
||||
|
@ -104,18 +105,8 @@ VoxelNode::~VoxelNode() {
|
|||
delete[] _octalCode.pointer;
|
||||
}
|
||||
|
||||
// delete all of this node's children
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
VoxelNode* childAt = getChildAtIndex(i);
|
||||
if (childAt) {
|
||||
delete childAt;
|
||||
setChildAtIndex(i, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// at this point, we should have no children, but we need to drop ourselves from population counts
|
||||
_singleChildrenCount--;
|
||||
_childrenCount[0]--;
|
||||
// delete all of this node's children, this also takes care of all population tracking data
|
||||
deleteAllChildren();
|
||||
}
|
||||
|
||||
void VoxelNode::markWithChangedTime() {
|
||||
|
@ -146,7 +137,9 @@ std::map<uint8_t, VoxelSystem*> VoxelNode::_mapIndexToVoxelSystemPointers;
|
|||
VoxelSystem* VoxelNode::getVoxelSystem() const {
|
||||
if (_voxelSystemIndex > INDEX_FOR_NULL) {
|
||||
if (_mapIndexToVoxelSystemPointers.end() != _mapIndexToVoxelSystemPointers.find(_voxelSystemIndex)) {
|
||||
return _mapIndexToVoxelSystemPointers[_voxelSystemIndex];
|
||||
|
||||
VoxelSystem* voxelSystem = _mapIndexToVoxelSystemPointers[_voxelSystemIndex];
|
||||
return voxelSystem;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
@ -287,7 +280,8 @@ void VoxelNode::auditChildren(const char* label) const {
|
|||
}
|
||||
}
|
||||
|
||||
if (auditFailed) {
|
||||
const bool alwaysReport = false; // set this to true to get additional debugging
|
||||
if (alwaysReport || auditFailed) {
|
||||
qDebug("%s... auditChildren() %s <<<< \n", label, (auditFailed ? "FAILED" : "PASSED"));
|
||||
qDebug(" _childrenExternal=%s\n", debug::valueOf(_childrenExternal));
|
||||
qDebug(" childCount=%d\n", getChildCount());
|
||||
|
@ -605,6 +599,60 @@ void VoxelNode::checkStoreFourChildren(VoxelNode* childOne, VoxelNode* childTwo,
|
|||
}
|
||||
}
|
||||
|
||||
void VoxelNode::deleteAllChildren() {
|
||||
// first delete all the VoxelNode objects...
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
VoxelNode* childAt = getChildAtIndex(i);
|
||||
if (childAt) {
|
||||
delete childAt;
|
||||
}
|
||||
}
|
||||
|
||||
// now, reset our internal state and ANY and all population data
|
||||
int childCount = getChildCount();
|
||||
switch (childCount) {
|
||||
case 0: {
|
||||
_singleChildrenCount--;
|
||||
_childrenCount[0]--;
|
||||
} break;
|
||||
case 1: {
|
||||
_singleChildrenCount--;
|
||||
_childrenCount[1]--;
|
||||
} break;
|
||||
|
||||
case 2: {
|
||||
if (_childrenExternal) {
|
||||
_twoChildrenExternalCount--;
|
||||
} else {
|
||||
_twoChildrenOffsetCount--;
|
||||
}
|
||||
_childrenCount[2]--;
|
||||
} break;
|
||||
|
||||
case 3: {
|
||||
if (_childrenExternal) {
|
||||
_threeChildrenExternalCount--;
|
||||
} else {
|
||||
_threeChildrenOffsetCount--;
|
||||
}
|
||||
_childrenCount[3]--;
|
||||
} break;
|
||||
|
||||
default: {
|
||||
_externalChildrenCount--;
|
||||
_childrenCount[childCount]--;
|
||||
} break;
|
||||
|
||||
|
||||
}
|
||||
|
||||
// If we had externally stored children, clean them too.
|
||||
if (_childrenExternal && _children.external) {
|
||||
delete[] _children.external;
|
||||
}
|
||||
_children.single = NULL;
|
||||
}
|
||||
|
||||
void VoxelNode::setChildAtIndex(int childIndex, VoxelNode* child) {
|
||||
PerformanceWarning warn(false,"setChildAtIndex",false,&_setChildAtIndexTime,&_setChildAtIndexCalls);
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#ifndef __hifi__VoxelNode__
|
||||
#define __hifi__VoxelNode__
|
||||
|
||||
//#define HAS_AUDIT_CHILDREN
|
||||
|
||||
#include <SharedUtil.h>
|
||||
#include "AABox.h"
|
||||
#include "ViewFrustum.h"
|
||||
|
@ -144,6 +146,7 @@ public:
|
|||
#endif // def HAS_AUDIT_CHILDREN
|
||||
|
||||
private:
|
||||
void deleteAllChildren();
|
||||
void setChildAtIndex(int childIndex, VoxelNode* child);
|
||||
void storeTwoChildren(VoxelNode* childOne, VoxelNode* childTwo);
|
||||
void retrieveTwoChildren(VoxelNode*& childOne, VoxelNode*& childTwo);
|
||||
|
|
|
@ -476,7 +476,9 @@ void VoxelTree::deleteVoxelCodeFromTreeRecursion(VoxelNode* node, void* extraDat
|
|||
void VoxelTree::eraseAllVoxels() {
|
||||
// XXXBHG Hack attack - is there a better way to erase the voxel tree?
|
||||
delete rootNode; // this will recurse and delete all children
|
||||
VoxelSystem* voxelSystem = rootNode->getVoxelSystem();
|
||||
rootNode = new VoxelNode();
|
||||
rootNode->setVoxelSystem(voxelSystem);
|
||||
_isDirty = true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue