mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 11:37:58 +02:00
Merge branch 'master' of github.com:worklist/hifi
This commit is contained in:
commit
2013f9f051
20 changed files with 613 additions and 174 deletions
|
@ -594,8 +594,12 @@ void* animateVoxels(void* args) {
|
||||||
|
|
||||||
timeval lastSendTime;
|
timeval lastSendTime;
|
||||||
|
|
||||||
|
bool firstTime = true;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
gettimeofday(&lastSendTime, NULL);
|
gettimeofday(&lastSendTime, NULL);
|
||||||
|
|
||||||
|
int packetsStarting = ::voxelEditPacketSender->packetsToSendCount();
|
||||||
|
|
||||||
// some animations
|
// some animations
|
||||||
//sendVoxelBlinkMessage();
|
//sendVoxelBlinkMessage();
|
||||||
|
@ -619,12 +623,22 @@ void* animateVoxels(void* args) {
|
||||||
if (::buildStreet) {
|
if (::buildStreet) {
|
||||||
doBuildStreet();
|
doBuildStreet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::voxelEditPacketSender->releaseQueuedMessages();
|
||||||
|
int packetsEnding = ::voxelEditPacketSender->packetsToSendCount();
|
||||||
|
|
||||||
if (::voxelEditPacketSender) {
|
if (firstTime) {
|
||||||
::voxelEditPacketSender->releaseQueuedMessages();
|
int packetsPerSecond = (packetsEnding - packetsStarting) * (ACTUAL_FPS);
|
||||||
if (::nonThreadedPacketSender) {
|
|
||||||
::voxelEditPacketSender->process();
|
std::cout << "Setting PPS to " << packetsPerSecond << "\n";
|
||||||
}
|
|
||||||
|
::voxelEditPacketSender->setPacketsPerSecond(packetsPerSecond);
|
||||||
|
firstTime = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (::nonThreadedPacketSender) {
|
||||||
|
::voxelEditPacketSender->process();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t end = usecTimestampNow();
|
uint64_t end = usecTimestampNow();
|
||||||
|
@ -715,14 +729,13 @@ int main(int argc, const char * argv[])
|
||||||
|
|
||||||
// Create out VoxelEditPacketSender
|
// Create out VoxelEditPacketSender
|
||||||
::voxelEditPacketSender = new VoxelEditPacketSender;
|
::voxelEditPacketSender = new VoxelEditPacketSender;
|
||||||
if (::voxelEditPacketSender) {
|
::voxelEditPacketSender->initialize(!::nonThreadedPacketSender);
|
||||||
::voxelEditPacketSender->initialize(!::nonThreadedPacketSender);
|
|
||||||
if (::jurisdictionListener) {
|
if (::jurisdictionListener) {
|
||||||
::voxelEditPacketSender->setVoxelServerJurisdictions(::jurisdictionListener->getJurisdictions());
|
::voxelEditPacketSender->setVoxelServerJurisdictions(::jurisdictionListener->getJurisdictions());
|
||||||
}
|
}
|
||||||
if (::nonThreadedPacketSender) {
|
if (::nonThreadedPacketSender) {
|
||||||
::voxelEditPacketSender->setProcessCallIntervalHint(ANIMATE_VOXELS_INTERVAL_USECS);
|
::voxelEditPacketSender->setProcessCallIntervalHint(ANIMATE_VOXELS_INTERVAL_USECS);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
srand((unsigned)time(0));
|
srand((unsigned)time(0));
|
||||||
|
|
|
@ -324,13 +324,23 @@ void Application::initializeGL() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::paintGL() {
|
void Application::paintGL() {
|
||||||
|
PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings));
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::paintGL()");
|
||||||
PerfStat("display");
|
PerfStat("display");
|
||||||
|
|
||||||
glEnable(GL_LINE_SMOOTH);
|
glEnable(GL_LINE_SMOOTH);
|
||||||
|
|
||||||
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||||
_myCamera.setTightness (100.0f);
|
_myCamera.setTightness (100.0f);
|
||||||
_myCamera.setTargetPosition(_myAvatar.getUprightHeadPosition());
|
glm::vec3 targetPosition = _myAvatar.getUprightHeadPosition();
|
||||||
|
if (_myAvatar.getHead().getBlendFace().isActive()) {
|
||||||
|
// make sure we're aligned to the blend face eyes
|
||||||
|
glm::vec3 leftEyePosition, rightEyePosition;
|
||||||
|
if (_myAvatar.getHead().getBlendFace().getEyePositions(leftEyePosition, rightEyePosition, true)) {
|
||||||
|
targetPosition = (leftEyePosition + rightEyePosition) * 0.5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_myCamera.setTargetPosition(targetPosition);
|
||||||
_myCamera.setTargetRotation(_myAvatar.getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f)));
|
_myCamera.setTargetRotation(_myAvatar.getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f)));
|
||||||
|
|
||||||
} else if (OculusManager::isConnected()) {
|
} else if (OculusManager::isConnected()) {
|
||||||
|
@ -1181,6 +1191,7 @@ void Application::idle() {
|
||||||
|
|
||||||
double timeSinceLastUpdate = diffclock(&_lastTimeUpdated, &check);
|
double timeSinceLastUpdate = diffclock(&_lastTimeUpdated, &check);
|
||||||
if (timeSinceLastUpdate > IDLE_SIMULATE_MSECS) {
|
if (timeSinceLastUpdate > IDLE_SIMULATE_MSECS) {
|
||||||
|
|
||||||
const float BIGGEST_DELTA_TIME_SECS = 0.25f;
|
const float BIGGEST_DELTA_TIME_SECS = 0.25f;
|
||||||
update(glm::clamp((float)timeSinceLastUpdate / 1000.f, 0.f, BIGGEST_DELTA_TIME_SECS));
|
update(glm::clamp((float)timeSinceLastUpdate / 1000.f, 0.f, BIGGEST_DELTA_TIME_SECS));
|
||||||
_glWidget->updateGL();
|
_glWidget->updateGL();
|
||||||
|
@ -1586,6 +1597,7 @@ void Application::init() {
|
||||||
// Set up VoxelSystem after loading preferences so we can get the desired max voxel count
|
// Set up VoxelSystem after loading preferences so we can get the desired max voxel count
|
||||||
_voxels.setMaxVoxels(Menu::getInstance()->getMaxVoxels());
|
_voxels.setMaxVoxels(Menu::getInstance()->getMaxVoxels());
|
||||||
_voxels.setUseVoxelShader(Menu::getInstance()->isOptionChecked(MenuOption::UseVoxelShader));
|
_voxels.setUseVoxelShader(Menu::getInstance()->isOptionChecked(MenuOption::UseVoxelShader));
|
||||||
|
_voxels.setVoxelsAsPoints(Menu::getInstance()->isOptionChecked(MenuOption::VoxelsAsPoints));
|
||||||
_voxels.setUseFastVoxelPipeline(Menu::getInstance()->isOptionChecked(MenuOption::FastVoxelPipeline));
|
_voxels.setUseFastVoxelPipeline(Menu::getInstance()->isOptionChecked(MenuOption::FastVoxelPipeline));
|
||||||
_voxels.init();
|
_voxels.init();
|
||||||
|
|
||||||
|
@ -2379,6 +2391,7 @@ void Application::computeOffAxisFrustum(float& left, float& right, float& bottom
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::displaySide(Camera& whichCamera) {
|
void Application::displaySide(Camera& whichCamera) {
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide()");
|
||||||
// transform by eye offset
|
// transform by eye offset
|
||||||
|
|
||||||
// flip x if in mirror mode (also requires reversing winding order for backface culling)
|
// flip x if in mirror mode (also requires reversing winding order for backface culling)
|
||||||
|
@ -2410,6 +2423,8 @@ void Application::displaySide(Camera& whichCamera) {
|
||||||
setupWorldLight(whichCamera);
|
setupWorldLight(whichCamera);
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Stars)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Stars)) {
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
|
"Application::displaySide() ... stars...");
|
||||||
if (!_stars.getFileLoaded()) {
|
if (!_stars.getFileLoaded()) {
|
||||||
_stars.readInput(STAR_FILE, STAR_CACHE_FILE, 0);
|
_stars.readInput(STAR_FILE, STAR_CACHE_FILE, 0);
|
||||||
}
|
}
|
||||||
|
@ -2435,6 +2450,8 @@ void Application::displaySide(Camera& whichCamera) {
|
||||||
|
|
||||||
// draw the sky dome
|
// draw the sky dome
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) {
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
|
"Application::displaySide() ... atmosphere...");
|
||||||
_environment.renderAtmospheres(whichCamera);
|
_environment.renderAtmospheres(whichCamera);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2457,6 +2474,9 @@ void Application::displaySide(Camera& whichCamera) {
|
||||||
|
|
||||||
//draw a grid ground plane....
|
//draw a grid ground plane....
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::GroundPlane)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::GroundPlane)) {
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
|
"Application::displaySide() ... ground plane...");
|
||||||
|
|
||||||
// draw grass plane with fog
|
// draw grass plane with fog
|
||||||
glEnable(GL_FOG);
|
glEnable(GL_FOG);
|
||||||
glEnable(GL_NORMALIZE);
|
glEnable(GL_NORMALIZE);
|
||||||
|
@ -2480,7 +2500,11 @@ void Application::displaySide(Camera& whichCamera) {
|
||||||
}
|
}
|
||||||
// Draw voxels
|
// Draw voxels
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
|
||||||
_voxels.render(Menu::getInstance()->isOptionChecked(MenuOption::VoxelTextures));
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
|
"Application::displaySide() ... voxels...");
|
||||||
|
if (!Menu::getInstance()->isOptionChecked(MenuOption::DontRenderVoxels)) {
|
||||||
|
_voxels.render(Menu::getInstance()->isOptionChecked(MenuOption::VoxelTextures));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// restore default, white specular
|
// restore default, white specular
|
||||||
|
@ -2488,6 +2512,9 @@ void Application::displaySide(Camera& whichCamera) {
|
||||||
|
|
||||||
// indicate what we'll be adding/removing in mouse mode, if anything
|
// indicate what we'll be adding/removing in mouse mode, if anything
|
||||||
if (_mouseVoxel.s != 0) {
|
if (_mouseVoxel.s != 0) {
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
|
"Application::displaySide() ... voxels TOOLS UX...");
|
||||||
|
|
||||||
glDisable(GL_LIGHTING);
|
glDisable(GL_LIGHTING);
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glScalef(TREE_SCALE, TREE_SCALE, TREE_SCALE);
|
glScalef(TREE_SCALE, TREE_SCALE, TREE_SCALE);
|
||||||
|
@ -2533,6 +2560,9 @@ void Application::displaySide(Camera& whichCamera) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelSelectMode) && _pasteMode) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelSelectMode) && _pasteMode) {
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
|
"Application::displaySide() ... PASTE Preview...");
|
||||||
|
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glTranslatef(_mouseVoxel.x * TREE_SCALE,
|
glTranslatef(_mouseVoxel.x * TREE_SCALE,
|
||||||
_mouseVoxel.y * TREE_SCALE,
|
_mouseVoxel.y * TREE_SCALE,
|
||||||
|
@ -2548,6 +2578,10 @@ void Application::displaySide(Camera& whichCamera) {
|
||||||
_myAvatar.renderScreenTint(SCREEN_TINT_BEFORE_AVATARS, whichCamera);
|
_myAvatar.renderScreenTint(SCREEN_TINT_BEFORE_AVATARS, whichCamera);
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) {
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
|
"Application::displaySide() ... Avatars...");
|
||||||
|
|
||||||
|
|
||||||
// Render avatars of other nodes
|
// Render avatars of other nodes
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
|
|
||||||
|
@ -2592,16 +2626,22 @@ void Application::displaySide(Camera& whichCamera) {
|
||||||
|
|
||||||
// render the ambient occlusion effect if enabled
|
// render the ambient occlusion effect if enabled
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::AmbientOcclusion)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::AmbientOcclusion)) {
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
|
"Application::displaySide() ... AmbientOcclusion...");
|
||||||
_ambientOcclusionEffect.render();
|
_ambientOcclusionEffect.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
// brad's frustum for debugging
|
// brad's frustum for debugging
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum)) {
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
|
"Application::displaySide() ... renderViewFrustum...");
|
||||||
renderViewFrustum(_viewFrustum);
|
renderViewFrustum(_viewFrustum);
|
||||||
}
|
}
|
||||||
|
|
||||||
// render voxel fades if they exist
|
// render voxel fades if they exist
|
||||||
if (_voxelFades.size() > 0) {
|
if (_voxelFades.size() > 0) {
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
|
"Application::displaySide() ... voxel fades...");
|
||||||
for(std::vector<VoxelFade>::iterator fade = _voxelFades.begin(); fade != _voxelFades.end();) {
|
for(std::vector<VoxelFade>::iterator fade = _voxelFades.begin(); fade != _voxelFades.end();) {
|
||||||
fade->render();
|
fade->render();
|
||||||
if(fade->isDone()) {
|
if(fade->isDone()) {
|
||||||
|
@ -2611,11 +2651,18 @@ void Application::displaySide(Camera& whichCamera) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderFollowIndicator();
|
{
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
|
"Application::displaySide() ... renderFollowIndicator...");
|
||||||
|
renderFollowIndicator();
|
||||||
|
}
|
||||||
|
|
||||||
// render transmitter pick ray, if non-empty
|
// render transmitter pick ray, if non-empty
|
||||||
if (_transmitterPickStart != _transmitterPickEnd) {
|
if (_transmitterPickStart != _transmitterPickEnd) {
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
|
"Application::displaySide() ... transmitter pick ray...");
|
||||||
|
|
||||||
Glower glower;
|
Glower glower;
|
||||||
const float TRANSMITTER_PICK_COLOR[] = { 1.0f, 1.0f, 0.0f };
|
const float TRANSMITTER_PICK_COLOR[] = { 1.0f, 1.0f, 0.0f };
|
||||||
glColor3fv(TRANSMITTER_PICK_COLOR);
|
glColor3fv(TRANSMITTER_PICK_COLOR);
|
||||||
|
@ -2637,6 +2684,8 @@ void Application::displaySide(Camera& whichCamera) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::displayOverlay() {
|
void Application::displayOverlay() {
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displayOverlay()");
|
||||||
|
|
||||||
// Render 2D overlay: I/O level bar graphs and text
|
// Render 2D overlay: I/O level bar graphs and text
|
||||||
glMatrixMode(GL_PROJECTION);
|
glMatrixMode(GL_PROJECTION);
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
|
|
|
@ -239,12 +239,19 @@ Menu::Menu() :
|
||||||
true,
|
true,
|
||||||
appInstance,
|
appInstance,
|
||||||
SLOT(setRenderVoxels(bool)));
|
SLOT(setRenderVoxels(bool)));
|
||||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures);
|
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontRenderVoxels);
|
||||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion);
|
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontCallOpenGLForVoxels);
|
||||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::UseVoxelShader, 0,
|
|
||||||
false, this, SLOT(switchVoxelShader()));
|
_useVoxelShader = addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::UseVoxelShader, 0,
|
||||||
|
false, appInstance->getVoxels(), SLOT(setUseVoxelShader(bool)));
|
||||||
|
|
||||||
|
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelsAsPoints, 0,
|
||||||
|
false, appInstance->getVoxels(), SLOT(setVoxelsAsPoints(bool)));
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::FastVoxelPipeline, 0,
|
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::FastVoxelPipeline, 0,
|
||||||
false, appInstance->getVoxels(), SLOT(setUseFastVoxelPipeline(bool)));
|
false, appInstance->getVoxels(), SLOT(setUseFastVoxelPipeline(bool)));
|
||||||
|
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures);
|
||||||
|
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion);
|
||||||
|
|
||||||
|
|
||||||
QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options");
|
QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options");
|
||||||
|
@ -346,6 +353,7 @@ Menu::Menu() :
|
||||||
|
|
||||||
QMenu* renderDebugMenu = developerMenu->addMenu("Render Debugging Tools");
|
QMenu* renderDebugMenu = developerMenu->addMenu("Render Debugging Tools");
|
||||||
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::PipelineWarnings);
|
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::PipelineWarnings);
|
||||||
|
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::SuppressShortTimings);
|
||||||
|
|
||||||
addActionToQMenuAndActionHash(renderDebugMenu,
|
addActionToQMenuAndActionHash(renderDebugMenu,
|
||||||
MenuOption::KillLocalVoxels,
|
MenuOption::KillLocalVoxels,
|
||||||
|
@ -1003,7 +1011,4 @@ void Menu::updateFrustumRenderModeAction() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Menu::switchVoxelShader() {
|
|
||||||
Application::getInstance()->getVoxels()->setUseVoxelShader(isOptionChecked(MenuOption::UseVoxelShader));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ public:
|
||||||
ViewFrustumOffset getViewFrustumOffset() const { return _viewFrustumOffset; }
|
ViewFrustumOffset getViewFrustumOffset() const { return _viewFrustumOffset; }
|
||||||
VoxelStatsDialog* getVoxelStatsDialog() const { return _voxelStatsDialog; }
|
VoxelStatsDialog* getVoxelStatsDialog() const { return _voxelStatsDialog; }
|
||||||
int getMaxVoxels() const { return _maxVoxels; }
|
int getMaxVoxels() const { return _maxVoxels; }
|
||||||
|
QAction* getUseVoxelShader() const { return _useVoxelShader; }
|
||||||
|
|
||||||
|
|
||||||
void handleViewFrustumOffsetKeyModifier(int key);
|
void handleViewFrustumOffsetKeyModifier(int key);
|
||||||
|
@ -78,7 +79,6 @@ private slots:
|
||||||
void chooseVoxelPaintColor();
|
void chooseVoxelPaintColor();
|
||||||
void runTests();
|
void runTests();
|
||||||
void resetSwatchColors();
|
void resetSwatchColors();
|
||||||
void switchVoxelShader();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Menu* _instance;
|
static Menu* _instance;
|
||||||
|
@ -116,6 +116,7 @@ private:
|
||||||
QActionGroup* _voxelModeActionsGroup;
|
QActionGroup* _voxelModeActionsGroup;
|
||||||
VoxelStatsDialog* _voxelStatsDialog;
|
VoxelStatsDialog* _voxelStatsDialog;
|
||||||
int _maxVoxels;
|
int _maxVoxels;
|
||||||
|
QAction* _useVoxelShader;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace MenuOption {
|
namespace MenuOption {
|
||||||
|
@ -138,6 +139,8 @@ namespace MenuOption {
|
||||||
const QString DestructiveAddVoxel = "Create Voxel is Destructive";
|
const QString DestructiveAddVoxel = "Create Voxel is Destructive";
|
||||||
const QString DeltaSending = "Delta Sending";
|
const QString DeltaSending = "Delta Sending";
|
||||||
const QString DisplayFrustum = "Display Frustum";
|
const QString DisplayFrustum = "Display Frustum";
|
||||||
|
const QString DontRenderVoxels = "Don't call _voxels.render()";
|
||||||
|
const QString DontCallOpenGLForVoxels = "Don't call glDrawElements()/glDrawRangeElementsEXT() for Voxels";
|
||||||
const QString EchoAudio = "Echo Audio";
|
const QString EchoAudio = "Echo Audio";
|
||||||
const QString ExportVoxels = "Export Voxels";
|
const QString ExportVoxels = "Export Voxels";
|
||||||
const QString HeadMouse = "Head Mouse";
|
const QString HeadMouse = "Head Mouse";
|
||||||
|
@ -193,6 +196,7 @@ namespace MenuOption {
|
||||||
const QString ShowTrueColors = "Show TRUE Colors";
|
const QString ShowTrueColors = "Show TRUE Colors";
|
||||||
const QString SimulateLeapHand = "Simulate Leap Hand";
|
const QString SimulateLeapHand = "Simulate Leap Hand";
|
||||||
const QString SkeletonTracking = "Skeleton Tracking";
|
const QString SkeletonTracking = "Skeleton Tracking";
|
||||||
|
const QString SuppressShortTimings = "Suppress Timings Less than 10ms";
|
||||||
const QString LEDTracking = "LED Tracking";
|
const QString LEDTracking = "LED Tracking";
|
||||||
const QString Stars = "Stars";
|
const QString Stars = "Stars";
|
||||||
const QString Stats = "Stats";
|
const QString Stats = "Stats";
|
||||||
|
@ -203,8 +207,7 @@ namespace MenuOption {
|
||||||
const QString UsePerlinFace = "Use Perlin's Face";
|
const QString UsePerlinFace = "Use Perlin's Face";
|
||||||
const QString Quit = "Quit";
|
const QString Quit = "Quit";
|
||||||
const QString UseVoxelShader = "Use Voxel Shader";
|
const QString UseVoxelShader = "Use Voxel Shader";
|
||||||
const QString UseByteNormals = "Use Byte Normals";
|
const QString VoxelsAsPoints = "Draw Voxels as Points";
|
||||||
const QString UseGlobalNormals = "Use Global Normals";
|
|
||||||
const QString Voxels = "Voxels";
|
const QString Voxels = "Voxels";
|
||||||
const QString VoxelAddMode = "Add Voxel Mode";
|
const QString VoxelAddMode = "Add Voxel Mode";
|
||||||
const QString VoxelColorMode = "Color Voxel Mode";
|
const QString VoxelColorMode = "Color Voxel Mode";
|
||||||
|
|
|
@ -47,15 +47,14 @@ void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char*
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
|
||||||
Node* voxelServer = NodeList::getInstance()->nodeWithAddress(&senderAddress);
|
Node* voxelServer = NodeList::getInstance()->nodeWithAddress(&senderAddress);
|
||||||
if (voxelServer && socketMatch(voxelServer->getActiveSocket(), &senderAddress)) {
|
if (voxelServer && socketMatch(voxelServer->getActiveSocket(), &senderAddress)) {
|
||||||
voxelServer->lock();
|
int nodeID = voxelServer->getNodeID();
|
||||||
if (packetData[0] == PACKET_TYPE_ENVIRONMENT_DATA) {
|
if (packetData[0] == PACKET_TYPE_ENVIRONMENT_DATA) {
|
||||||
app->_environment.parseData(&senderAddress, packetData, messageLength);
|
app->_environment.parseData(&senderAddress, packetData, messageLength);
|
||||||
} else {
|
} else {
|
||||||
app->_voxels.setDataSourceID(voxelServer->getNodeID());
|
app->_voxels.setDataSourceID(nodeID);
|
||||||
app->_voxels.parseData(packetData, messageLength);
|
app->_voxels.parseData(packetData, messageLength);
|
||||||
app->_voxels.setDataSourceID(UNKNOWN_NODE_ID);
|
app->_voxels.setDataSourceID(UNKNOWN_NODE_ID);
|
||||||
}
|
}
|
||||||
voxelServer->unlock();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,6 +90,8 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels)
|
||||||
connect(_tree, SIGNAL(importProgress(int)), SIGNAL(importProgress(int)));
|
connect(_tree, SIGNAL(importProgress(int)), SIGNAL(importProgress(int)));
|
||||||
|
|
||||||
_useVoxelShader = false;
|
_useVoxelShader = false;
|
||||||
|
_voxelsAsPoints = false;
|
||||||
|
_voxelShaderModeWhenVoxelsAsPointsEnabled = false;
|
||||||
|
|
||||||
_writeVoxelShaderData = NULL;
|
_writeVoxelShaderData = NULL;
|
||||||
_readVoxelShaderData = NULL;
|
_readVoxelShaderData = NULL;
|
||||||
|
@ -191,6 +193,8 @@ void VoxelSystem::freeBufferIndex(glBufferIndex index) {
|
||||||
|
|
||||||
// This will run through the list of _freeIndexes and reset their VBO array values to be "invisible".
|
// This will run through the list of _freeIndexes and reset their VBO array values to be "invisible".
|
||||||
void VoxelSystem::clearFreeBufferIndexes() {
|
void VoxelSystem::clearFreeBufferIndexes() {
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "###### clearFreeBufferIndexes()");
|
||||||
|
|
||||||
for (int i = 0; i < _freeIndexes.size(); i++) {
|
for (int i = 0; i < _freeIndexes.size(); i++) {
|
||||||
glBufferIndex nodeIndex = _freeIndexes[i];
|
glBufferIndex nodeIndex = _freeIndexes[i];
|
||||||
glm::vec3 startVertex(FLT_MAX, FLT_MAX, FLT_MAX);
|
glm::vec3 startVertex(FLT_MAX, FLT_MAX, FLT_MAX);
|
||||||
|
@ -217,7 +221,6 @@ void VoxelSystem::setMaxVoxels(int maxVoxels) {
|
||||||
if (maxVoxels == _maxVoxels) {
|
if (maxVoxels == _maxVoxels) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pthread_mutex_lock(&_bufferWriteLock);
|
|
||||||
bool wasInitialized = _initialized;
|
bool wasInitialized = _initialized;
|
||||||
if (wasInitialized) {
|
if (wasInitialized) {
|
||||||
clearAllNodesBufferIndex();
|
clearAllNodesBufferIndex();
|
||||||
|
@ -225,9 +228,8 @@ void VoxelSystem::setMaxVoxels(int maxVoxels) {
|
||||||
}
|
}
|
||||||
_maxVoxels = maxVoxels;
|
_maxVoxels = maxVoxels;
|
||||||
if (wasInitialized) {
|
if (wasInitialized) {
|
||||||
init();
|
initVoxelMemory();
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&_bufferWriteLock);
|
|
||||||
if (wasInitialized) {
|
if (wasInitialized) {
|
||||||
forceRedrawEntireTree();
|
forceRedrawEntireTree();
|
||||||
}
|
}
|
||||||
|
@ -238,7 +240,6 @@ void VoxelSystem::setUseVoxelShader(bool useVoxelShader) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&_bufferWriteLock);
|
|
||||||
bool wasInitialized = _initialized;
|
bool wasInitialized = _initialized;
|
||||||
if (wasInitialized) {
|
if (wasInitialized) {
|
||||||
clearAllNodesBufferIndex();
|
clearAllNodesBufferIndex();
|
||||||
|
@ -246,17 +247,59 @@ void VoxelSystem::setUseVoxelShader(bool useVoxelShader) {
|
||||||
}
|
}
|
||||||
_useVoxelShader = useVoxelShader;
|
_useVoxelShader = useVoxelShader;
|
||||||
if (wasInitialized) {
|
if (wasInitialized) {
|
||||||
init();
|
initVoxelMemory();
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&_bufferWriteLock);
|
|
||||||
|
|
||||||
if (wasInitialized) {
|
if (wasInitialized) {
|
||||||
forceRedrawEntireTree();
|
forceRedrawEntireTree();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VoxelSystem::setVoxelsAsPoints(bool voxelsAsPoints) {
|
||||||
|
if (_voxelsAsPoints == voxelsAsPoints) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wasInitialized = _initialized;
|
||||||
|
|
||||||
|
// If we're "turning on" Voxels as points, we need to double check that we're in voxel shader mode.
|
||||||
|
// Voxels as points uses the VoxelShader memory model, so if we're not in voxel shader mode,
|
||||||
|
// then set it to voxel shader mode.
|
||||||
|
if (voxelsAsPoints) {
|
||||||
|
Menu::getInstance()->getUseVoxelShader()->setEnabled(false);
|
||||||
|
|
||||||
|
// If enabling this... then do it before checking voxel shader status, that way, if voxel
|
||||||
|
// shader is already enabled, we just start drawing as points.
|
||||||
|
_voxelsAsPoints = true;
|
||||||
|
|
||||||
|
if (!_useVoxelShader) {
|
||||||
|
setUseVoxelShader(true);
|
||||||
|
_voxelShaderModeWhenVoxelsAsPointsEnabled = false;
|
||||||
|
} else {
|
||||||
|
_voxelShaderModeWhenVoxelsAsPointsEnabled = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Menu::getInstance()->getUseVoxelShader()->setEnabled(true);
|
||||||
|
// if we're turning OFF voxels as point mode, then we check what the state of voxel shader was when we enabled
|
||||||
|
// voxels as points, if it was OFF, then we return it to that value.
|
||||||
|
if (_voxelShaderModeWhenVoxelsAsPointsEnabled == false) {
|
||||||
|
setUseVoxelShader(false);
|
||||||
|
}
|
||||||
|
// If disabling this... then do it AFTER checking previous voxel shader status, that way, if voxel
|
||||||
|
// shader is was not enabled, we switch back to normal mode before turning off points.
|
||||||
|
_voxelsAsPoints = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set our voxels as points
|
||||||
|
if (wasInitialized) {
|
||||||
|
forceRedrawEntireTree();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void VoxelSystem::cleanupVoxelMemory() {
|
void VoxelSystem::cleanupVoxelMemory() {
|
||||||
if (_initialized) {
|
if (_initialized) {
|
||||||
|
pthread_mutex_lock(&_bufferWriteLock);
|
||||||
|
_initialized = false; // no longer initialized
|
||||||
if (_useVoxelShader) {
|
if (_useVoxelShader) {
|
||||||
// these are used when in VoxelShader mode.
|
// these are used when in VoxelShader mode.
|
||||||
glDeleteBuffers(1, &_vboVoxelsID);
|
glDeleteBuffers(1, &_vboVoxelsID);
|
||||||
|
@ -264,6 +307,9 @@ void VoxelSystem::cleanupVoxelMemory() {
|
||||||
|
|
||||||
delete[] _writeVoxelShaderData;
|
delete[] _writeVoxelShaderData;
|
||||||
delete[] _readVoxelShaderData;
|
delete[] _readVoxelShaderData;
|
||||||
|
|
||||||
|
_writeVoxelShaderData = _readVoxelShaderData = NULL;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Destroy glBuffers
|
// Destroy glBuffers
|
||||||
glDeleteBuffers(1, &_vboVerticesID);
|
glDeleteBuffers(1, &_vboVerticesID);
|
||||||
|
@ -280,11 +326,18 @@ void VoxelSystem::cleanupVoxelMemory() {
|
||||||
delete[] _writeVerticesArray;
|
delete[] _writeVerticesArray;
|
||||||
delete[] _readColorsArray;
|
delete[] _readColorsArray;
|
||||||
delete[] _writeColorsArray;
|
delete[] _writeColorsArray;
|
||||||
|
|
||||||
|
_readVerticesArray = NULL;
|
||||||
|
_writeVerticesArray = NULL;
|
||||||
|
_readColorsArray = NULL;
|
||||||
|
_writeColorsArray = NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
delete[] _writeVoxelDirtyArray;
|
delete[] _writeVoxelDirtyArray;
|
||||||
delete[] _readVoxelDirtyArray;
|
delete[] _readVoxelDirtyArray;
|
||||||
|
_writeVoxelDirtyArray = _readVoxelDirtyArray = NULL;
|
||||||
|
pthread_mutex_unlock(&_bufferWriteLock);
|
||||||
}
|
}
|
||||||
_initialized = false; // no longer initialized
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelSystem::setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndices[]) {
|
void VoxelSystem::setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndices[]) {
|
||||||
|
@ -316,11 +369,11 @@ void VoxelSystem::setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndice
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelSystem::initVoxelMemory() {
|
void VoxelSystem::initVoxelMemory() {
|
||||||
_initialMemoryUsageGPU = getFreeMemoryGPU();
|
pthread_mutex_lock(&_bufferWriteLock);
|
||||||
|
|
||||||
_memoryUsageRAM = 0;
|
_memoryUsageRAM = 0;
|
||||||
_memoryUsageVBO = 0; // our VBO allocations as we know them
|
_memoryUsageVBO = 0; // our VBO allocations as we know them
|
||||||
if (_useVoxelShader) {
|
if (_useVoxelShader) {
|
||||||
qDebug("Using Voxel Shader...\n");
|
|
||||||
GLuint* indicesArray = new GLuint[_maxVoxels];
|
GLuint* indicesArray = new GLuint[_maxVoxels];
|
||||||
|
|
||||||
// populate the indicesArray
|
// populate the indicesArray
|
||||||
|
@ -416,6 +469,10 @@ void VoxelSystem::initVoxelMemory() {
|
||||||
_perlinModulateProgram.release();
|
_perlinModulateProgram.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_initialized = true;
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&_bufferWriteLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) {
|
void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) {
|
||||||
|
@ -481,15 +538,15 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||||
int numBytesPacketHeader = numBytesForPacketHeader(sourceBuffer);
|
int numBytesPacketHeader = numBytesForPacketHeader(sourceBuffer);
|
||||||
unsigned char* voxelData = sourceBuffer + numBytesPacketHeader;
|
unsigned char* voxelData = sourceBuffer + numBytesPacketHeader;
|
||||||
|
|
||||||
pthread_mutex_lock(&_treeLock);
|
|
||||||
|
|
||||||
switch(command) {
|
switch(command) {
|
||||||
case PACKET_TYPE_VOXEL_DATA: {
|
case PACKET_TYPE_VOXEL_DATA: {
|
||||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
"readBitstreamToTree()");
|
"readBitstreamToTree()");
|
||||||
// ask the VoxelTree to read the bitstream into the tree
|
// ask the VoxelTree to read the bitstream into the tree
|
||||||
ReadBitstreamToTreeParams args(WANT_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceID());
|
ReadBitstreamToTreeParams args(WANT_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceID());
|
||||||
|
pthread_mutex_lock(&_treeLock);
|
||||||
_tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args);
|
_tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args);
|
||||||
|
pthread_mutex_unlock(&_treeLock);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PACKET_TYPE_VOXEL_DATA_MONOCHROME: {
|
case PACKET_TYPE_VOXEL_DATA_MONOCHROME: {
|
||||||
|
@ -497,7 +554,9 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||||
"readBitstreamToTree()");
|
"readBitstreamToTree()");
|
||||||
// ask the VoxelTree to read the MONOCHROME bitstream into the tree
|
// ask the VoxelTree to read the MONOCHROME bitstream into the tree
|
||||||
ReadBitstreamToTreeParams args(NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceID());
|
ReadBitstreamToTreeParams args(NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceID());
|
||||||
|
pthread_mutex_lock(&_treeLock);
|
||||||
_tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args);
|
_tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args);
|
||||||
|
pthread_mutex_unlock(&_treeLock);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PACKET_TYPE_Z_COMMAND:
|
case PACKET_TYPE_Z_COMMAND:
|
||||||
|
@ -515,7 +574,9 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||||
while (totalLength <= numBytes) {
|
while (totalLength <= numBytes) {
|
||||||
if (0==strcmp(command,(char*)"erase all")) {
|
if (0==strcmp(command,(char*)"erase all")) {
|
||||||
qDebug("got Z message == erase all\n");
|
qDebug("got Z message == erase all\n");
|
||||||
|
pthread_mutex_lock(&_treeLock);
|
||||||
_tree->eraseAllVoxels();
|
_tree->eraseAllVoxels();
|
||||||
|
pthread_mutex_unlock(&_treeLock);
|
||||||
_voxelsInReadArrays = _voxelsInWriteArrays = 0; // better way to do this??
|
_voxelsInReadArrays = _voxelsInWriteArrays = 0; // better way to do this??
|
||||||
}
|
}
|
||||||
if (0==strcmp(command,(char*)"add scene")) {
|
if (0==strcmp(command,(char*)"add scene")) {
|
||||||
|
@ -533,8 +594,6 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||||
setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY);
|
setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&_treeLock);
|
|
||||||
|
|
||||||
Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::VOXELS).updateValue(numBytes);
|
Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::VOXELS).updateValue(numBytes);
|
||||||
|
|
||||||
return numBytes;
|
return numBytes;
|
||||||
|
@ -542,7 +601,12 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||||
|
|
||||||
void VoxelSystem::setupNewVoxelsForDrawing() {
|
void VoxelSystem::setupNewVoxelsForDrawing() {
|
||||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
"setupNewVoxelsForDrawing()"); // would like to include _voxelsInArrays, _voxelsUpdated
|
"setupNewVoxelsForDrawing()");
|
||||||
|
|
||||||
|
if (!_initialized) {
|
||||||
|
return; // bail early if we're not initialized
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t start = usecTimestampNow();
|
uint64_t start = usecTimestampNow();
|
||||||
uint64_t sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000;
|
uint64_t sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000;
|
||||||
|
|
||||||
|
@ -606,7 +670,7 @@ void VoxelSystem::setupNewVoxelsForDrawing() {
|
||||||
void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) {
|
void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) {
|
||||||
|
|
||||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
"setupNewVoxelsForDrawingSingleNode()"); // would like to include _voxelsInArrays, _voxelsUpdated
|
"setupNewVoxelsForDrawingSingleNode() xxxxx");
|
||||||
|
|
||||||
uint64_t start = usecTimestampNow();
|
uint64_t start = usecTimestampNow();
|
||||||
uint64_t sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000;
|
uint64_t sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000;
|
||||||
|
@ -623,7 +687,11 @@ void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) {
|
||||||
checkForCulling(); // check for out of view and deleted voxels...
|
checkForCulling(); // check for out of view and deleted voxels...
|
||||||
|
|
||||||
// lock on the buffer write lock so we can't modify the data when the GPU is reading it
|
// lock on the buffer write lock so we can't modify the data when the GPU is reading it
|
||||||
pthread_mutex_lock(&_bufferWriteLock);
|
{
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
|
"setupNewVoxelsForDrawingSingleNode()... pthread_mutex_lock(&_bufferWriteLock);");
|
||||||
|
pthread_mutex_lock(&_bufferWriteLock);
|
||||||
|
}
|
||||||
|
|
||||||
_voxelsDirty = true; // if we got this far, then we can assume some voxels are dirty
|
_voxelsDirty = true; // if we got this far, then we can assume some voxels are dirty
|
||||||
|
|
||||||
|
@ -840,6 +908,10 @@ int VoxelSystem::updateNodeInArraysAsFullVBO(VoxelNode* node) {
|
||||||
// will forcibly remove it from the VBOs because we know better!!!
|
// will forcibly remove it from the VBOs because we know better!!!
|
||||||
int VoxelSystem::forceRemoveNodeFromArraysAsPartialVBO(VoxelNode* node) {
|
int VoxelSystem::forceRemoveNodeFromArraysAsPartialVBO(VoxelNode* node) {
|
||||||
|
|
||||||
|
if (!_initialized) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// if the node is not in the VBOs then we have nothing to do!
|
// if the node is not in the VBOs then we have nothing to do!
|
||||||
if (node->isKnownBufferIndex()) {
|
if (node->isKnownBufferIndex()) {
|
||||||
|
|
||||||
|
@ -869,6 +941,10 @@ int VoxelSystem::updateNodeInArraysAsPartialVBO(VoxelNode* node) {
|
||||||
if (_voxelsInWriteArrays >= _maxVoxels) {
|
if (_voxelsInWriteArrays >= _maxVoxels) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_initialized) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Now, if we've changed any attributes (our renderness, our color, etc) then update the Arrays...
|
// Now, if we've changed any attributes (our renderness, our color, etc) then update the Arrays...
|
||||||
if (node->isDirty()) {
|
if (node->isDirty()) {
|
||||||
|
@ -951,14 +1027,13 @@ void VoxelSystem::init() {
|
||||||
_setupNewVoxelsForDrawingLastElapsed = 0;
|
_setupNewVoxelsForDrawingLastElapsed = 0;
|
||||||
_lastViewCullingElapsed = _lastViewCulling = 0;
|
_lastViewCullingElapsed = _lastViewCulling = 0;
|
||||||
|
|
||||||
// When we change voxels representations in the arrays, we'll update this
|
|
||||||
_voxelsDirty = false;
|
_voxelsDirty = false;
|
||||||
_voxelsInWriteArrays = 0;
|
_voxelsInWriteArrays = 0;
|
||||||
_voxelsInReadArrays = 0;
|
_voxelsInReadArrays = 0;
|
||||||
|
|
||||||
// VBO for the verticesArray
|
// VBO for the verticesArray
|
||||||
|
_initialMemoryUsageGPU = getFreeMemoryGPU();
|
||||||
initVoxelMemory();
|
initVoxelMemory();
|
||||||
_initialized = true;
|
|
||||||
|
|
||||||
// our own _removedVoxels doesn't need to be notified of voxel deletes
|
// our own _removedVoxels doesn't need to be notified of voxel deletes
|
||||||
VoxelNode::removeDeleteHook(&_removedVoxels);
|
VoxelNode::removeDeleteHook(&_removedVoxels);
|
||||||
|
@ -1065,14 +1140,14 @@ void VoxelSystem::render(bool texture) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the lock so that the update thread won't change anything
|
|
||||||
pthread_mutex_lock(&_bufferWriteLock);
|
|
||||||
|
|
||||||
updateVBOs();
|
updateVBOs();
|
||||||
|
|
||||||
if (_useVoxelShader) {
|
|
||||||
|
|
||||||
Application::getInstance()->getVoxelShader().begin();
|
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..");
|
||||||
|
|
||||||
|
|
||||||
//Define this somewhere in your header file
|
//Define this somewhere in your header file
|
||||||
#define BUFFER_OFFSET(i) ((void*)(i))
|
#define BUFFER_OFFSET(i) ((void*)(i))
|
||||||
|
@ -1080,14 +1155,29 @@ void VoxelSystem::render(bool texture) {
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVoxelsID);
|
glBindBuffer(GL_ARRAY_BUFFER, _vboVoxelsID);
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
glVertexPointer(3, GL_FLOAT, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(0)); //The starting point of the VBO, for the vertices
|
glVertexPointer(3, GL_FLOAT, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(0)); //The starting point of the VBO, for the vertices
|
||||||
int loc = Application::getInstance()->getVoxelShader().attributeLocation("voxelSizeIn");
|
|
||||||
glEnableVertexAttribArray(loc);
|
int attributeLocation;
|
||||||
glVertexAttribPointer(loc, 1, GL_FLOAT, false, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(3*sizeof(float)));
|
|
||||||
|
if (!_voxelsAsPoints) {
|
||||||
|
Application::getInstance()->getVoxelShader().begin();
|
||||||
|
|
||||||
|
attributeLocation = Application::getInstance()->getVoxelShader().attributeLocation("voxelSizeIn");
|
||||||
|
glEnableVertexAttribArray(attributeLocation);
|
||||||
|
glVertexAttribPointer(attributeLocation, 1, GL_FLOAT, false, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(3*sizeof(float)));
|
||||||
|
} else {
|
||||||
|
const float POINT_SIZE = 4.0;
|
||||||
|
glPointSize(POINT_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
glEnableClientState(GL_COLOR_ARRAY);
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(4*sizeof(float)));//The starting point of colors
|
glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(4*sizeof(float)));//The starting point of colors
|
||||||
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboVoxelsIndicesID);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboVoxelsIndicesID);
|
||||||
glDrawElements(GL_POINTS, _voxelsInReadArrays, GL_UNSIGNED_INT, BUFFER_OFFSET(0)); //The starting point of the IBO
|
|
||||||
|
if (!dontCallOpenGLDraw) {
|
||||||
|
glDrawElements(GL_POINTS, _voxelsInReadArrays, GL_UNSIGNED_INT, BUFFER_OFFSET(0)); //The starting point of the IBO
|
||||||
|
}
|
||||||
|
|
||||||
// deactivate vertex and color arrays after drawing
|
// deactivate vertex and color arrays after drawing
|
||||||
glDisableClientState(GL_VERTEX_ARRAY);
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
@ -1097,9 +1187,13 @@ void VoxelSystem::render(bool texture) {
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
Application::getInstance()->getVoxelShader().end();
|
if (!_voxelsAsPoints) {
|
||||||
|
Application::getInstance()->getVoxelShader().end();
|
||||||
|
glDisableVertexAttribArray(attributeLocation);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "render().. openGL...");
|
||||||
|
|
||||||
// tell OpenGL where to find vertex and color information
|
// tell OpenGL where to find vertex and color information
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
glEnableClientState(GL_COLOR_ARRAY);
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
|
@ -1111,47 +1205,48 @@ void VoxelSystem::render(bool texture) {
|
||||||
glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
|
glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
|
||||||
|
|
||||||
applyScaleAndBindProgram(texture);
|
applyScaleAndBindProgram(texture);
|
||||||
|
|
||||||
// for performance, enable backface culling
|
// for performance, enable backface culling
|
||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
|
|
||||||
// draw voxels in 6 passes
|
// draw voxels in 6 passes
|
||||||
|
|
||||||
glNormal3f(0,1.0f,0);
|
if (!dontCallOpenGLDraw) {
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesTop);
|
glNormal3f(0,1.0f,0);
|
||||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesTop);
|
||||||
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||||
|
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||||
|
|
||||||
glNormal3f(0,-1.0f,0);
|
glNormal3f(0,-1.0f,0);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBottom);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBottom);
|
||||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||||
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||||
|
|
||||||
glNormal3f(-1.0f,0,0);
|
glNormal3f(-1.0f,0,0);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesLeft);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesLeft);
|
||||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||||
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||||
|
|
||||||
glNormal3f(1.0f,0,0);
|
glNormal3f(1.0f,0,0);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesRight);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesRight);
|
||||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||||
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||||
|
|
||||||
glNormal3f(0,0,-1.0f);
|
glNormal3f(0,0,-1.0f);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesFront);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesFront);
|
||||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||||
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
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,
|
|
||||||
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,
|
||||||
|
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
glDisable(GL_CULL_FACE);
|
glDisable(GL_CULL_FACE);
|
||||||
|
|
||||||
removeScaleAndReleaseProgram(texture);
|
removeScaleAndReleaseProgram(texture);
|
||||||
|
|
||||||
// deactivate vertex and color arrays after drawing
|
// deactivate vertex and color arrays after drawing
|
||||||
glDisableClientState(GL_VERTEX_ARRAY);
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
glDisableClientState(GL_COLOR_ARRAY);
|
glDisableClientState(GL_COLOR_ARRAY);
|
||||||
|
@ -1160,8 +1255,6 @@ void VoxelSystem::render(bool texture) {
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&_bufferWriteLock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelSystem::applyScaleAndBindProgram(bool texture) {
|
void VoxelSystem::applyScaleAndBindProgram(bool texture) {
|
||||||
|
@ -1416,7 +1509,7 @@ void VoxelSystem::falseColorizeDistanceFromView() {
|
||||||
class removeOutOfViewArgs {
|
class removeOutOfViewArgs {
|
||||||
public:
|
public:
|
||||||
VoxelSystem* thisVoxelSystem;
|
VoxelSystem* thisVoxelSystem;
|
||||||
ViewFrustum* thisViewFrustum;
|
ViewFrustum thisViewFrustum;
|
||||||
VoxelNodeBag dontRecurseBag;
|
VoxelNodeBag dontRecurseBag;
|
||||||
unsigned long nodesScanned;
|
unsigned long nodesScanned;
|
||||||
unsigned long nodesRemoved;
|
unsigned long nodesRemoved;
|
||||||
|
@ -1426,14 +1519,20 @@ public:
|
||||||
|
|
||||||
removeOutOfViewArgs(VoxelSystem* voxelSystem) :
|
removeOutOfViewArgs(VoxelSystem* voxelSystem) :
|
||||||
thisVoxelSystem(voxelSystem),
|
thisVoxelSystem(voxelSystem),
|
||||||
thisViewFrustum(voxelSystem->getViewFrustum()),
|
thisViewFrustum(*voxelSystem->getViewFrustum()),
|
||||||
dontRecurseBag(),
|
dontRecurseBag(),
|
||||||
nodesScanned(0),
|
nodesScanned(0),
|
||||||
nodesRemoved(0),
|
nodesRemoved(0),
|
||||||
nodesInside(0),
|
nodesInside(0),
|
||||||
nodesIntersect(0),
|
nodesIntersect(0),
|
||||||
nodesOutside(0)
|
nodesOutside(0)
|
||||||
{ }
|
{
|
||||||
|
// Widen the FOV for trimming
|
||||||
|
float originalFOV = thisViewFrustum.getFieldOfView();
|
||||||
|
float wideFOV = originalFOV + VIEW_FRUSTUM_FOV_OVERSEND;
|
||||||
|
thisViewFrustum.setFieldOfView(wideFOV);
|
||||||
|
thisViewFrustum.calculate();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void VoxelSystem::cancelImport() {
|
void VoxelSystem::cancelImport() {
|
||||||
|
@ -1459,7 +1558,7 @@ bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) {
|
||||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||||
VoxelNode* childNode = node->getChildAtIndex(i);
|
VoxelNode* childNode = node->getChildAtIndex(i);
|
||||||
if (childNode) {
|
if (childNode) {
|
||||||
ViewFrustum::location inFrustum = childNode->inFrustum(*args->thisViewFrustum);
|
ViewFrustum::location inFrustum = childNode->inFrustum(args->thisViewFrustum);
|
||||||
switch (inFrustum) {
|
switch (inFrustum) {
|
||||||
case ViewFrustum::OUTSIDE: {
|
case ViewFrustum::OUTSIDE: {
|
||||||
args->nodesOutside++;
|
args->nodesOutside++;
|
||||||
|
@ -1731,13 +1830,13 @@ VoxelNode* VoxelSystem::getVoxelAt(float x, float y, float z, float s) const {
|
||||||
|
|
||||||
void VoxelSystem::createVoxel(float x, float y, float z, float s,
|
void VoxelSystem::createVoxel(float x, float y, float z, float s,
|
||||||
unsigned char red, unsigned char green, unsigned char blue, bool destructive) {
|
unsigned char red, unsigned char green, unsigned char blue, bool destructive) {
|
||||||
pthread_mutex_lock(&_treeLock);
|
|
||||||
|
|
||||||
//qDebug("VoxelSystem::createVoxel(%f,%f,%f,%f)\n",x,y,z,s);
|
//qDebug("VoxelSystem::createVoxel(%f,%f,%f,%f)\n",x,y,z,s);
|
||||||
|
pthread_mutex_lock(&_treeLock);
|
||||||
_tree->createVoxel(x, y, z, s, red, green, blue, destructive);
|
_tree->createVoxel(x, y, z, s, red, green, blue, destructive);
|
||||||
setupNewVoxelsForDrawing();
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&_treeLock);
|
pthread_mutex_unlock(&_treeLock);
|
||||||
|
|
||||||
|
setupNewVoxelsForDrawing();
|
||||||
};
|
};
|
||||||
|
|
||||||
void VoxelSystem::createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color, bool destructive) {
|
void VoxelSystem::createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color, bool destructive) {
|
||||||
|
|
|
@ -65,8 +65,6 @@ public:
|
||||||
bool readFromSquareARGB32Pixels(const char* filename);
|
bool readFromSquareARGB32Pixels(const char* filename);
|
||||||
bool readFromSchematicFile(const char* filename);
|
bool readFromSchematicFile(const char* filename);
|
||||||
|
|
||||||
void setUseVoxelShader(bool useVoxelShader);
|
|
||||||
|
|
||||||
void setMaxVoxels(int maxVoxels);
|
void setMaxVoxels(int maxVoxels);
|
||||||
long int getMaxVoxels() const { return _maxVoxels; }
|
long int getMaxVoxels() const { return _maxVoxels; }
|
||||||
unsigned long getVoxelMemoryUsageRAM() const { return _memoryUsageRAM; }
|
unsigned long getVoxelMemoryUsageRAM() const { return _memoryUsageRAM; }
|
||||||
|
@ -137,6 +135,8 @@ public slots:
|
||||||
void cancelImport();
|
void cancelImport();
|
||||||
|
|
||||||
void setUseFastVoxelPipeline(bool useFastVoxelPipeline);
|
void setUseFastVoxelPipeline(bool useFastVoxelPipeline);
|
||||||
|
void setUseVoxelShader(bool useVoxelShader);
|
||||||
|
void setVoxelsAsPoints(bool voxelsAsPoints);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
float _treeScale;
|
float _treeScale;
|
||||||
|
@ -224,6 +224,9 @@ private:
|
||||||
void cleanupVoxelMemory();
|
void cleanupVoxelMemory();
|
||||||
|
|
||||||
bool _useVoxelShader;
|
bool _useVoxelShader;
|
||||||
|
bool _voxelsAsPoints;
|
||||||
|
bool _voxelShaderModeWhenVoxelsAsPointsEnabled;
|
||||||
|
|
||||||
GLuint _vboVoxelsID; /// when using voxel shader, we'll use this VBO
|
GLuint _vboVoxelsID; /// when using voxel shader, we'll use this VBO
|
||||||
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;
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
|
|
||||||
|
#include <glm/gtx/transform.hpp>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "BlendFace.h"
|
#include "BlendFace.h"
|
||||||
#include "Head.h"
|
#include "Head.h"
|
||||||
|
@ -41,21 +43,117 @@ void BlendFace::init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BlendFace::reset() {
|
||||||
|
_resetStates = true;
|
||||||
|
}
|
||||||
|
|
||||||
const glm::vec3 MODEL_TRANSLATION(0.0f, -120.0f, 40.0f); // temporary fudge factor
|
const glm::vec3 MODEL_TRANSLATION(0.0f, -120.0f, 40.0f); // temporary fudge factor
|
||||||
const float MODEL_SCALE = 0.0006f;
|
const float MODEL_SCALE = 0.0006f;
|
||||||
|
|
||||||
bool BlendFace::render(float alpha) {
|
void BlendFace::simulate(float deltaTime) {
|
||||||
if (!isActive()) {
|
if (!isActive()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set up world vertices on first simulate after load
|
||||||
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
|
if (_meshStates.isEmpty()) {
|
||||||
|
QVector<glm::vec3> vertices;
|
||||||
|
foreach (const FBXMesh& mesh, geometry.meshes) {
|
||||||
|
MeshState state;
|
||||||
|
if (mesh.springiness > 0.0f) {
|
||||||
|
state.worldSpaceVertices.resize(mesh.vertices.size());
|
||||||
|
state.vertexVelocities.resize(mesh.vertices.size());
|
||||||
|
state.worldSpaceNormals.resize(mesh.vertices.size());
|
||||||
|
}
|
||||||
|
_meshStates.append(state);
|
||||||
|
}
|
||||||
|
_resetStates = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::quat orientation = _owningHead->getOrientation();
|
||||||
|
glm::vec3 scale = glm::vec3(-1.0f, 1.0f, -1.0f) * _owningHead->getScale() * MODEL_SCALE;
|
||||||
|
glm::vec3 offset = MODEL_TRANSLATION - _geometry->getFBXGeometry().neckPivot;
|
||||||
|
glm::mat4 baseTransform = glm::translate(_owningHead->getPosition()) * glm::mat4_cast(orientation) *
|
||||||
|
glm::scale(scale) * glm::translate(offset);
|
||||||
|
|
||||||
|
for (int i = 0; i < _meshStates.size(); i++) {
|
||||||
|
MeshState& state = _meshStates[i];
|
||||||
|
int vertexCount = state.worldSpaceVertices.size();
|
||||||
|
if (vertexCount == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
glm::vec3* destVertices = state.worldSpaceVertices.data();
|
||||||
|
glm::vec3* destVelocities = state.vertexVelocities.data();
|
||||||
|
glm::vec3* destNormals = state.worldSpaceNormals.data();
|
||||||
|
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||||
|
const glm::vec3* sourceVertices = mesh.vertices.constData();
|
||||||
|
if (!mesh.blendshapes.isEmpty()) {
|
||||||
|
_blendedVertices.resize(max(_blendedVertices.size(), vertexCount));
|
||||||
|
memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3));
|
||||||
|
|
||||||
|
// blend in each coefficient
|
||||||
|
const vector<float>& coefficients = _owningHead->getBlendshapeCoefficients();
|
||||||
|
for (int j = 0; j < coefficients.size(); j++) {
|
||||||
|
float coefficient = coefficients[j];
|
||||||
|
if (coefficient == 0.0f || j >= mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData();
|
||||||
|
for (const int* index = mesh.blendshapes[j].indices.constData(),
|
||||||
|
*end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++) {
|
||||||
|
_blendedVertices[*index] += *vertex * coefficient;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceVertices = _blendedVertices.constData();
|
||||||
|
}
|
||||||
|
glm::mat4 transform = baseTransform;
|
||||||
|
if (mesh.isEye) {
|
||||||
|
transform = transform * glm::translate(mesh.pivot) * glm::mat4_cast(glm::inverse(orientation) *
|
||||||
|
_owningHead->getEyeRotation(orientation * ((mesh.pivot + offset) * scale) + _owningHead->getPosition())) *
|
||||||
|
glm::translate(-mesh.pivot);
|
||||||
|
}
|
||||||
|
if (_resetStates) {
|
||||||
|
for (int j = 0; j < vertexCount; j++) {
|
||||||
|
destVertices[j] = glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f));
|
||||||
|
destVelocities[j] = glm::vec3();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const float SPRINGINESS_MULTIPLIER = 200.0f;
|
||||||
|
const float DAMPING = 5.0f;
|
||||||
|
for (int j = 0; j < vertexCount; j++) {
|
||||||
|
destVelocities[j] += ((glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f)) - destVertices[j]) *
|
||||||
|
mesh.springiness * SPRINGINESS_MULTIPLIER - destVelocities[j] * DAMPING) * deltaTime;
|
||||||
|
destVertices[j] += destVelocities[j] * deltaTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int j = 0; j < vertexCount; j++) {
|
||||||
|
destNormals[j] = glm::vec3();
|
||||||
|
|
||||||
|
const glm::vec3& middle = destVertices[j];
|
||||||
|
for (QVarLengthArray<QPair<int, int>, 4>::const_iterator connection = mesh.vertexConnections.at(j).constBegin();
|
||||||
|
connection != mesh.vertexConnections.at(j).constEnd(); connection++) {
|
||||||
|
destNormals[j] += glm::normalize(glm::cross(destVertices[connection->second] - middle,
|
||||||
|
destVertices[connection->first] - middle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_resetStates = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BlendFace::render(float alpha) {
|
||||||
|
if (_meshStates.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set up blended buffer ids on first render after load
|
// set up blended buffer ids on first render after load/simulate
|
||||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes();
|
const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes();
|
||||||
if (_blendedVertexBufferIDs.isEmpty()) {
|
if (_blendedVertexBufferIDs.isEmpty()) {
|
||||||
foreach (const FBXMesh& mesh, geometry.meshes) {
|
foreach (const FBXMesh& mesh, geometry.meshes) {
|
||||||
GLuint id = 0;
|
GLuint id = 0;
|
||||||
if (!mesh.blendshapes.isEmpty()) {
|
if (!mesh.blendshapes.isEmpty() || mesh.springiness > 0.0f) {
|
||||||
glGenBuffers(1, &id);
|
glGenBuffers(1, &id);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, id);
|
glBindBuffer(GL_ARRAY_BUFFER, id);
|
||||||
glBufferData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3),
|
glBufferData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3),
|
||||||
|
@ -69,6 +167,9 @@ bool BlendFace::render(float alpha) {
|
||||||
_dilatedTextures.resize(geometry.meshes.size());
|
_dilatedTextures.resize(geometry.meshes.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::mat4 viewMatrix;
|
||||||
|
glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&viewMatrix);
|
||||||
|
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glTranslatef(_owningHead->getPosition().x, _owningHead->getPosition().y, _owningHead->getPosition().z);
|
glTranslatef(_owningHead->getPosition().x, _owningHead->getPosition().y, _owningHead->getPosition().z);
|
||||||
glm::quat orientation = _owningHead->getOrientation();
|
glm::quat orientation = _owningHead->getOrientation();
|
||||||
|
@ -88,8 +189,7 @@ bool BlendFace::render(float alpha) {
|
||||||
// enable normalization under the expectation that the GPU can do it faster
|
// enable normalization under the expectation that the GPU can do it faster
|
||||||
glEnable(GL_NORMALIZE);
|
glEnable(GL_NORMALIZE);
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glDisable(GL_COLOR_MATERIAL);
|
||||||
glColor4f(_owningHead->getSkinColor().r, _owningHead->getSkinColor().g, _owningHead->getSkinColor().b, alpha);
|
|
||||||
|
|
||||||
for (int i = 0; i < networkMeshes.size(); i++) {
|
for (int i = 0; i < networkMeshes.size(); i++) {
|
||||||
const NetworkMesh& networkMesh = networkMeshes.at(i);
|
const NetworkMesh& networkMesh = networkMeshes.at(i);
|
||||||
|
@ -105,7 +205,7 @@ bool BlendFace::render(float alpha) {
|
||||||
if (mesh.isEye) {
|
if (mesh.isEye) {
|
||||||
glTranslatef(mesh.pivot.x, mesh.pivot.y, mesh.pivot.z);
|
glTranslatef(mesh.pivot.x, mesh.pivot.y, mesh.pivot.z);
|
||||||
glm::quat rotation = glm::inverse(orientation) * _owningHead->getEyeRotation(orientation *
|
glm::quat rotation = glm::inverse(orientation) * _owningHead->getEyeRotation(orientation *
|
||||||
(mesh.pivot * scale + MODEL_TRANSLATION) + _owningHead->getPosition());
|
((mesh.pivot + offset) * scale) + _owningHead->getPosition());
|
||||||
glm::vec3 rotationAxis = glm::axis(rotation);
|
glm::vec3 rotationAxis = glm::axis(rotation);
|
||||||
glRotatef(glm::angle(rotation), -rotationAxis.x, rotationAxis.y, -rotationAxis.z);
|
glRotatef(glm::angle(rotation), -rotationAxis.x, rotationAxis.y, -rotationAxis.z);
|
||||||
glTranslatef(-mesh.pivot.x, -mesh.pivot.y, -mesh.pivot.z);
|
glTranslatef(-mesh.pivot.x, -mesh.pivot.y, -mesh.pivot.z);
|
||||||
|
@ -118,49 +218,62 @@ bool BlendFace::render(float alpha) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glMultMatrixf((const GLfloat*)&mesh.transform);
|
// apply material properties
|
||||||
|
glm::vec4 diffuse = glm::vec4(mesh.diffuseColor, alpha);
|
||||||
|
glm::vec4 specular = glm::vec4(mesh.specularColor, alpha);
|
||||||
|
glMaterialfv(GL_FRONT, GL_AMBIENT, (const float*)&diffuse);
|
||||||
|
glMaterialfv(GL_FRONT, GL_DIFFUSE, (const float*)&diffuse);
|
||||||
|
glMaterialfv(GL_FRONT, GL_SPECULAR, (const float*)&specular);
|
||||||
|
glMaterialf(GL_FRONT, GL_SHININESS, mesh.shininess);
|
||||||
|
|
||||||
// all meshes after the first are white
|
glMultMatrixf((const GLfloat*)&mesh.transform);
|
||||||
if (i == 1) {
|
|
||||||
glColor4f(1.0f, 1.0f, 1.0f, alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texture == NULL ? 0 : texture->getID());
|
glBindTexture(GL_TEXTURE_2D, texture == NULL ? 0 : texture->getID());
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, networkMesh.vertexBufferID);
|
glBindBuffer(GL_ARRAY_BUFFER, networkMesh.vertexBufferID);
|
||||||
if (mesh.blendshapes.isEmpty()) {
|
if (mesh.blendshapes.isEmpty() && mesh.springiness == 0.0f) {
|
||||||
glTexCoordPointer(2, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3)));
|
glTexCoordPointer(2, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3)));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
glTexCoordPointer(2, GL_FLOAT, 0, 0);
|
glTexCoordPointer(2, GL_FLOAT, 0, 0);
|
||||||
|
|
||||||
_blendedVertices.resize(max(_blendedVertices.size(), vertexCount));
|
|
||||||
_blendedNormals.resize(_blendedVertices.size());
|
|
||||||
memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3));
|
|
||||||
memcpy(_blendedNormals.data(), mesh.normals.constData(), vertexCount * sizeof(glm::vec3));
|
|
||||||
|
|
||||||
// blend in each coefficient
|
|
||||||
const vector<float>& coefficients = _owningHead->getBlendshapeCoefficients();
|
|
||||||
for (int j = 0; j < coefficients.size(); j++) {
|
|
||||||
float coefficient = coefficients[j];
|
|
||||||
if (coefficient == 0.0f || j >= mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const float NORMAL_COEFFICIENT_SCALE = 0.01f;
|
|
||||||
float normalCoefficient = coefficient * NORMAL_COEFFICIENT_SCALE;
|
|
||||||
const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData();
|
|
||||||
const glm::vec3* normal = mesh.blendshapes[j].normals.constData();
|
|
||||||
for (const int* index = mesh.blendshapes[j].indices.constData(),
|
|
||||||
*end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++, normal++) {
|
|
||||||
_blendedVertices[*index] += *vertex * coefficient;
|
|
||||||
_blendedNormals[*index] += *normal * normalCoefficient;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, _blendedVertexBufferIDs.at(i));
|
glBindBuffer(GL_ARRAY_BUFFER, _blendedVertexBufferIDs.at(i));
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), _blendedVertices.constData());
|
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3),
|
const MeshState& state = _meshStates.at(i);
|
||||||
vertexCount * sizeof(glm::vec3), _blendedNormals.constData());
|
if (!state.worldSpaceVertices.isEmpty()) {
|
||||||
|
glLoadMatrixf((const GLfloat*)&viewMatrix);
|
||||||
|
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), state.worldSpaceVertices.constData());
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3),
|
||||||
|
vertexCount * sizeof(glm::vec3), state.worldSpaceNormals.constData());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
_blendedVertices.resize(max(_blendedVertices.size(), vertexCount));
|
||||||
|
_blendedNormals.resize(_blendedVertices.size());
|
||||||
|
memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3));
|
||||||
|
memcpy(_blendedNormals.data(), mesh.normals.constData(), vertexCount * sizeof(glm::vec3));
|
||||||
|
|
||||||
|
// blend in each coefficient
|
||||||
|
const vector<float>& coefficients = _owningHead->getBlendshapeCoefficients();
|
||||||
|
for (int j = 0; j < coefficients.size(); j++) {
|
||||||
|
float coefficient = coefficients[j];
|
||||||
|
if (coefficient == 0.0f || j >= mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const float NORMAL_COEFFICIENT_SCALE = 0.01f;
|
||||||
|
float normalCoefficient = coefficient * NORMAL_COEFFICIENT_SCALE;
|
||||||
|
const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData();
|
||||||
|
const glm::vec3* normal = mesh.blendshapes[j].normals.constData();
|
||||||
|
for (const int* index = mesh.blendshapes[j].indices.constData(),
|
||||||
|
*end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++, normal++) {
|
||||||
|
_blendedVertices[*index] += *vertex * coefficient;
|
||||||
|
_blendedNormals[*index] += *normal * normalCoefficient;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), _blendedVertices.constData());
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3),
|
||||||
|
vertexCount * sizeof(glm::vec3), _blendedNormals.constData());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
glVertexPointer(3, GL_FLOAT, 0, 0);
|
glVertexPointer(3, GL_FLOAT, 0, 0);
|
||||||
glNormalPointer(GL_FLOAT, 0, (void*)(vertexCount * sizeof(glm::vec3)));
|
glNormalPointer(GL_FLOAT, 0, (void*)(vertexCount * sizeof(glm::vec3)));
|
||||||
|
@ -191,15 +304,22 @@ bool BlendFace::render(float alpha) {
|
||||||
|
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
|
|
||||||
|
// restore all the default material settings
|
||||||
|
Application::getInstance()->setupWorldLight(*Application::getInstance()->getCamera());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlendFace::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const {
|
bool BlendFace::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition, bool upright) const {
|
||||||
if (!isActive()) {
|
if (!isActive()) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
glm::vec3 translation = _owningHead->getPosition();
|
||||||
glm::quat orientation = _owningHead->getOrientation();
|
glm::quat orientation = _owningHead->getOrientation();
|
||||||
|
if (upright) {
|
||||||
|
translation = static_cast<MyAvatar*>(_owningHead->_owningAvatar)->getUprightHeadPosition();
|
||||||
|
orientation = static_cast<Avatar*>(_owningHead->_owningAvatar)->getWorldAlignedOrientation();
|
||||||
|
}
|
||||||
glm::vec3 scale(-_owningHead->getScale() * MODEL_SCALE, _owningHead->getScale() * MODEL_SCALE,
|
glm::vec3 scale(-_owningHead->getScale() * MODEL_SCALE, _owningHead->getScale() * MODEL_SCALE,
|
||||||
-_owningHead->getScale() * MODEL_SCALE);
|
-_owningHead->getScale() * MODEL_SCALE);
|
||||||
bool foundFirst = false;
|
bool foundFirst = false;
|
||||||
|
@ -207,16 +327,16 @@ void BlendFace::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEy
|
||||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
foreach (const FBXMesh& mesh, geometry.meshes) {
|
foreach (const FBXMesh& mesh, geometry.meshes) {
|
||||||
if (mesh.isEye) {
|
if (mesh.isEye) {
|
||||||
glm::vec3 position = orientation * ((mesh.pivot + MODEL_TRANSLATION - geometry.neckPivot) * scale) +
|
glm::vec3 position = orientation * ((mesh.pivot + MODEL_TRANSLATION - geometry.neckPivot) * scale) + translation;
|
||||||
_owningHead->getPosition();
|
|
||||||
if (foundFirst) {
|
if (foundFirst) {
|
||||||
secondEyePosition = position;
|
secondEyePosition = position;
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
firstEyePosition = position;
|
firstEyePosition = position;
|
||||||
foundFirst = true;
|
foundFirst = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlendFace::setModelURL(const QUrl& url) {
|
void BlendFace::setModelURL(const QUrl& url) {
|
||||||
|
@ -238,4 +358,5 @@ void BlendFace::deleteGeometry() {
|
||||||
glDeleteBuffers(1, &id);
|
glDeleteBuffers(1, &id);
|
||||||
}
|
}
|
||||||
_blendedVertexBufferIDs.clear();
|
_blendedVertexBufferIDs.clear();
|
||||||
|
_meshStates.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,12 +33,17 @@ public:
|
||||||
bool isActive() const { return _geometry && _geometry->isLoaded(); }
|
bool isActive() const { return _geometry && _geometry->isLoaded(); }
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
void reset();
|
||||||
|
void simulate(float deltaTime);
|
||||||
bool render(float alpha);
|
bool render(float alpha);
|
||||||
|
|
||||||
Q_INVOKABLE void setModelURL(const QUrl& url);
|
Q_INVOKABLE void setModelURL(const QUrl& url);
|
||||||
const QUrl& getModelURL() const { return _modelURL; }
|
const QUrl& getModelURL() const { return _modelURL; }
|
||||||
|
|
||||||
void getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const;
|
/// Retrieve the positions of up to two eye meshes.
|
||||||
|
/// \param upright if true, retrieve the locations of the eyes in the upright position
|
||||||
|
/// \return whether or not both eye meshes were found
|
||||||
|
bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition, bool upright = false) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -50,8 +55,17 @@ private:
|
||||||
|
|
||||||
QSharedPointer<NetworkGeometry> _geometry;
|
QSharedPointer<NetworkGeometry> _geometry;
|
||||||
|
|
||||||
|
class MeshState {
|
||||||
|
public:
|
||||||
|
QVector<glm::vec3> worldSpaceVertices;
|
||||||
|
QVector<glm::vec3> vertexVelocities;
|
||||||
|
QVector<glm::vec3> worldSpaceNormals;
|
||||||
|
};
|
||||||
|
|
||||||
|
QVector<MeshState> _meshStates;
|
||||||
QVector<GLuint> _blendedVertexBufferIDs;
|
QVector<GLuint> _blendedVertexBufferIDs;
|
||||||
QVector<QSharedPointer<Texture> > _dilatedTextures;
|
QVector<QSharedPointer<Texture> > _dilatedTextures;
|
||||||
|
bool _resetStates;
|
||||||
|
|
||||||
QVector<glm::vec3> _blendedVertices;
|
QVector<glm::vec3> _blendedVertices;
|
||||||
QVector<glm::vec3> _blendedNormals;
|
QVector<glm::vec3> _blendedNormals;
|
||||||
|
|
|
@ -117,6 +117,8 @@ void Head::reset() {
|
||||||
if (USING_PHYSICAL_MOHAWK) {
|
if (USING_PHYSICAL_MOHAWK) {
|
||||||
resetHairPhysics();
|
resetHairPhysics();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_blendFace.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Head::resetHairPhysics() {
|
void Head::resetHairPhysics() {
|
||||||
|
@ -235,6 +237,8 @@ void Head::simulate(float deltaTime, bool isMine) {
|
||||||
if (USING_PHYSICAL_MOHAWK) {
|
if (USING_PHYSICAL_MOHAWK) {
|
||||||
updateHairPhysics(deltaTime);
|
updateHairPhysics(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_blendFace.simulate(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Head::calculateGeometry() {
|
void Head::calculateGeometry() {
|
||||||
|
@ -300,19 +304,21 @@ void Head::render(float alpha, bool isMine) {
|
||||||
renderEyeBrows();
|
renderEyeBrows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_blendFace.isActive()) {
|
||||||
|
// the blend face may have custom eye meshes
|
||||||
|
_blendFace.getEyePositions(_leftEyePosition, _rightEyePosition);
|
||||||
|
}
|
||||||
|
|
||||||
if (_renderLookatVectors) {
|
if (_renderLookatVectors) {
|
||||||
glm::vec3 firstEyePosition = _leftEyePosition;
|
renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition);
|
||||||
glm::vec3 secondEyePosition = _rightEyePosition;
|
|
||||||
if (_blendFace.isActive()) {
|
|
||||||
// the blend face may have custom eye meshes
|
|
||||||
_blendFace.getEyePositions(firstEyePosition, secondEyePosition);
|
|
||||||
}
|
|
||||||
renderLookatVectors(firstEyePosition, secondEyePosition, _lookAtPosition);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Head::setScale (float scale) {
|
void Head::setScale (float scale) {
|
||||||
|
if (_scale == scale) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
_scale = scale;
|
_scale = scale;
|
||||||
|
|
||||||
createMohawk();
|
createMohawk();
|
||||||
|
|
|
@ -158,6 +158,7 @@ private:
|
||||||
void resetHairPhysics();
|
void resetHairPhysics();
|
||||||
void updateHairPhysics(float deltaTime);
|
void updateHairPhysics(float deltaTime);
|
||||||
|
|
||||||
|
friend class BlendFace;
|
||||||
friend class PerlinFace;
|
friend class PerlinFace;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -300,6 +300,7 @@ const char* FACESHIFT_BLENDSHAPES[] = {
|
||||||
|
|
||||||
class Transform {
|
class Transform {
|
||||||
public:
|
public:
|
||||||
|
QByteArray name;
|
||||||
bool inheritScale;
|
bool inheritScale;
|
||||||
glm::mat4 withScale;
|
glm::mat4 withScale;
|
||||||
glm::mat4 withoutScale;
|
glm::mat4 withoutScale;
|
||||||
|
@ -346,6 +347,13 @@ void printNode(const FBXNode& node, int indent) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Material {
|
||||||
|
public:
|
||||||
|
glm::vec3 diffuse;
|
||||||
|
glm::vec3 specular;
|
||||||
|
float shininess;
|
||||||
|
};
|
||||||
|
|
||||||
FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) {
|
FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) {
|
||||||
QHash<qint64, FBXMesh> meshes;
|
QHash<qint64, FBXMesh> meshes;
|
||||||
QVector<ExtractedBlendshape> blendshapes;
|
QVector<ExtractedBlendshape> blendshapes;
|
||||||
|
@ -354,6 +362,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
QHash<qint64, Transform> localTransforms;
|
QHash<qint64, Transform> localTransforms;
|
||||||
QHash<qint64, glm::mat4> transformLinkMatrices;
|
QHash<qint64, glm::mat4> transformLinkMatrices;
|
||||||
QHash<qint64, QByteArray> textureFilenames;
|
QHash<qint64, QByteArray> textureFilenames;
|
||||||
|
QHash<qint64, Material> materials;
|
||||||
QHash<qint64, qint64> diffuseTextures;
|
QHash<qint64, qint64> diffuseTextures;
|
||||||
QHash<qint64, qint64> bumpTextures;
|
QHash<qint64, qint64> bumpTextures;
|
||||||
|
|
||||||
|
@ -374,7 +383,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
}
|
}
|
||||||
QList<QVariant> mappings = blendshapeMappings.values(blendshapeName);
|
QList<QVariant> mappings = blendshapeMappings.values(blendshapeName);
|
||||||
if (mappings.isEmpty()) {
|
if (mappings.isEmpty()) {
|
||||||
blendshapeIndices.insert("ExpressionBlendshapes." + blendshapeName, QPair<int, float>(i, 1.0f));
|
blendshapeIndices.insert(blendshapeName, QPair<int, float>(i, 1.0f));
|
||||||
} else {
|
} else {
|
||||||
foreach (const QVariant& mapping, mappings) {
|
foreach (const QVariant& mapping, mappings) {
|
||||||
QVariantList blendshapeMapping = mapping.toList();
|
QVariantList blendshapeMapping = mapping.toList();
|
||||||
|
@ -394,6 +403,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
|
|
||||||
QVector<int> polygonIndices;
|
QVector<int> polygonIndices;
|
||||||
QVector<glm::vec3> normals;
|
QVector<glm::vec3> normals;
|
||||||
|
QVector<int> normalIndices;
|
||||||
QVector<glm::vec2> texCoords;
|
QVector<glm::vec2> texCoords;
|
||||||
QVector<int> texCoordIndices;
|
QVector<int> texCoordIndices;
|
||||||
foreach (const FBXNode& data, object.children) {
|
foreach (const FBXNode& data, object.children) {
|
||||||
|
@ -409,6 +419,9 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
if (subdata.name == "Normals") {
|
if (subdata.name == "Normals") {
|
||||||
normals = createVec3Vector(subdata.properties.at(0).value<QVector<double> >());
|
normals = createVec3Vector(subdata.properties.at(0).value<QVector<double> >());
|
||||||
|
|
||||||
|
} else if (subdata.name == "NormalsIndex") {
|
||||||
|
normalIndices = subdata.properties.at(0).value<QVector<int> >();
|
||||||
|
|
||||||
} else if (subdata.name == "MappingInformationType" &&
|
} else if (subdata.name == "MappingInformationType" &&
|
||||||
subdata.properties.at(0) == "ByVertice") {
|
subdata.properties.at(0) == "ByVertice") {
|
||||||
byVertex = true;
|
byVertex = true;
|
||||||
|
@ -432,10 +445,20 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
// convert normals from per-index to per-vertex if necessary
|
// convert normals from per-index to per-vertex if necessary
|
||||||
if (mesh.normals.isEmpty()) {
|
if (mesh.normals.isEmpty()) {
|
||||||
mesh.normals.resize(mesh.vertices.size());
|
mesh.normals.resize(mesh.vertices.size());
|
||||||
for (int i = 0, n = polygonIndices.size(); i < n; i++) {
|
if (normalIndices.isEmpty()) {
|
||||||
int index = polygonIndices.at(i);
|
for (int i = 0, n = polygonIndices.size(); i < n; i++) {
|
||||||
mesh.normals[index < 0 ? (-index - 1) : index] = normals.at(i);
|
int index = polygonIndices.at(i);
|
||||||
}
|
mesh.normals[index < 0 ? (-index - 1) : index] = normals.at(i);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0, n = polygonIndices.size(); i < n; i++) {
|
||||||
|
int index = polygonIndices.at(i);
|
||||||
|
int normalIndex = normalIndices.at(i);
|
||||||
|
if (normalIndex >= 0) {
|
||||||
|
mesh.normals[index < 0 ? (-index - 1) : index] = normals.at(normalIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// same with the tex coords
|
// same with the tex coords
|
||||||
|
@ -513,7 +536,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
glm::vec3 preRotation, rotation, postRotation;
|
glm::vec3 preRotation, rotation, postRotation;
|
||||||
glm::vec3 scale = glm::vec3(1.0f, 1.0f, 1.0f);
|
glm::vec3 scale = glm::vec3(1.0f, 1.0f, 1.0f);
|
||||||
glm::vec3 scalePivot, rotationPivot;
|
glm::vec3 scalePivot, rotationPivot;
|
||||||
Transform transform = { true };
|
Transform transform = { name, true };
|
||||||
foreach (const FBXNode& subobject, object.children) {
|
foreach (const FBXNode& subobject, object.children) {
|
||||||
if (subobject.name == "Properties70") {
|
if (subobject.name == "Properties70") {
|
||||||
foreach (const FBXNode& property, subobject.children) {
|
foreach (const FBXNode& property, subobject.children) {
|
||||||
|
@ -578,6 +601,31 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
textureFilenames.insert(object.properties.at(0).value<qint64>(), filename);
|
textureFilenames.insert(object.properties.at(0).value<qint64>(), filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (object.name == "Material") {
|
||||||
|
Material material = { glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 1.0f, 1.0f), 96.0f };
|
||||||
|
foreach (const FBXNode& subobject, object.children) {
|
||||||
|
if (subobject.name == "Properties70") {
|
||||||
|
foreach (const FBXNode& property, subobject.children) {
|
||||||
|
if (property.name == "P") {
|
||||||
|
if (property.properties.at(0) == "DiffuseColor") {
|
||||||
|
material.diffuse = glm::vec3(property.properties.at(4).value<double>(),
|
||||||
|
property.properties.at(5).value<double>(),
|
||||||
|
property.properties.at(6).value<double>());
|
||||||
|
|
||||||
|
} else if (property.properties.at(0) == "SpecularColor") {
|
||||||
|
material.specular = glm::vec3(property.properties.at(4).value<double>(),
|
||||||
|
property.properties.at(5).value<double>(),
|
||||||
|
property.properties.at(6).value<double>());
|
||||||
|
|
||||||
|
} else if (property.properties.at(0) == "Shininess") {
|
||||||
|
material.shininess = property.properties.at(4).value<double>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
materials.insert(object.properties.at(0).value<qint64>(), material);
|
||||||
|
|
||||||
} else if (object.name == "Deformer") {
|
} else if (object.name == "Deformer") {
|
||||||
if (object.properties.at(2) == "Cluster") {
|
if (object.properties.at(2) == "Cluster") {
|
||||||
foreach (const FBXNode& subobject, object.children) {
|
foreach (const FBXNode& subobject, object.children) {
|
||||||
|
@ -588,8 +636,13 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
}
|
}
|
||||||
} else if (object.properties.at(2) == "BlendShapeChannel") {
|
} else if (object.properties.at(2) == "BlendShapeChannel") {
|
||||||
QByteArray name = object.properties.at(1).toByteArray();
|
QByteArray name = object.properties.at(1).toByteArray();
|
||||||
|
name = name.left(name.indexOf('\0'));
|
||||||
|
if (!blendshapeIndices.contains(name)) {
|
||||||
|
// try everything after the dot
|
||||||
|
name = name.mid(name.lastIndexOf('.') + 1);
|
||||||
|
}
|
||||||
blendshapeChannelIndices.insert(object.properties.at(0).value<qint64>(),
|
blendshapeChannelIndices.insert(object.properties.at(0).value<qint64>(),
|
||||||
blendshapeIndices.value(name.left(name.indexOf('\0'))));
|
blendshapeIndices.value(name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -631,18 +684,26 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
mapping.value("ry").toFloat(), mapping.value("rz").toFloat())))) *
|
mapping.value("ry").toFloat(), mapping.value("rz").toFloat())))) *
|
||||||
glm::scale(offsetScale, offsetScale, offsetScale);
|
glm::scale(offsetScale, offsetScale, offsetScale);
|
||||||
|
|
||||||
// as a temporary hack, put the mesh with the most blendshapes on top; assume it to be the face
|
|
||||||
FBXGeometry geometry;
|
FBXGeometry geometry;
|
||||||
int mostBlendshapes = 0;
|
QVariantHash springs = mapping.value("spring").toHash();
|
||||||
|
QVariant defaultSpring = springs.value("default");
|
||||||
for (QHash<qint64, FBXMesh>::iterator it = meshes.begin(); it != meshes.end(); it++) {
|
for (QHash<qint64, FBXMesh>::iterator it = meshes.begin(); it != meshes.end(); it++) {
|
||||||
FBXMesh& mesh = it.value();
|
FBXMesh& mesh = it.value();
|
||||||
|
|
||||||
// accumulate local transforms
|
// accumulate local transforms
|
||||||
qint64 modelID = parentMap.value(it.key());
|
qint64 modelID = parentMap.value(it.key());
|
||||||
|
mesh.springiness = springs.value(localTransforms.value(modelID).name, defaultSpring).toFloat();
|
||||||
glm::mat4 modelTransform = getGlobalTransform(parentMap, localTransforms, modelID);
|
glm::mat4 modelTransform = getGlobalTransform(parentMap, localTransforms, modelID);
|
||||||
|
|
||||||
// look for textures
|
// look for textures, material properties
|
||||||
foreach (qint64 childID, childMap.values(modelID)) {
|
foreach (qint64 childID, childMap.values(modelID)) {
|
||||||
|
if (!materials.contains(childID)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Material material = materials.value(childID);
|
||||||
|
mesh.diffuseColor = material.diffuse;
|
||||||
|
mesh.specularColor = material.specular;
|
||||||
|
mesh.shininess = material.shininess;
|
||||||
qint64 diffuseTextureID = diffuseTextures.value(childID);
|
qint64 diffuseTextureID = diffuseTextures.value(childID);
|
||||||
if (diffuseTextureID != 0) {
|
if (diffuseTextureID != 0) {
|
||||||
mesh.diffuseFilename = textureFilenames.value(diffuseTextureID);
|
mesh.diffuseFilename = textureFilenames.value(diffuseTextureID);
|
||||||
|
@ -676,13 +737,47 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mesh.blendshapes.size() > mostBlendshapes) {
|
// extract spring edges, connections if springy
|
||||||
geometry.meshes.prepend(mesh);
|
if (mesh.springiness > 0.0f) {
|
||||||
mostBlendshapes = mesh.blendshapes.size();
|
QSet<QPair<int, int> > edges;
|
||||||
|
|
||||||
} else {
|
mesh.vertexConnections.resize(mesh.vertices.size());
|
||||||
geometry.meshes.append(mesh);
|
for (int i = 0; i < mesh.quadIndices.size(); i += 4) {
|
||||||
|
int index0 = mesh.quadIndices.at(i);
|
||||||
|
int index1 = mesh.quadIndices.at(i + 1);
|
||||||
|
int index2 = mesh.quadIndices.at(i + 2);
|
||||||
|
int index3 = mesh.quadIndices.at(i + 3);
|
||||||
|
|
||||||
|
edges.insert(QPair<int, int>(qMin(index0, index1), qMax(index0, index1)));
|
||||||
|
edges.insert(QPair<int, int>(qMin(index1, index2), qMax(index1, index2)));
|
||||||
|
edges.insert(QPair<int, int>(qMin(index2, index3), qMax(index2, index3)));
|
||||||
|
edges.insert(QPair<int, int>(qMin(index3, index0), qMax(index3, index0)));
|
||||||
|
|
||||||
|
mesh.vertexConnections[index0].append(QPair<int, int>(index3, index1));
|
||||||
|
mesh.vertexConnections[index1].append(QPair<int, int>(index0, index2));
|
||||||
|
mesh.vertexConnections[index2].append(QPair<int, int>(index1, index3));
|
||||||
|
mesh.vertexConnections[index3].append(QPair<int, int>(index2, index0));
|
||||||
|
}
|
||||||
|
for (int i = 0; i < mesh.triangleIndices.size(); i += 3) {
|
||||||
|
int index0 = mesh.triangleIndices.at(i);
|
||||||
|
int index1 = mesh.triangleIndices.at(i + 1);
|
||||||
|
int index2 = mesh.triangleIndices.at(i + 2);
|
||||||
|
|
||||||
|
edges.insert(QPair<int, int>(qMin(index0, index1), qMax(index0, index1)));
|
||||||
|
edges.insert(QPair<int, int>(qMin(index1, index2), qMax(index1, index2)));
|
||||||
|
edges.insert(QPair<int, int>(qMin(index2, index0), qMax(index2, index0)));
|
||||||
|
|
||||||
|
mesh.vertexConnections[index0].append(QPair<int, int>(index2, index1));
|
||||||
|
mesh.vertexConnections[index1].append(QPair<int, int>(index0, index2));
|
||||||
|
mesh.vertexConnections[index2].append(QPair<int, int>(index1, index0));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (QSet<QPair<int, int> >::const_iterator edge = edges.constBegin(); edge != edges.constEnd(); edge++) {
|
||||||
|
mesh.springEdges.append(*edge);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry.meshes.append(mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract translation component for neck pivot
|
// extract translation component for neck pivot
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#ifndef __interface__FBXReader__
|
#ifndef __interface__FBXReader__
|
||||||
#define __interface__FBXReader__
|
#define __interface__FBXReader__
|
||||||
|
|
||||||
|
#include <QVarLengthArray>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
|
@ -51,10 +52,18 @@ public:
|
||||||
|
|
||||||
bool isEye;
|
bool isEye;
|
||||||
|
|
||||||
|
glm::vec3 diffuseColor;
|
||||||
|
glm::vec3 specularColor;
|
||||||
|
float shininess;
|
||||||
|
|
||||||
QByteArray diffuseFilename;
|
QByteArray diffuseFilename;
|
||||||
QByteArray normalFilename;
|
QByteArray normalFilename;
|
||||||
|
|
||||||
QVector<FBXBlendshape> blendshapes;
|
QVector<FBXBlendshape> blendshapes;
|
||||||
|
|
||||||
|
float springiness;
|
||||||
|
QVector<QPair<int, int> > springEdges;
|
||||||
|
QVector<QVarLengthArray<QPair<int, int>, 4> > vertexConnections;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A set of meshes extracted from an FBX document.
|
/// A set of meshes extracted from an FBX document.
|
||||||
|
|
|
@ -346,7 +346,7 @@ void NetworkGeometry::maybeReadModelWithMapping() {
|
||||||
glGenBuffers(1, &networkMesh.vertexBufferID);
|
glGenBuffers(1, &networkMesh.vertexBufferID);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, networkMesh.vertexBufferID);
|
glBindBuffer(GL_ARRAY_BUFFER, networkMesh.vertexBufferID);
|
||||||
|
|
||||||
if (mesh.blendshapes.isEmpty()) {
|
if (mesh.blendshapes.isEmpty() && mesh.springiness == 0.0f) {
|
||||||
glBufferData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3) +
|
glBufferData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3) +
|
||||||
mesh.texCoords.size() * sizeof(glm::vec2), NULL, GL_STATIC_DRAW);
|
mesh.texCoords.size() * sizeof(glm::vec2), NULL, GL_STATIC_DRAW);
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, 0, mesh.vertices.size() * sizeof(glm::vec3), mesh.vertices.constData());
|
glBufferSubData(GL_ARRAY_BUFFER, 0, mesh.vertices.size() * sizeof(glm::vec3), mesh.vertices.constData());
|
||||||
|
|
|
@ -85,7 +85,8 @@ bool PacketSender::process() {
|
||||||
int packetsLeft = _packets.size();
|
int packetsLeft = _packets.size();
|
||||||
bool keepGoing = packetsLeft > 0;
|
bool keepGoing = packetsLeft > 0;
|
||||||
while (keepGoing) {
|
while (keepGoing) {
|
||||||
|
uint64_t SEND_INTERVAL_USECS = (_packetsPerSecond == 0) ? USECS_PER_SECOND : (USECS_PER_SECOND / _packetsPerSecond);
|
||||||
|
|
||||||
NetworkPacket& packet = _packets.front();
|
NetworkPacket& packet = _packets.front();
|
||||||
|
|
||||||
// send the packet through the NodeList...
|
// send the packet through the NodeList...
|
||||||
|
@ -93,7 +94,7 @@ bool PacketSender::process() {
|
||||||
|
|
||||||
nodeSocket->send(&packet.getAddress(), packet.getData(), packet.getLength());
|
nodeSocket->send(&packet.getAddress(), packet.getData(), packet.getLength());
|
||||||
packetsThisCall++;
|
packetsThisCall++;
|
||||||
|
|
||||||
if (_notify) {
|
if (_notify) {
|
||||||
_notify->packetSentNotification(packet.getLength());
|
_notify->packetSentNotification(packet.getLength());
|
||||||
}
|
}
|
||||||
|
@ -110,11 +111,15 @@ bool PacketSender::process() {
|
||||||
|
|
||||||
// dynamically sleep until we need to fire off the next set of voxels we only sleep in threaded mode
|
// dynamically sleep until we need to fire off the next set of voxels we only sleep in threaded mode
|
||||||
if (keepGoing) {
|
if (keepGoing) {
|
||||||
|
now = usecTimestampNow();
|
||||||
uint64_t elapsed = now - _lastSendTime;
|
uint64_t elapsed = now - _lastSendTime;
|
||||||
int usecToSleep = std::max(SEND_INTERVAL_USECS, SEND_INTERVAL_USECS - elapsed);
|
int usecToSleep = SEND_INTERVAL_USECS - elapsed;
|
||||||
|
|
||||||
// we only sleep in non-threaded mode
|
// we only sleep in non-threaded mode
|
||||||
if (usecToSleep > 0) {
|
if (usecToSleep > 0) {
|
||||||
|
if (usecToSleep > SEND_INTERVAL_USECS) {
|
||||||
|
usecToSleep = SEND_INTERVAL_USECS;
|
||||||
|
}
|
||||||
usleep(usecToSleep);
|
usleep(usecToSleep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ public:
|
||||||
/// \thread any thread, typically the application thread
|
/// \thread any thread, typically the application thread
|
||||||
void queuePacketForSending(sockaddr& address, unsigned char* packetData, ssize_t packetLength);
|
void queuePacketForSending(sockaddr& address, unsigned char* packetData, ssize_t packetLength);
|
||||||
|
|
||||||
void setPacketsPerSecond(int packetsPerSecond) { _packetsPerSecond = std::min(MINIMUM_PACKETS_PER_SECOND, packetsPerSecond); }
|
void setPacketsPerSecond(int packetsPerSecond) { _packetsPerSecond = std::max(MINIMUM_PACKETS_PER_SECOND, packetsPerSecond); }
|
||||||
int getPacketsPerSecond() const { return _packetsPerSecond; }
|
int getPacketsPerSecond() const { return _packetsPerSecond; }
|
||||||
|
|
||||||
void setPacketSenderNotify(PacketSenderNotify* notify) { _notify = notify; }
|
void setPacketSenderNotify(PacketSenderNotify* notify) { _notify = notify; }
|
||||||
|
|
|
@ -103,6 +103,7 @@ int PerfStat::DumpStats(char** array) {
|
||||||
return lineCount;
|
return lineCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PerformanceWarning::_suppressShortTimings = false;
|
||||||
|
|
||||||
// Destructor handles recording all of our stats
|
// Destructor handles recording all of our stats
|
||||||
PerformanceWarning::~PerformanceWarning() {
|
PerformanceWarning::~PerformanceWarning() {
|
||||||
|
@ -111,9 +112,17 @@ PerformanceWarning::~PerformanceWarning() {
|
||||||
if ((_alwaysDisplay || _renderWarningsOn) && elapsedmsec > 1) {
|
if ((_alwaysDisplay || _renderWarningsOn) && elapsedmsec > 1) {
|
||||||
if (elapsedmsec > 1000) {
|
if (elapsedmsec > 1000) {
|
||||||
double elapsedsec = (end - _start) / 1000000.0;
|
double elapsedsec = (end - _start) / 1000000.0;
|
||||||
qDebug("%s%s took %lf seconds\n", (_alwaysDisplay ? "" : "WARNING!"), _message, elapsedsec);
|
qDebug("%s took %lf seconds %s\n", _message, elapsedsec, (_alwaysDisplay ? "" : "WARNING!") );
|
||||||
} else {
|
} else {
|
||||||
qDebug("%s%s took %lf milliseconds\n", (_alwaysDisplay ? "" : "WARNING!"), _message, elapsedmsec);
|
if (_suppressShortTimings) {
|
||||||
|
if (elapsedmsec > 10) {
|
||||||
|
qDebug("%s took %lf milliseconds %s\n", _message, elapsedmsec,
|
||||||
|
(_alwaysDisplay || (elapsedmsec < 10) ? "" : "WARNING!"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qDebug("%s took %lf milliseconds %s\n", _message, elapsedmsec,
|
||||||
|
(_alwaysDisplay || (elapsedmsec < 10) ? "" : "WARNING!"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (_alwaysDisplay) {
|
} else if (_alwaysDisplay) {
|
||||||
qDebug("%s took %lf milliseconds\n", _message, elapsedmsec);
|
qDebug("%s took %lf milliseconds\n", _message, elapsedmsec);
|
||||||
|
|
|
@ -89,6 +89,7 @@ private:
|
||||||
const char* _message;
|
const char* _message;
|
||||||
bool _renderWarningsOn;
|
bool _renderWarningsOn;
|
||||||
bool _alwaysDisplay;
|
bool _alwaysDisplay;
|
||||||
|
static bool _suppressShortTimings;
|
||||||
public:
|
public:
|
||||||
PerformanceWarning(bool renderWarnings, const char* message, bool alwaysDisplay = false) :
|
PerformanceWarning(bool renderWarnings, const char* message, bool alwaysDisplay = false) :
|
||||||
_start(usecTimestampNow()),
|
_start(usecTimestampNow()),
|
||||||
|
@ -97,6 +98,8 @@ public:
|
||||||
_alwaysDisplay(alwaysDisplay) { }
|
_alwaysDisplay(alwaysDisplay) { }
|
||||||
|
|
||||||
~PerformanceWarning();
|
~PerformanceWarning();
|
||||||
|
|
||||||
|
static void setSuppressShortTimings(bool suppressShortTimings) { _suppressShortTimings = suppressShortTimings; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,10 @@ bool VoxelNodeData::updateCurrentViewFrustum() {
|
||||||
newestViewFrustum.setOrientation(getCameraOrientation());
|
newestViewFrustum.setOrientation(getCameraOrientation());
|
||||||
|
|
||||||
// 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
|
||||||
newestViewFrustum.setFieldOfView(getCameraFov());
|
float originalFOV = getCameraFov();
|
||||||
|
float wideFOV = originalFOV + VIEW_FRUSTUM_FOV_OVERSEND;
|
||||||
|
|
||||||
|
newestViewFrustum.setFieldOfView(wideFOV); // hack
|
||||||
newestViewFrustum.setAspectRatio(getCameraAspectRatio());
|
newestViewFrustum.setAspectRatio(getCameraAspectRatio());
|
||||||
newestViewFrustum.setNearClip(getCameraNearClip());
|
newestViewFrustum.setNearClip(getCameraNearClip());
|
||||||
newestViewFrustum.setFarClip(getCameraFarClip());
|
newestViewFrustum.setFarClip(getCameraFarClip());
|
||||||
|
|
|
@ -52,4 +52,6 @@ const float VIEW_CULLING_RATE_IN_MILLISECONDS = 1000.0f; // once a second is fin
|
||||||
|
|
||||||
const uint64_t CLIENT_TO_SERVER_VOXEL_SEND_INTERVAL_USECS = 1000 * 5; // 1 packet every 50 milliseconds
|
const uint64_t CLIENT_TO_SERVER_VOXEL_SEND_INTERVAL_USECS = 1000 * 5; // 1 packet every 50 milliseconds
|
||||||
|
|
||||||
|
const float VIEW_FRUSTUM_FOV_OVERSEND = 60.0f;
|
||||||
|
|
||||||
#endif
|
#endif
|
Loading…
Reference in a new issue