-
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/html/style.css b/examples/html/style.css
new file mode 100644
index 0000000000..1625fd094f
--- /dev/null
+++ b/examples/html/style.css
@@ -0,0 +1,95 @@
+* {
+}
+
+body {
+ margin: 0;
+ padding: 0;
+
+ background-color: #efefef;
+ font-family: Sans-Serif;
+ font-size: 12px;
+
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+input {
+ line-height: 2;
+}
+
+.input-left {
+ display: inline-block;
+ width: 20px;
+}
+
+.color-box {
+ display: inline-block;
+ width: 20px;
+ height: 20px;
+ border: 1px solid black;
+ margin: 2px;
+ cursor: pointer;
+}
+
+.color-box.highlight {
+ width: 18px;
+ height: 18px;
+ border: 2px solid black;
+}
+
+.section-header {
+ background: #AAA;
+ border-bottom: 1px solid #CCC;
+ background-color: #333333;
+ color: #999;
+ padding: 4px;
+}
+
+.section-header label {
+ font-weight: bold;
+}
+
+.multi-property-section {
+}
+.property-section {
+ display: block;
+ margin: 10 10;
+ height: 30px;
+}
+
+.property-section label {
+ font-weight: bold;
+ vertical-align: middle;
+}
+
+.property-section span {
+ float: right;
+}
+
+.grid-section {
+ border-top: 1px solid #DDD;
+ background-color: #efefef;
+}
+
+input[type=button] {
+ cursor: pointer;
+ background-color: #608e96;
+ border-color: #608e96;
+ border-radius: 5px;
+ padding: 5px 10px;
+ border: 0;
+ color: #fff;
+ font-weight: bold;
+ margin: 0 2px;
+ margin-top: 5px;
+ font-size: .9em;
+}
+
+input.coord {
+ width: 6em;
+ height: 2em;
+}
diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js
index 22f75cb187..6733ccaf39 100644
--- a/examples/libraries/entitySelectionTool.js
+++ b/examples/libraries/entitySelectionTool.js
@@ -23,12 +23,13 @@ SelectionManager = (function() {
that.savedProperties = {};
- that.eventListener = null;
that.selections = [];
// These are selections that don't have a known ID yet
that.pendingSelections = [];
var pendingSelectionTimer = null;
+ var listeners = [];
+
that.localRotation = Quat.fromPitchYawRollDegrees(0, 0, 0);
that.localPosition = { x: 0, y: 0, z: 0 };
that.localDimensions = { x: 0, y: 0, z: 0 };
@@ -46,8 +47,8 @@ SelectionManager = (function() {
}
};
- that.setEventListener = function(func) {
- that.eventListener = func;
+ that.addEventListener = function(func) {
+ listeners.push(func);
};
that.hasSelection = function() {
@@ -187,8 +188,12 @@ SelectionManager = (function() {
SelectionDisplay.setSpaceMode(SPACE_WORLD);
}
- if (that.eventListener) {
- that.eventListener();
+ for (var i = 0; i < listeners.length; i++) {
+ try {
+ listeners[i]();
+ } catch (e) {
+ print("got exception");
+ }
}
};
diff --git a/examples/libraries/gridTool.js b/examples/libraries/gridTool.js
index 34e25d6733..d8b84babf9 100644
--- a/examples/libraries/gridTool.js
+++ b/examples/libraries/gridTool.js
@@ -31,6 +31,7 @@ Grid = function(opts) {
that.getMajorIncrement = function() { return minorGridSpacing * majorGridEvery; };
that.visible = false;
+ that.enabled = false;
that.getOrigin = function() {
return origin;
@@ -38,6 +39,11 @@ Grid = function(opts) {
that.getSnapToGrid = function() { return snapToGrid; };
+ that.setEnabled = function(enabled) {
+ that.enabled = enabled;
+ updateGrid();
+ }
+
that.setVisible = function(visible, noUpdate) {
that.visible = visible;
updateGrid();
@@ -127,7 +133,7 @@ Grid = function(opts) {
function updateGrid() {
Overlays.editOverlay(gridOverlay, {
position: { x: origin.y, y: origin.y, z: -origin.y },
- visible: that.visible,
+ visible: that.visible && that.enabled,
minorGridWidth: minorGridSpacing,
majorGridEvery: majorGridEvery,
color: gridColor,
@@ -159,7 +165,7 @@ GridTool = function(opts) {
var listeners = [];
var url = Script.resolvePath('html/gridControls.html');
- var webView = new WebWindow(url, 200, 280);
+ var webView = new WebWindow('Grid', url, 200, 280);
horizontalGrid.addListener(function(data) {
webView.eventBridge.emitScriptEvent(JSON.stringify(data));
@@ -174,6 +180,15 @@ GridTool = function(opts) {
for (var i = 0; i < listeners.length; i++) {
listeners[i](data);
}
+ } else if (data.type == "action") {
+ var action = data.action;
+ if (action == "moveToAvatar") {
+ grid.setPosition(MyAvatar.position);
+ } else if (action == "moveToSelection") {
+ var newPosition = selectionManager.worldPosition;
+ newPosition = Vec3.subtract(newPosition, { x: 0, y: selectionManager.worldDimensions.y * 0.5, z: 0 });
+ grid.setPosition(newPosition);
+ }
}
});
diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js
index fefc3ca6da..cc3c0fceda 100644
--- a/examples/newEditEntities.js
+++ b/examples/newEditEntities.js
@@ -39,7 +39,7 @@ Script.include("libraries/gridTool.js");
var grid = Grid();
gridTool = GridTool({ horizontalGrid: grid });
-selectionManager.setEventListener(selectionDisplay.updateHandles);
+selectionManager.addEventListener(selectionDisplay.updateHandles);
var windowDimensions = Controller.getViewportDimensions();
var toolIconUrl = HIFI_PUBLIC_BUCKET + "images/tools/";
@@ -55,13 +55,11 @@ var wantEntityGlow = false;
var SPAWN_DISTANCE = 1;
var DEFAULT_DIMENSION = 0.20;
-var MENU_GRID_TOOL_ENABLED = 'Grid Tool';
var MENU_INSPECT_TOOL_ENABLED = "Inspect Tool";
var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus";
var SETTING_INSPECT_TOOL_ENABLED = "inspectToolEnabled";
var SETTING_EASE_ON_FOCUS = "cameraEaseOnFocus";
-var SETTING_GRID_TOOL_ENABLED = 'GridToolEnabled';
var modelURLs = [
HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Alder.fbx",
@@ -272,11 +270,15 @@ var toolBar = (function () {
isActive = !isActive;
if (!isActive) {
gridTool.setVisible(false);
+ grid.setEnabled(false);
+ propertiesTool.setVisible(false);
selectionManager.clearSelections();
cameraManager.disable();
} else {
cameraManager.enable();
- gridTool.setVisible(Menu.isOptionChecked(MENU_GRID_TOOL_ENABLED));
+ gridTool.setVisible(true);
+ grid.setEnabled(true);
+ propertiesTool.setVisible(true);
}
return true;
}
@@ -608,10 +610,6 @@ function setupModelMenus() {
Menu.addMenuItem({ menuName: "File", menuItemName: "Import Models", shortcutKey: "CTRL+META+I", afterItem: "Export Models" });
Menu.addMenuItem({ menuName: "Developer", menuItemName: "Debug Ryans Rotation Problems", isCheckable: true });
- Menu.addMenuItem({ menuName: "View", menuItemName: MENU_GRID_TOOL_ENABLED, afterItem: "Edit Entities Help...", isCheckable: true,
- isChecked: Settings.getValue(SETTING_GRID_TOOL_ENABLED) == 'true'});
- Menu.addMenuItem({ menuName: "View", menuItemName: MENU_INSPECT_TOOL_ENABLED, afterItem: MENU_GRID_TOOL_ENABLED,
- isCheckable: true, isChecked: Settings.getValue(SETTING_INSPECT_TOOL_ENABLED) == "true" });
Menu.addMenuItem({ menuName: "View", menuItemName: MENU_EASE_ON_FOCUS, afterItem: MENU_INSPECT_TOOL_ENABLED,
isCheckable: true, isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" });
}
@@ -636,8 +634,6 @@ function cleanupModelMenus() {
Menu.removeMenuItem("File", "Import Models");
Menu.removeMenuItem("Developer", "Debug Ryans Rotation Problems");
- Settings.setValue(SETTING_GRID_TOOL_ENABLED, Menu.isOptionChecked(MENU_GRID_TOOL_ENABLED));
- Menu.removeMenuItem("View", MENU_GRID_TOOL_ENABLED);
Menu.removeMenuItem("View", MENU_INSPECT_TOOL_ENABLED);
Menu.removeMenuItem("View", MENU_EASE_ON_FOCUS);
}
@@ -749,10 +745,6 @@ function handeMenuEvent(menuItem) {
}
} else if (menuItem == "Import Models") {
modelImporter.doImport();
- } else if (menuItem == MENU_GRID_TOOL_ENABLED) {
- if (isActive) {
- gridTool.setVisible(Menu.isOptionChecked(MENU_GRID_TOOL_ENABLED));
- }
}
tooltip.show(false);
}
@@ -911,3 +903,43 @@ function pushCommandForSelections(createdEntityData, deletedEntityData) {
}
UndoStack.pushCommand(applyEntityProperties, undoData, applyEntityProperties, redoData);
}
+
+PropertiesTool = function(opts) {
+ var that = {};
+
+ var url = Script.resolvePath('html/entityProperties.html');
+ var webView = new WebWindow('Entity Properties', url, 200, 280);
+
+ var visible = false;
+
+ webView.setVisible(visible);
+
+ that.setVisible = function(newVisible) {
+ visible = newVisible;
+ webView.setVisible(visible);
+ };
+
+ selectionManager.addEventListener(function() {
+ data = {
+ type: 'update',
+ };
+ if (selectionManager.hasSelection()) {
+ data.properties = Entities.getEntityProperties(selectionManager.selections[0]);
+ }
+ webView.eventBridge.emitScriptEvent(JSON.stringify(data));
+ });
+
+ webView.eventBridge.webEventReceived.connect(function(data) {
+ print(data);
+ data = JSON.parse(data);
+ if (data.type == "update") {
+ Entities.editEntity(selectionManager.selections[0], data.properties);
+ selectionManager._update();
+ }
+ });
+
+ return that;
+};
+
+propertiesTool = PropertiesTool();
+
diff --git a/examples/overlaysExample.js b/examples/overlaysExample.js
index 3ab70a0562..0d47f7ca64 100644
--- a/examples/overlaysExample.js
+++ b/examples/overlaysExample.js
@@ -194,20 +194,23 @@ print("Cube overlay color =\n"
+ "green: " + cubeColor.green + "\n"
+ "blue: " + cubeColor.blue
);
-var modelOverlayProperties = {
- textures: {
- filename1: "http://url1",
- filename2: "http://url2"
- }
-}
-var modelOverlay = Overlays.addOverlay("model", modelOverlayProperties);
-var textures = Overlays.getProperty(modelOverlay, "textures");
-var textureValues = "";
-for (key in textures) {
- textureValues += "\n" + key + ": " + textures[key];
-}
-print("Model overlay textures =" + textureValues);
-Overlays.deleteOverlay(modelOverlay);
+
+// This model overlay example causes intermittent crashes in NetworkGeometry::setTextureWithNameToURL()
+//var modelOverlayProperties = {
+// textures: {
+// filename1: HIFI_PUBLIC_BUCKET + "images/testing-swatches.svg",
+// filename2: HIFI_PUBLIC_BUCKET + "images/hifi-interface-tools.svg"
+// }
+//}
+//var modelOverlay = Overlays.addOverlay("model", modelOverlayProperties);
+//var textures = Overlays.getProperty(modelOverlay, "textures");
+//var textureValues = "";
+//for (key in textures) {
+// textureValues += "\n" + key + ": " + textures[key];
+//}
+//print("Model overlay textures =" + textureValues);
+//Overlays.deleteOverlay(modelOverlay);
+
print("Unknown overlay property =\n" + Overlays.getProperty(1000, "text")); // value = undefined
// When our script shuts down, we should clean up all of our overlays
diff --git a/interface/resources/meshes/defaultAvatar_body.fst b/interface/resources/meshes/defaultAvatar_body.fst
index 5874c206db..f061a87726 100644
--- a/interface/resources/meshes/defaultAvatar_body.fst
+++ b/interface/resources/meshes/defaultAvatar_body.fst
@@ -1,6 +1,6 @@
filename=defaultAvatar/body.fbx
texdir=defaultAvatar
-scale=130
+scale=8.666
joint = jointRoot = jointRoot
joint = jointLean = jointSpine
joint = jointNeck = jointNeck
diff --git a/interface/resources/meshes/defaultAvatar_head.fst b/interface/resources/meshes/defaultAvatar_head.fst
index 34cf44f0e4..c2478ce7d9 100644
--- a/interface/resources/meshes/defaultAvatar_head.fst
+++ b/interface/resources/meshes/defaultAvatar_head.fst
@@ -2,7 +2,7 @@
name= defaultAvatar_head
filename=defaultAvatar/head.fbx
texdir=defaultAvatar
-scale=80
+scale=5.333
rx=0
ry=0
rz=0
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 605bd62118..f890baff3d 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -124,7 +124,7 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt
QString logMessage = LogHandler::getInstance().printMessage((LogMsgType) type, context, message);
if (!logMessage.isEmpty()) {
- Application::getInstance()->getLogger()->addMessage(qPrintable(logMessage));
+ Application::getInstance()->getLogger()->addMessage(qPrintable(logMessage + "\n"));
}
}
@@ -373,6 +373,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
// enable mouse tracking; otherwise, we only get drag events
_glWidget->setMouseTracking(true);
+ _toolWindow = new ToolWindow();
+ _toolWindow->setWindowFlags(_toolWindow->windowFlags() | Qt::WindowStaysOnTopHint);
+ _toolWindow->setWindowTitle("Tools");
+
// initialization continues in initializeGL when OpenGL context is ready
// Tell our voxel edit sender about our known jurisdictions
@@ -2874,7 +2878,7 @@ QImage Application::renderAvatarBillboard() {
return image;
}
-void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
+void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly, RenderArgs::RenderSide renderSide) {
PROFILE_RANGE(__FUNCTION__);
PerformanceTimer perfTimer("display");
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide()");
@@ -3021,7 +3025,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
PerformanceTimer perfTimer("entities");
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::displaySide() ... entities...");
- _entities.render();
+ _entities.render(RenderArgs::DEFAULT_RENDER_MODE, renderSide);
}
// render JS/scriptable overlays
diff --git a/interface/src/Application.h b/interface/src/Application.h
index cba39317a5..dc1ec96321 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -82,6 +82,7 @@
#include "ui/overlays/Overlays.h"
#include "ui/ApplicationOverlay.h"
#include "ui/RunningScriptsWidget.h"
+#include "ui/ToolWindow.h"
#include "ui/VoxelImportDialog.h"
#include "voxels/VoxelFade.h"
#include "voxels/VoxelHideShowThread.h"
@@ -246,6 +247,8 @@ public:
void lockOctreeSceneStats() { _octreeSceneStatsLock.lockForRead(); }
void unlockOctreeSceneStats() { _octreeSceneStatsLock.unlock(); }
+ ToolWindow* getToolWindow() { return _toolWindow ; }
+
GeometryCache* getGeometryCache() { return &_geometryCache; }
AnimationCache* getAnimationCache() { return &_animationCache; }
TextureCache* getTextureCache() { return &_textureCache; }
@@ -262,7 +265,7 @@ public:
QImage renderAvatarBillboard();
- void displaySide(Camera& whichCamera, bool selfAvatarOnly = false);
+ void displaySide(Camera& whichCamera, bool selfAvatarOnly = false, RenderArgs::RenderSide renderSide = RenderArgs::MONO);
/// Stores the current modelview matrix as the untranslated view matrix to use for transforms and the supplied vector as
/// the view matrix translation.
@@ -459,6 +462,8 @@ private:
MainWindow* _window;
GLCanvas* _glWidget; // our GLCanvas has a couple extra features
+ ToolWindow* _toolWindow;
+
BandwidthMeter _bandwidthMeter;
QThread* _nodeThread;
diff --git a/interface/src/FileLogger.cpp b/interface/src/FileLogger.cpp
index 505cb6a029..4808842036 100644
--- a/interface/src/FileLogger.cpp
+++ b/interface/src/FileLogger.cpp
@@ -41,7 +41,7 @@ void FileLogger::addMessage(QString message) {
QFile file(_fileName);
if (file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
QTextStream out(&file);
- out << message << "\n";
+ out << message;
}
}
diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp
index e0feb4e349..f7aabc8f06 100644
--- a/interface/src/Menu.cpp
+++ b/interface/src/Menu.cpp
@@ -247,6 +247,12 @@ Menu::Menu() :
_chatWindow = new ChatWindow(Application::getInstance()->getWindow());
#endif
+ addActionToQMenuAndActionHash(toolsMenu,
+ MenuOption::ToolWindow,
+ Qt::CTRL | Qt::ALT | Qt::Key_T,
+ this,
+ SLOT(toggleToolWindow()));
+
addActionToQMenuAndActionHash(toolsMenu,
MenuOption::Console,
Qt::CTRL | Qt::ALT | Qt::Key_J,
@@ -1464,6 +1470,11 @@ void Menu::toggleConsole() {
_jsConsole->setVisible(!_jsConsole->isVisible());
}
+void Menu::toggleToolWindow() {
+ QMainWindow* toolWindow = Application::getInstance()->getToolWindow();
+ toolWindow->setVisible(!toolWindow->isVisible());
+}
+
void Menu::audioMuteToggled() {
QAction *muteAction = _actionHash.value(MenuOption::MuteAudio);
if (muteAction) {
diff --git a/interface/src/Menu.h b/interface/src/Menu.h
index b745246780..8590d8580e 100644
--- a/interface/src/Menu.h
+++ b/interface/src/Menu.h
@@ -224,6 +224,7 @@ private slots:
void showScriptEditor();
void showChat();
void toggleConsole();
+ void toggleToolWindow();
void toggleChat();
void audioMuteToggled();
void displayNameLocationResponse(const QString& errorString);
@@ -490,6 +491,7 @@ namespace MenuOption {
const QString StringHair = "String Hair";
const QString SuppressShortTimings = "Suppress Timings Less than 10ms";
const QString TestPing = "Test Ping";
+ const QString ToolWindow = "Tool Window";
const QString TransmitterDrive = "Transmitter Drive";
const QString TurnWithHead = "Turn using Head";
const QString UploadAttachment = "Upload Attachment Model";
diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp
index 4c0acc553a..5d8f77eedc 100644
--- a/interface/src/MetavoxelSystem.cpp
+++ b/interface/src/MetavoxelSystem.cpp
@@ -3164,8 +3164,7 @@ void StaticModelRenderer::applyRotation(const glm::quat& rotation) {
}
void StaticModelRenderer::applyScale(float scale) {
- const float SCALE_MULTIPLIER = 0.0006f;
- _model->setScale(glm::vec3(scale, scale, scale) * SCALE_MULTIPLIER);
+ _model->setScale(glm::vec3(scale, scale, scale));
}
void StaticModelRenderer::applyURL(const QUrl& url) {
diff --git a/interface/src/ModelUploader.cpp b/interface/src/ModelUploader.cpp
index b117197f48..2599f39e83 100644
--- a/interface/src/ModelUploader.cpp
+++ b/interface/src/ModelUploader.cpp
@@ -157,7 +157,7 @@ bool ModelUploader::zip() {
// mixamo/autodesk defaults
if (!mapping.contains(SCALE_FIELD)) {
- mapping.insert(SCALE_FIELD, 15.0);
+ mapping.insert(SCALE_FIELD, 1.0);
}
QVariantHash joints = mapping.value(JOINT_FIELD).toHash();
if (!joints.contains("jointEyeLeft")) {
diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp
index 70f59f0661..5a30e8634d 100644
--- a/interface/src/avatar/FaceModel.cpp
+++ b/interface/src/avatar/FaceModel.cpp
@@ -34,8 +34,7 @@ void FaceModel::simulate(float deltaTime, bool fullUpdate) {
neckParentRotation = owningAvatar->getOrientation();
}
setRotation(neckParentRotation);
- const float MODEL_SCALE = 0.0006f;
- setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningHead->getScale() * MODEL_SCALE);
+ setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningHead->getScale());
setPupilDilation(_owningHead->getPupilDilation());
setBlendshapeCoefficients(_owningHead->getBlendshapeCoefficients());
diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp
index e760813fe5..7ca105f483 100644
--- a/interface/src/avatar/SkeletonModel.cpp
+++ b/interface/src/avatar/SkeletonModel.cpp
@@ -36,8 +36,6 @@ SkeletonModel::~SkeletonModel() {
_ragdoll = NULL;
}
-const float MODEL_SCALE = 0.0006f;
-
void SkeletonModel::setJointStates(QVector
states) {
Model::setJointStates(states);
@@ -57,7 +55,7 @@ void SkeletonModel::setJointStates(QVector states) {
_defaultEyeModelPosition.z = -_defaultEyeModelPosition.z;
// Skeleton may have already been scaled so unscale it
- _defaultEyeModelPosition = MODEL_SCALE * _defaultEyeModelPosition / _scale;
+ _defaultEyeModelPosition = _defaultEyeModelPosition / _scale;
}
// the SkeletonModel override of updateJointState() will clear the translation part
@@ -80,7 +78,7 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
setTranslation(_owningAvatar->getSkeletonPosition());
static const glm::quat refOrientation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
setRotation(_owningAvatar->getOrientation() * refOrientation);
- setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getScale() * MODEL_SCALE);
+ setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getScale());
setBlendshapeCoefficients(_owningAvatar->getHead()->getBlendshapeCoefficients());
Model::simulate(deltaTime, fullUpdate);
diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp
index 872f4ce7e6..d7d7353b24 100644
--- a/interface/src/devices/TV3DManager.cpp
+++ b/interface/src/devices/TV3DManager.cpp
@@ -126,7 +126,7 @@ void TV3DManager::display(Camera& whichCamera) {
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
- Application::getInstance()->displaySide(whichCamera);
+ Application::getInstance()->displaySide(whichCamera, false, RenderArgs::STEREO_LEFT);
if (displayOverlays) {
applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov);
@@ -156,7 +156,7 @@ void TV3DManager::display(Camera& whichCamera) {
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
- Application::getInstance()->displaySide(whichCamera);
+ Application::getInstance()->displaySide(whichCamera, false, RenderArgs::STEREO_RIGHT);
if (displayOverlays) {
applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov);
diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp
index 6357dfc71d..89bba43620 100644
--- a/interface/src/entities/EntityTreeRenderer.cpp
+++ b/interface/src/entities/EntityTreeRenderer.cpp
@@ -254,15 +254,15 @@ void EntityTreeRenderer::checkEnterLeaveEntities() {
}
}
-void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode) {
+void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::RenderSide renderSide) {
bool dontRenderAsScene = !Menu::getInstance()->isOptionChecked(MenuOption::RenderEntitiesAsScene);
if (dontRenderAsScene) {
- OctreeRenderer::render(renderMode);
+ OctreeRenderer::render(renderMode, renderSide);
} else {
if (_tree) {
- Model::startScene();
- RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode,
+ Model::startScene(renderSide);
+ RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, renderSide,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
_tree->lockForRead();
_tree->recurseTreeWithOperation(renderOperation, &args);
diff --git a/interface/src/entities/EntityTreeRenderer.h b/interface/src/entities/EntityTreeRenderer.h
index 7c1c81b6c9..66107b368a 100644
--- a/interface/src/entities/EntityTreeRenderer.h
+++ b/interface/src/entities/EntityTreeRenderer.h
@@ -56,7 +56,7 @@ public:
void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
virtual void init();
- virtual void render(RenderArgs::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE);
+ virtual void render(RenderArgs::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE, RenderArgs::RenderSide renderSide = RenderArgs::MONO);
virtual const FBXGeometry* getGeometryForEntity(const EntityItem* entityItem);
virtual const Model* getModelForEntityItem(const EntityItem* entityItem);
diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp
index c007f44f2e..fc3845d94f 100644
--- a/interface/src/renderer/Model.cpp
+++ b/interface/src/renderer/Model.cpp
@@ -537,7 +537,7 @@ void Model::renderSetup(RenderArgs* args) {
}
}
- if (!_meshGroupsKnown) {
+ if (!_meshGroupsKnown && isLoadedWithTextures()) {
segregateMeshGroups();
}
}
@@ -628,7 +628,7 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) {
opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, args);
opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args);
opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, args);
- opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args);
+ opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, true, args);
// render translucent meshes afterwards
//Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(false, true, true);
@@ -649,7 +649,7 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) {
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, false, args);
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args);
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, false, args);
- translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args);
+ translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, true, args);
GLBATCH(glDisable)(GL_ALPHA_TEST);
GLBATCH(glEnable)(GL_BLEND);
@@ -673,7 +673,7 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) {
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, false, args);
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args);
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, false, args);
- translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args);
+ translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, true, args);
}
GLBATCH(glDepthMask)(true);
@@ -1484,8 +1484,10 @@ void Model::deleteGeometry() {
// Scene rendering support
QVector Model::_modelsInScene;
gpu::Batch Model::_sceneRenderBatch;
-void Model::startScene() {
- _modelsInScene.clear();
+void Model::startScene(RenderArgs::RenderSide renderSide) {
+ if (renderSide != RenderArgs::STEREO_RIGHT) {
+ _modelsInScene.clear();
+ }
}
void Model::setupBatchTransform(gpu::Batch& batch) {
@@ -1503,146 +1505,155 @@ void Model::setupBatchTransform(gpu::Batch& batch) {
void Model::endScene(RenderMode mode, RenderArgs* args) {
PROFILE_RANGE(__FUNCTION__);
- // Let's introduce a gpu::Batch to capture all the calls to the graphics api
- _sceneRenderBatch.clear();
- gpu::Batch& batch = _sceneRenderBatch;
+ RenderArgs::RenderSide renderSide = RenderArgs::MONO;
+ if (args) {
+ renderSide = args->_renderSide;
+ }
- GLBATCH(glDisable)(GL_COLOR_MATERIAL);
+ // Do the rendering batch creation for mono or left eye, not for right eye
+ if (renderSide != RenderArgs::STEREO_RIGHT) {
+ // Let's introduce a gpu::Batch to capture all the calls to the graphics api
+ _sceneRenderBatch.clear();
+ gpu::Batch& batch = _sceneRenderBatch;
+
+ GLBATCH(glDisable)(GL_COLOR_MATERIAL);
+
+ if (mode == DIFFUSE_RENDER_MODE || mode == NORMAL_RENDER_MODE) {
+ GLBATCH(glDisable)(GL_CULL_FACE);
+ } else {
+ GLBATCH(glEnable)(GL_CULL_FACE);
+ if (mode == SHADOW_RENDER_MODE) {
+ GLBATCH(glCullFace)(GL_FRONT);
+ }
+ }
+
+ // render opaque meshes with alpha testing
+
+ GLBATCH(glDisable)(GL_BLEND);
+ GLBATCH(glEnable)(GL_ALPHA_TEST);
- if (mode == DIFFUSE_RENDER_MODE || mode == NORMAL_RENDER_MODE) {
- GLBATCH(glDisable)(GL_CULL_FACE);
- } else {
- GLBATCH(glEnable)(GL_CULL_FACE);
if (mode == SHADOW_RENDER_MODE) {
- GLBATCH(glCullFace)(GL_FRONT);
+ GLBATCH(glAlphaFunc)(GL_EQUAL, 0.0f);
}
- }
-
- // render opaque meshes with alpha testing
-
- GLBATCH(glDisable)(GL_BLEND);
- GLBATCH(glEnable)(GL_ALPHA_TEST);
-
- if (mode == SHADOW_RENDER_MODE) {
- GLBATCH(glAlphaFunc)(GL_EQUAL, 0.0f);
- }
- /*Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(
- mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE,
- mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE,
- mode == DEFAULT_RENDER_MODE);
- */
- {
- GLenum buffers[3];
- int bufferCount = 0;
- if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) {
- buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
+ /*Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(
+ mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE,
+ mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE,
+ mode == DEFAULT_RENDER_MODE);
+ */
+ {
+ GLenum buffers[3];
+ int bufferCount = 0;
+ if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) {
+ buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
+ }
+ if (mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE) {
+ buffers[bufferCount++] = GL_COLOR_ATTACHMENT1;
+ }
+ if (mode == DEFAULT_RENDER_MODE) {
+ buffers[bufferCount++] = GL_COLOR_ATTACHMENT2;
+ }
+ GLBATCH(glDrawBuffers)(bufferCount, buffers);
}
- if (mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE) {
+
+ const float DEFAULT_ALPHA_THRESHOLD = 0.5f;
+
+ int opaqueMeshPartsRendered = 0;
+
+ // now, for each model in the scene, render the mesh portions
+ opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, args);
+ opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, args);
+ opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, args);
+ opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, args);
+ opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, args);
+ opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args);
+ opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, args);
+ opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, true, args);
+
+ // render translucent meshes afterwards
+ //Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(false, true, true);
+ {
+ GLenum buffers[2];
+ int bufferCount = 0;
buffers[bufferCount++] = GL_COLOR_ATTACHMENT1;
- }
- if (mode == DEFAULT_RENDER_MODE) {
buffers[bufferCount++] = GL_COLOR_ATTACHMENT2;
+ GLBATCH(glDrawBuffers)(bufferCount, buffers);
}
- GLBATCH(glDrawBuffers)(bufferCount, buffers);
+
+ int translucentParts = 0;
+ const float MOSTLY_OPAQUE_THRESHOLD = 0.75f;
+ translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, args);
+ translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, args);
+ translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, args);
+ translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, args);
+ translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, false, args);
+ translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args);
+ translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, false, args);
+ translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, true, args);
+
+ GLBATCH(glDisable)(GL_ALPHA_TEST);
+ GLBATCH(glEnable)(GL_BLEND);
+ GLBATCH(glDepthMask)(false);
+ GLBATCH(glDepthFunc)(GL_LEQUAL);
+
+ //Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true);
+ {
+ GLenum buffers[1];
+ int bufferCount = 0;
+ buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
+ GLBATCH(glDrawBuffers)(bufferCount, buffers);
+ }
+
+ if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) {
+ const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f;
+ translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, args);
+ translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, args);
+ translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, args);
+ translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, args);
+ translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, false, args);
+ translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args);
+ translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, false, args);
+ translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, true, args);
+ }
+
+ GLBATCH(glDepthMask)(true);
+ GLBATCH(glDepthFunc)(GL_LESS);
+ GLBATCH(glDisable)(GL_CULL_FACE);
+
+ if (mode == SHADOW_RENDER_MODE) {
+ GLBATCH(glCullFace)(GL_BACK);
+ }
+
+ // deactivate vertex arrays after drawing
+ GLBATCH(glDisableClientState)(GL_NORMAL_ARRAY);
+ GLBATCH(glDisableClientState)(GL_VERTEX_ARRAY);
+ GLBATCH(glDisableClientState)(GL_TEXTURE_COORD_ARRAY);
+ GLBATCH(glDisableClientState)(GL_COLOR_ARRAY);
+ GLBATCH(glDisableVertexAttribArray)(gpu::Stream::TANGENT);
+ GLBATCH(glDisableVertexAttribArray)(gpu::Stream::SKIN_CLUSTER_INDEX);
+ GLBATCH(glDisableVertexAttribArray)(gpu::Stream::SKIN_CLUSTER_WEIGHT);
+
+ // bind with 0 to switch back to normal operation
+ GLBATCH(glBindBuffer)(GL_ARRAY_BUFFER, 0);
+ GLBATCH(glBindBuffer)(GL_ELEMENT_ARRAY_BUFFER, 0);
+ GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0);
+ if (args) {
+ args->_translucentMeshPartsRendered = translucentParts;
+ args->_opaqueMeshPartsRendered = opaqueMeshPartsRendered;
}
- const float DEFAULT_ALPHA_THRESHOLD = 0.5f;
-
- int opaqueMeshPartsRendered = 0;
-
- // now, for each model in the scene, render the mesh portions
- opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, args);
- opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, args);
- opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, args);
- opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, args);
- opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, args);
- opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args);
- opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, args);
- opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, true, args);
-
- // render translucent meshes afterwards
- //Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(false, true, true);
- {
- GLenum buffers[2];
- int bufferCount = 0;
- buffers[bufferCount++] = GL_COLOR_ATTACHMENT1;
- buffers[bufferCount++] = GL_COLOR_ATTACHMENT2;
- GLBATCH(glDrawBuffers)(bufferCount, buffers);
}
- int translucentParts = 0;
- const float MOSTLY_OPAQUE_THRESHOLD = 0.75f;
- translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, args);
- translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, args);
- translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, args);
- translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, args);
- translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, false, args);
- translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args);
- translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, false, args);
- translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, true, args);
-
- GLBATCH(glDisable)(GL_ALPHA_TEST);
- GLBATCH(glEnable)(GL_BLEND);
- GLBATCH(glDepthMask)(false);
- GLBATCH(glDepthFunc)(GL_LEQUAL);
-
- //Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true);
- {
- GLenum buffers[1];
- int bufferCount = 0;
- buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
- GLBATCH(glDrawBuffers)(bufferCount, buffers);
- }
-
- if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) {
- const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f;
- translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, args);
- translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, args);
- translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, args);
- translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, args);
- translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, false, args);
- translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args);
- translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, false, args);
- translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, true, args);
- }
-
- GLBATCH(glDepthMask)(true);
- GLBATCH(glDepthFunc)(GL_LESS);
- GLBATCH(glDisable)(GL_CULL_FACE);
-
- if (mode == SHADOW_RENDER_MODE) {
- GLBATCH(glCullFace)(GL_BACK);
- }
-
- // deactivate vertex arrays after drawing
- GLBATCH(glDisableClientState)(GL_NORMAL_ARRAY);
- GLBATCH(glDisableClientState)(GL_VERTEX_ARRAY);
- GLBATCH(glDisableClientState)(GL_TEXTURE_COORD_ARRAY);
- GLBATCH(glDisableClientState)(GL_COLOR_ARRAY);
- GLBATCH(glDisableVertexAttribArray)(gpu::Stream::TANGENT);
- GLBATCH(glDisableVertexAttribArray)(gpu::Stream::SKIN_CLUSTER_INDEX);
- GLBATCH(glDisableVertexAttribArray)(gpu::Stream::SKIN_CLUSTER_WEIGHT);
-
- // bind with 0 to switch back to normal operation
- GLBATCH(glBindBuffer)(GL_ARRAY_BUFFER, 0);
- GLBATCH(glBindBuffer)(GL_ELEMENT_ARRAY_BUFFER, 0);
- GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0);
-
// Render!
{
PROFILE_RANGE("render Batch");
- ::gpu::GLBackend::renderBatch(batch);
+ ::gpu::GLBackend::renderBatch(_sceneRenderBatch);
}
// restore all the default material settings
Application::getInstance()->setupWorldLight();
- if (args) {
- args->_translucentMeshPartsRendered = translucentParts;
- args->_opaqueMeshPartsRendered = opaqueMeshPartsRendered;
- }
}
bool Model::renderInScene(float alpha, RenderArgs* args) {
diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h
index 32c072dc99..4dceb07655 100644
--- a/interface/src/renderer/Model.h
+++ b/interface/src/renderer/Model.h
@@ -31,7 +31,7 @@
class QScriptEngine;
class Shape;
-class RenderArgs;
+#include "RenderArgs.h"
class ViewFrustum;
@@ -91,7 +91,7 @@ public:
bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_RENDER_MODE, RenderArgs* args = NULL);
// Scene rendering support
- static void startScene();
+ static void startScene(RenderArgs::RenderSide renderSide);
bool renderInScene(float alpha = 1.0f, RenderArgs* args = NULL);
static void endScene(RenderMode mode = DEFAULT_RENDER_MODE, RenderArgs* args = NULL);
diff --git a/interface/src/scripting/WebWindowClass.cpp b/interface/src/scripting/WebWindowClass.cpp
index d280d8eecf..cc6f4fbfff 100644
--- a/interface/src/scripting/WebWindowClass.cpp
+++ b/interface/src/scripting/WebWindowClass.cpp
@@ -11,9 +11,13 @@
#include
#include
+#include
+#include
#include
#include
+#include
+#include "Application.h"
#include "WindowScriptingInterface.h"
#include "WebWindowClass.h"
@@ -28,29 +32,34 @@ void ScriptEventBridge::emitScriptEvent(const QString& data) {
emit scriptEventReceived(data);
}
-WebWindowClass::WebWindowClass(const QString& url, int width, int height)
+
+WebWindowClass::WebWindowClass(const QString& title, const QString& url, int width, int height)
: QObject(NULL),
- _window(new QWidget(NULL, Qt::Tool)),
_eventBridge(new ScriptEventBridge(this)) {
- QWebView* webView = new QWebView(_window);
+ ToolWindow* toolWindow = Application::getInstance()->getToolWindow();
+
+ _dockWidget = new QDockWidget(title, toolWindow);
+ _dockWidget->setFeatures(QDockWidget::DockWidgetMovable);
+ QWebView* webView = new QWebView(_dockWidget);
webView->page()->mainFrame()->addToJavaScriptWindowObject("EventBridge", _eventBridge);
webView->setUrl(url);
- QVBoxLayout* layout = new QVBoxLayout(_window);
- _window->setLayout(layout);
- layout->addWidget(webView);
- layout->setSpacing(0);
- layout->setContentsMargins(0, 0, 0, 0);
- _window->setGeometry(0, 0, width, height);
+ _dockWidget->setWidget(webView);
- connect(this, &WebWindowClass::destroyed, _window, &QWidget::deleteLater);
+ toolWindow->addDockWidget(Qt::RightDockWidgetArea, _dockWidget);
+
+ connect(this, &WebWindowClass::destroyed, _dockWidget, &QWidget::deleteLater);
}
WebWindowClass::~WebWindowClass() {
}
void WebWindowClass::setVisible(bool visible) {
- QMetaObject::invokeMethod(_window, "setVisible", Qt::BlockingQueuedConnection, Q_ARG(bool, visible));
+ if (visible) {
+ QMetaObject::invokeMethod(
+ Application::getInstance()->getToolWindow(), "setVisible", Qt::BlockingQueuedConnection, Q_ARG(bool, visible));
+ }
+ QMetaObject::invokeMethod(_dockWidget, "setVisible", Qt::BlockingQueuedConnection, Q_ARG(bool, visible));
}
QScriptValue WebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) {
@@ -59,8 +68,9 @@ QScriptValue WebWindowClass::constructor(QScriptContext* context, QScriptEngine*
QMetaObject::invokeMethod(WindowScriptingInterface::getInstance(), "doCreateWebWindow", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(WebWindowClass*, retVal),
Q_ARG(const QString&, file),
- Q_ARG(int, context->argument(1).toInteger()),
- Q_ARG(int, context->argument(2).toInteger()));
+ Q_ARG(QString, context->argument(1).toString()),
+ Q_ARG(int, context->argument(2).toInteger()),
+ Q_ARG(int, context->argument(3).toInteger()));
connect(engine, &QScriptEngine::destroyed, retVal, &WebWindowClass::deleteLater);
diff --git a/interface/src/scripting/WebWindowClass.h b/interface/src/scripting/WebWindowClass.h
index 7b77299774..ae0d14ae06 100644
--- a/interface/src/scripting/WebWindowClass.h
+++ b/interface/src/scripting/WebWindowClass.h
@@ -34,7 +34,7 @@ class WebWindowClass : public QObject {
Q_OBJECT
Q_PROPERTY(QObject* eventBridge READ getEventBridge)
public:
- WebWindowClass(const QString& url, int width, int height);
+ WebWindowClass(const QString& title, const QString& url, int width, int height);
~WebWindowClass();
static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine);
@@ -44,7 +44,7 @@ public slots:
ScriptEventBridge* getEventBridge() const { return _eventBridge; }
private:
- QWidget* _window;
+ QDockWidget* _dockWidget;
ScriptEventBridge* _eventBridge;
};
diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp
index 8c2066f253..8a79cad6e1 100644
--- a/interface/src/scripting/WindowScriptingInterface.cpp
+++ b/interface/src/scripting/WindowScriptingInterface.cpp
@@ -34,8 +34,8 @@ WindowScriptingInterface::WindowScriptingInterface() :
{
}
-WebWindowClass* WindowScriptingInterface::doCreateWebWindow(const QString& url, int width, int height) {
- return new WebWindowClass(url, width, height);
+WebWindowClass* WindowScriptingInterface::doCreateWebWindow(const QString& title, const QString& url, int width, int height) {
+ return new WebWindowClass(title, url, width, height);
}
QScriptValue WindowScriptingInterface::hasFocus() {
diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h
index 5529d31efd..0b320f23a1 100644
--- a/interface/src/scripting/WindowScriptingInterface.h
+++ b/interface/src/scripting/WindowScriptingInterface.h
@@ -78,7 +78,7 @@ private slots:
void nonBlockingFormAccepted() { _nonBlockingFormActive = false; _formResult = QDialog::Accepted; emit nonBlockingFormClosed(); }
void nonBlockingFormRejected() { _nonBlockingFormActive = false; _formResult = QDialog::Rejected; emit nonBlockingFormClosed(); }
- WebWindowClass* doCreateWebWindow(const QString& url, int width, int height);
+ WebWindowClass* doCreateWebWindow(const QString& title, const QString& url, int width, int height);
private:
WindowScriptingInterface();
diff --git a/interface/src/ui/ToolWindow.cpp b/interface/src/ui/ToolWindow.cpp
new file mode 100644
index 0000000000..1375ff1ea5
--- /dev/null
+++ b/interface/src/ui/ToolWindow.cpp
@@ -0,0 +1,82 @@
+//
+// ToolWindow.cpp
+// interface/src/ui
+//
+// Created by Ryan Huffman on 11/13/14.
+// Copyright 2014 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "Application.h"
+#include "ToolWindow.h"
+#include "UIUtil.h"
+
+const int DEFAULT_WIDTH = 300;
+
+ToolWindow::ToolWindow(QWidget* parent) :
+ QMainWindow(parent),
+ _hasShown(false),
+ _lastGeometry() {
+}
+
+bool ToolWindow::event(QEvent* event) {
+ QEvent::Type type = event->type();
+ if (type == QEvent::Show) {
+ if (!_hasShown) {
+ _hasShown = true;
+
+ QMainWindow* mainWindow = Application::getInstance()->getWindow();
+ QRect mainGeometry = mainWindow->geometry();
+
+ int titleBarHeight = UIUtil::getWindowTitleBarHeight(this);
+ int menuBarHeight = Menu::getInstance()->geometry().height();
+ int topMargin = titleBarHeight + menuBarHeight;
+
+ _lastGeometry = QRect(mainGeometry.topLeft().x(), mainGeometry.topLeft().y() + topMargin,
+ DEFAULT_WIDTH, mainGeometry.height() - topMargin);
+ }
+ setGeometry(_lastGeometry);
+ return true;
+ } else if (type == QEvent::Hide) {
+ _lastGeometry = geometry();
+ return true;
+ }
+
+ return QMainWindow::event(event);
+}
+
+void ToolWindow::onChildVisibilityUpdated(bool visible) {
+ if (visible) {
+ setVisible(true);
+ } else {
+ bool hasVisible = false;
+ QList dockWidgets = findChildren();
+ for (int i = 0; i < dockWidgets.count(); i++) {
+ if (dockWidgets[i]->isVisible()) {
+ hasVisible = true;
+ break;
+ }
+ }
+ setVisible(hasVisible);
+ }
+}
+
+void ToolWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget* dockWidget) {
+ QMainWindow::addDockWidget(area, dockWidget);
+
+ connect(dockWidget, &QDockWidget::visibilityChanged, this, &ToolWindow::onChildVisibilityUpdated);
+}
+
+void ToolWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget* dockWidget, Qt::Orientation orientation) {
+ QMainWindow::addDockWidget(area, dockWidget, orientation);
+
+ connect(dockWidget, &QDockWidget::visibilityChanged, this, &ToolWindow::onChildVisibilityUpdated);
+}
+
+void ToolWindow::removeDockWidget(QDockWidget* dockWidget) {
+ QMainWindow::removeDockWidget(dockWidget);
+
+ disconnect(dockWidget, &QDockWidget::visibilityChanged, this, &ToolWindow::onChildVisibilityUpdated);
+}
diff --git a/interface/src/ui/ToolWindow.h b/interface/src/ui/ToolWindow.h
new file mode 100644
index 0000000000..87b94d46df
--- /dev/null
+++ b/interface/src/ui/ToolWindow.h
@@ -0,0 +1,40 @@
+//
+// ToolWindow.h
+// interface/src/ui
+//
+// Created by Ryan Huffman on 11/13/14.
+// Copyright 2014 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#ifndef hifi_ToolWindow_h
+#define hifi_ToolWindow_h
+
+#include
+#include
+#include
+#include
+#include
+
+class ToolWindow : public QMainWindow {
+ Q_OBJECT
+public:
+ ToolWindow(QWidget* parent = NULL);
+
+ virtual bool event(QEvent* event);
+ virtual void addDockWidget(Qt::DockWidgetArea area, QDockWidget* dockWidget);
+ virtual void addDockWidget(Qt::DockWidgetArea area, QDockWidget* dockWidget, Qt::Orientation orientation);
+ virtual void removeDockWidget(QDockWidget* dockWidget);
+
+public slots:
+ void onChildVisibilityUpdated(bool visible);
+
+
+private:
+ bool _hasShown;
+ QRect _lastGeometry;
+};
+
+#endif // hifi_ToolWindow_h
diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp
index 7bdddd6b42..71980ba92c 100644
--- a/interface/src/ui/overlays/Overlays.cpp
+++ b/interface/src/ui/overlays/Overlays.cpp
@@ -86,14 +86,14 @@ void Overlays::render2D() {
RenderArgs args = { NULL, Application::getInstance()->getViewFrustum(),
Menu::getInstance()->getVoxelSizeScale(), Menu::getInstance()->getBoundaryLevelAdjust(),
- RenderArgs::DEFAULT_RENDER_MODE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ RenderArgs::DEFAULT_RENDER_MODE, RenderArgs::MONO, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
foreach(Overlay* thisOverlay, _overlays2D) {
thisOverlay->render(&args);
}
}
-void Overlays::render3D(RenderArgs::RenderMode renderMode) {
+void Overlays::render3D(RenderArgs::RenderMode renderMode, RenderArgs::RenderSide renderSide) {
QReadLocker lock(&_lock);
if (_overlays3D.size() == 0) {
return;
@@ -108,7 +108,7 @@ void Overlays::render3D(RenderArgs::RenderMode renderMode) {
RenderArgs args = { NULL, Application::getInstance()->getViewFrustum(),
Menu::getInstance()->getVoxelSizeScale(), Menu::getInstance()->getBoundaryLevelAdjust(),
- renderMode, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ renderMode, renderSide, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
foreach(Overlay* thisOverlay, _overlays3D) {
diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h
index 5a66eb8ff5..d49ffcc3d0 100644
--- a/interface/src/ui/overlays/Overlays.h
+++ b/interface/src/ui/overlays/Overlays.h
@@ -51,7 +51,7 @@ public:
~Overlays();
void init(QGLWidget* parent);
void update(float deltatime);
- void render3D(RenderArgs::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE);
+ void render3D(RenderArgs::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE, RenderArgs::RenderSide renderSide = RenderArgs::MONO);
void render2D();
public slots:
diff --git a/interface/src/ui/overlays/Planar3DOverlay.cpp b/interface/src/ui/overlays/Planar3DOverlay.cpp
index b2de7bdaad..ffd7d73531 100644
--- a/interface/src/ui/overlays/Planar3DOverlay.cpp
+++ b/interface/src/ui/overlays/Planar3DOverlay.cpp
@@ -82,7 +82,7 @@ QScriptValue Planar3DOverlay::getProperty(const QString& property) {
return vec2toScriptValue(_scriptEngine, _dimensions);
}
- Base3DOverlay::getProperty(property);
+ return Base3DOverlay::getProperty(property);
}
bool Planar3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h
index 6b882a1389..c8e5e61d49 100644
--- a/libraries/avatars/src/AvatarData.h
+++ b/libraries/avatars/src/AvatarData.h
@@ -91,8 +91,8 @@ const float MAX_AUDIO_LOUDNESS = 1000.0; // close enough for mouth animation
const int AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS = 1000;
const int AVATAR_BILLBOARD_PACKET_SEND_INTERVAL_MSECS = 5000;
-const QUrl DEFAULT_HEAD_MODEL_URL = QUrl("http://public.highfidelity.io/meshes/defaultAvatar_head.fst");
-const QUrl DEFAULT_BODY_MODEL_URL = QUrl("http://public.highfidelity.io/meshes/defaultAvatar_body.fst");
+const QUrl DEFAULT_HEAD_MODEL_URL = QUrl("http://public.highfidelity.io/models/heads/defaultAvatar_head.fst");
+const QUrl DEFAULT_BODY_MODEL_URL = QUrl("http://public.highfidelity.io/models/skeletons/defaultAvatar_body.fst");
enum KeyState {
NO_KEY_DOWN = 0,
diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp
index 52b8f7e643..f50fe7866b 100644
--- a/libraries/entities/src/ModelEntityItem.cpp
+++ b/libraries/entities/src/ModelEntityItem.cpp
@@ -115,7 +115,9 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, animationIsPlaying);
if (propertyFlags.getHasProperty(PROP_ANIMATION_PLAYING)) {
- setAnimationIsPlaying(animationIsPlaying);
+ if (animationIsPlaying != getAnimationIsPlaying()) {
+ setAnimationIsPlaying(animationIsPlaying);
+ }
}
if (propertyFlags.getHasProperty(PROP_ANIMATION_FPS)) {
setAnimationFPS(animationFPS);
@@ -345,7 +347,6 @@ QVector ModelEntityItem::getAnimationFrame() {
if (frameCount > 0) {
int animationFrameIndex = (int)(glm::floor(getAnimationFrameIndex())) % frameCount;
-
if (animationFrameIndex < 0 || animationFrameIndex > frameCount) {
animationFrameIndex = 0;
}
@@ -427,7 +428,9 @@ void ModelEntityItem::setAnimationSettings(const QString& value) {
if (settingsMap.contains("running")) {
bool running = settingsMap["running"].toBool();
- setAnimationIsPlaying(running);
+ if (running != getAnimationIsPlaying()) {
+ setAnimationIsPlaying(running);
+ }
}
if (settingsMap.contains("firstFrame")) {
diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp
index 7ba5e7bc24..4ffd3f6286 100644
--- a/libraries/fbx/src/FBXReader.cpp
+++ b/libraries/fbx/src/FBXReader.cpp
@@ -1456,7 +1456,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
}
// get offset transform from mapping
- float offsetScale = mapping.value("scale", 1.0f).toFloat() * unitScaleFactor;
+ float offsetScale = mapping.value("scale", 1.0f).toFloat() * unitScaleFactor * METERS_PER_CENTIMETER;
glm::quat offsetRotation = glm::quat(glm::radians(glm::vec3(mapping.value("rx").toFloat(),
mapping.value("ry").toFloat(), mapping.value("rz").toFloat())));
geometry.offset = glm::translate(glm::vec3(mapping.value("tx").toFloat(), mapping.value("ty").toFloat(),
diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp
index 4450689949..e9cf1158fa 100644
--- a/libraries/octree/src/Octree.cpp
+++ b/libraries/octree/src/Octree.cpp
@@ -74,7 +74,7 @@ void Octree::recurseElementWithOperation(OctreeElement* element, RecurseOctreeOp
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(
- "Octree::recurseElementWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!");
+ "Octree::recurseElementWithOperation\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!");
qDebug() << "Octree::recurseElementWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!";
return;
@@ -96,7 +96,7 @@ void Octree::recurseElementWithPostOperation(OctreeElement* element, RecurseOctr
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(
- "Octree::recurseElementWithPostOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!");
+ "Octree::recurseElementWithPostOperation\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!");
qDebug() << "Octree::recurseElementWithPostOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!";
return;
@@ -126,7 +126,7 @@ void Octree::recurseElementWithOperationDistanceSorted(OctreeElement* element, R
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(
- "Octree::recurseElementWithOperationDistanceSorted() reached DANGEROUSLY_DEEP_RECURSION, bailing!");
+ "Octree::recurseElementWithOperationDistanceSorted\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!");
qDebug() << "Octree::recurseElementWithOperationDistanceSorted() reached DANGEROUSLY_DEEP_RECURSION, bailing!";
return;
@@ -167,7 +167,7 @@ bool Octree::recurseElementWithOperator(OctreeElement* element, RecurseOctreeOpe
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(
- "Octree::recurseElementWithOperator() reached DANGEROUSLY_DEEP_RECURSION, bailing!");
+ "Octree::recurseElementWithOperator\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!");
qDebug() << "Octree::recurseElementWithOperator() reached DANGEROUSLY_DEEP_RECURSION, bailing!";
return false;
@@ -231,8 +231,18 @@ OctreeElement* Octree::nodeForOctalCode(OctreeElement* ancestorElement,
}
// returns the element created!
-OctreeElement* Octree::createMissingElement(OctreeElement* lastParentElement, const unsigned char* codeToReach) {
+OctreeElement* Octree::createMissingElement(OctreeElement* lastParentElement, const unsigned char* codeToReach, int recursionCount) {
+
+ if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
+ static QString repeatedMessage
+ = LogHandler::getInstance().addRepeatedMessageRegex(
+ "Octree::createMissingElement\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!");
+
+ qDebug() << "Octree::createMissingElement() reached DANGEROUSLY_DEEP_RECURSION, bailing!";
+ return lastParentElement;
+ }
int indexOfNewChild = branchIndexWithDescendant(lastParentElement->getOctalCode(), codeToReach);
+
// If this parent element is a leaf, then you know the child path doesn't exist, so deal with
// breaking up the leaf first, which will also create a child path
if (lastParentElement->requiresSplit()) {
@@ -246,7 +256,7 @@ OctreeElement* Octree::createMissingElement(OctreeElement* lastParentElement, co
if (*lastParentElement->getChildAtIndex(indexOfNewChild)->getOctalCode() == *codeToReach) {
return lastParentElement->getChildAtIndex(indexOfNewChild);
} else {
- return createMissingElement(lastParentElement->getChildAtIndex(indexOfNewChild), codeToReach);
+ return createMissingElement(lastParentElement->getChildAtIndex(indexOfNewChild), codeToReach, recursionCount + 1);
}
}
@@ -255,25 +265,20 @@ int Octree::readElementData(OctreeElement* destinationElement, const unsigned ch
int bytesLeftToRead = bytesAvailable;
int bytesRead = 0;
- bool wantDebug = false;
// give this destination element the child mask from the packet
const unsigned char ALL_CHILDREN_ASSUMED_TO_EXIST = 0xFF;
if ((size_t)bytesLeftToRead < sizeof(unsigned char)) {
- if (wantDebug) {
- qDebug() << "UNEXPECTED: readElementData() only had " << bytesLeftToRead << " bytes. "
- "Not enough for meaningful data.";
- }
+ qDebug() << "UNEXPECTED: readElementData() only had " << bytesLeftToRead << " bytes. "
+ "Not enough for meaningful data.";
return bytesAvailable; // assume we read the entire buffer...
}
if (destinationElement->getScale() < SCALE_AT_DANGEROUSLY_DEEP_RECURSION) {
- if (wantDebug) {
- qDebug() << "UNEXPECTED: readElementData() destination element is unreasonably small ["
- << destinationElement->getScale() * (float)TREE_SCALE << " meters] "
- << " Discarding " << bytesAvailable << " remaining bytes.";
- }
+ qDebug() << "UNEXPECTED: readElementData() destination element is unreasonably small ["
+ << destinationElement->getScale() * (float)TREE_SCALE << " meters] "
+ << " Discarding " << bytesAvailable << " remaining bytes.";
return bytesAvailable; // assume we read the entire buffer...
}
@@ -322,7 +327,7 @@ int Octree::readElementData(OctreeElement* destinationElement, const unsigned ch
: sizeof(childInBufferMask);
if (bytesLeftToRead < bytesForMasks) {
- if (wantDebug) {
+ if (bytesLeftToRead > 0) {
qDebug() << "UNEXPECTED: readElementDataFromBuffer() only had " << bytesLeftToRead << " bytes before masks. "
"Not enough for meaningful data.";
}
@@ -385,7 +390,6 @@ void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long
ReadBitstreamToTreeParams& args) {
int bytesRead = 0;
const unsigned char* bitstreamAt = bitstream;
- bool wantDebug = false;
// If destination element is not included, set it to root
if (!args.destinationElement) {
@@ -398,14 +402,24 @@ void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long
while (bitstreamAt < bitstream + bufferSizeBytes) {
OctreeElement* bitstreamRootElement = nodeForOctalCode(args.destinationElement, (unsigned char *)bitstreamAt, NULL);
-
int numberOfThreeBitSectionsInStream = numberOfThreeBitSectionsInCode(bitstreamAt, bufferSizeBytes);
+ if (numberOfThreeBitSectionsInStream > UNREASONABLY_DEEP_RECURSION) {
+ static QString repeatedMessage
+ = LogHandler::getInstance().addRepeatedMessageRegex(
+ "UNEXPECTED: parsing of the octal code would make UNREASONABLY_DEEP_RECURSION... "
+ "numberOfThreeBitSectionsInStream: \\d+ This buffer is corrupt. Returning."
+ );
+
+
+ qDebug() << "UNEXPECTED: parsing of the octal code would make UNREASONABLY_DEEP_RECURSION... "
+ "numberOfThreeBitSectionsInStream:" << numberOfThreeBitSectionsInStream <<
+ "This buffer is corrupt. Returning.";
+ return;
+ }
if (numberOfThreeBitSectionsInStream == OVERFLOWED_OCTCODE_BUFFER) {
- if (wantDebug) {
- qDebug() << "UNEXPECTED: parsing of the octal code would overflow the buffer. "
- "This buffer is corrupt. Returning.";
- }
+ qDebug() << "UNEXPECTED: parsing of the octal code would overflow the buffer. "
+ "This buffer is corrupt. Returning.";
return;
}
diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h
index 42cbb3c38d..4ac7e22d90 100644
--- a/libraries/octree/src/Octree.h
+++ b/libraries/octree/src/Octree.h
@@ -373,7 +373,7 @@ protected:
static bool countOctreeElementsOperation(OctreeElement* element, void* extraData);
OctreeElement* nodeForOctalCode(OctreeElement* ancestorElement, const unsigned char* needleCode, OctreeElement** parentOfFoundElement) const;
- OctreeElement* createMissingElement(OctreeElement* lastParentElement, const unsigned char* codeToReach);
+ OctreeElement* createMissingElement(OctreeElement* lastParentElement, const unsigned char* codeToReach, int recursionCount = 0);
int readElementData(OctreeElement *destinationElement, const unsigned char* nodeData,
int bufferSizeBytes, ReadBitstreamToTreeParams& args);
diff --git a/libraries/octree/src/OctreeConstants.h b/libraries/octree/src/OctreeConstants.h
index 4186b90888..e924676771 100644
--- a/libraries/octree/src/OctreeConstants.h
+++ b/libraries/octree/src/OctreeConstants.h
@@ -35,10 +35,11 @@ const int MAX_TREE_SLICE_BYTES = 26;
const float VIEW_FRUSTUM_FOV_OVERSEND = 60.0f;
// These are guards to prevent our voxel tree recursive routines from spinning out of control
-const int UNREASONABLY_DEEP_RECURSION = 20; // use this for something that you want to be shallow, but not spin out
+const int UNREASONABLY_DEEP_RECURSION = 29; // use this for something that you want to be shallow, but not spin out
const int DANGEROUSLY_DEEP_RECURSION = 200; // use this for something that needs to go deeper
const float SCALE_AT_UNREASONABLY_DEEP_RECURSION = (1.0f / powf(2.0f, UNREASONABLY_DEEP_RECURSION));
const float SCALE_AT_DANGEROUSLY_DEEP_RECURSION = (1.0f / powf(2.0f, DANGEROUSLY_DEEP_RECURSION));
+const float SMALLEST_REASONABLE_OCTREE_ELEMENT_SCALE = SCALE_AT_UNREASONABLY_DEEP_RECURSION * 2.0f; // 0.00006103515 meter ~1/10,0000th
const int DEFAULT_MAX_OCTREE_PPS = 600; // the default maximum PPS we think any octree based server should send to a client
diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp
index a0a331beb3..e5db8b24f8 100644
--- a/libraries/octree/src/OctreeElement.cpp
+++ b/libraries/octree/src/OctreeElement.cpp
@@ -16,6 +16,7 @@
#include
+#include
#include
#include
#include
@@ -1159,6 +1160,10 @@ OctreeElement* OctreeElement::addChildAtIndex(int childIndex) {
bool OctreeElement::safeDeepDeleteChildAtIndex(int childIndex, int recursionCount) {
bool deleteApproved = false;
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
+ static QString repeatedMessage
+ = LogHandler::getInstance().addRepeatedMessageRegex(
+ "OctreeElement::safeDeepDeleteChildAtIndex\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!");
+
qDebug() << "OctreeElement::safeDeepDeleteChildAtIndex() reached DANGEROUSLY_DEEP_RECURSION, bailing!";
return deleteApproved;
}
diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h
index 31a9dfddc1..2bd5e3ae1e 100644
--- a/libraries/octree/src/OctreeElement.h
+++ b/libraries/octree/src/OctreeElement.h
@@ -36,8 +36,6 @@ class ReadBitstreamToTreeParams;
class Shape;
class VoxelSystem;
-const float SMALLEST_REASONABLE_OCTREE_ELEMENT_SCALE = (1.0f / TREE_SCALE) / 10000.0f; // 1/10,000th of a meter
-
// Callers who want delete hook callbacks should implement this class
class OctreeElementDeleteHook {
public:
diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp
index a8aafbe34d..5bcf49a1a4 100644
--- a/libraries/octree/src/OctreeRenderer.cpp
+++ b/libraries/octree/src/OctreeRenderer.cpp
@@ -162,8 +162,8 @@ bool OctreeRenderer::renderOperation(OctreeElement* element, void* extraData) {
return false;
}
-void OctreeRenderer::render(RenderArgs::RenderMode renderMode) {
- RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode,
+void OctreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::RenderSide renderSide) {
+ RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, renderSide,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
if (_tree) {
_tree->lockForRead();
diff --git a/libraries/octree/src/OctreeRenderer.h b/libraries/octree/src/OctreeRenderer.h
index d418467012..e8612b4cb6 100644
--- a/libraries/octree/src/OctreeRenderer.h
+++ b/libraries/octree/src/OctreeRenderer.h
@@ -52,7 +52,7 @@ public:
virtual void init();
/// render the content of the octree
- virtual void render(RenderArgs::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE);
+ virtual void render(RenderArgs::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE, RenderArgs::RenderSide renderSide = RenderArgs::MONO);
ViewFrustum* getViewFrustum() const { return _viewFrustum; }
void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; }
diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp
index dfac02b912..a13f3a9dad 100644
--- a/libraries/shared/src/LogHandler.cpp
+++ b/libraries/shared/src/LogHandler.cpp
@@ -119,6 +119,8 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont
char dateString[100];
strftime(dateString, sizeof(dateString), DATE_STRING_FORMAT, localTime);
+ prefixString.append(QString(" [%1]").arg(dateString));
+
if (_shouldOutputPID) {
prefixString.append(QString(" [%1").arg(getpid()));
diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h
index 1ed43f94ad..e447472fee 100644
--- a/libraries/shared/src/RenderArgs.h
+++ b/libraries/shared/src/RenderArgs.h
@@ -18,12 +18,14 @@ class OctreeRenderer;
class RenderArgs {
public:
enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE };
+ enum RenderSide { MONO, STEREO_LEFT, STEREO_RIGHT };
OctreeRenderer* _renderer;
ViewFrustum* _viewFrustum;
float _sizeScale;
int _boundaryLevelAdjust;
RenderMode _renderMode;
+ RenderSide _renderSide;
int _elementsTouched;
int _itemsRendered;