From 881cfb86dd9364f387ec453967003252df5f3b94 Mon Sep 17 00:00:00 2001 From: samcake Date: Sat, 8 Aug 2015 16:43:55 -0700 Subject: [PATCH 001/102] Updating the render engine dashboard --- examples/utilities/tools/cookies.js | 26 ++++ examples/utilities/tools/renderEngineDebug.js | 118 +++++++----------- 2 files changed, 72 insertions(+), 72 deletions(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index 751008fd99..b9d634d462 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -183,6 +183,24 @@ var CHECK_MARK_COLOR = { this.onValueChanged(resetValue); }; + + Slider.prototype.setMinValue = function(minValue) { + var currentValue = this.getValue(); + this.minValue = minValue; + this.setValue(currentValue); + }; + Slider.prototype.getMinValue = function() { + return this.minValue; + }; + Slider.prototype.setMaxValue = function(maxValue) { + var currentValue = this.getValue(); + this.maxValue = maxValue; + this.setValue(currentValue); + }; + Slider.prototype.getMaxValue = function() { + return this.maxValue; + }; + Slider.prototype.onValueChanged = function(value) {}; Slider.prototype.getHeight = function() { @@ -1396,6 +1414,14 @@ var CHECK_MARK_COLOR = { return null; }; + Panel.prototype.getWidget = function(name) { + var item = this.items[name]; + if (item != null) { + return item.widget; + } + return null; + }; + Panel.prototype.update = function(name) { var item = this.items[name]; if (item != null) { diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index d50a9c545c..49ac923436 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -12,59 +12,55 @@ Script.include("cookies.js"); var panel = new Panel(10, 100); -panel.newSlider("Num Feed Opaques", 0, 1000, - function(value) { }, - function() { return Scene.getEngineNumFeedOpaqueItems(); }, - function(value) { return (value); } +function CounterWidget(parentPanel, name, feedGetter, drawGetter, capSetter, capGetter) { + this.subPanel = panel.newSubPanel(name); + + this.subPanel.newSlider("Num Feed", 0, 1, + function(value) { }, + feedGetter, + function(value) { return (value); }); + this.subPanel.newSlider("Num Drawn", 0, 1, + function(value) { }, + drawGetter, + function(value) { return (value); }); + this.subPanel.newSlider("Max Drawn", -1, 1, + capSetter, + capGetter, + function(value) { return (value); }); + + this.update = function () { + var numFeed = this.subPanel.get("Num Feed"); + this.subPanel.set("Num Feed", numFeed); + this.subPanel.set("Num Drawn", this.subPanel.get("Num Drawn")); + + var numMax = Math.max(numFeed, 1); + this.subPanel.getWidget("Num Feed").setMaxValue(numMax); + this.subPanel.getWidget("Num Drawn").setMaxValue(numMax); + this.subPanel.getWidget("Max Drawn").setMaxValue(numMax); + }; +}; + +var opaquesCounter = new CounterWidget(panel, "Opaques", + function () { return Scene.getEngineNumFeedOpaqueItems(); }, + function () { return Scene.getEngineNumDrawnOpaqueItems(); }, + function(value) { Scene.setEngineMaxDrawnOpaqueItems(value); }, + function () { return Scene.getEngineMaxDrawnOpaqueItems(); } ); -panel.newSlider("Num Drawn Opaques", 0, 1000, - function(value) { }, - function() { return Scene.getEngineNumDrawnOpaqueItems(); }, - function(value) { return (value); } +var transparentsCounter = new CounterWidget(panel, "Transparents", + function () { return Scene.getEngineNumFeedTransparentItems(); }, + function () { return Scene.getEngineNumDrawnTransparentItems(); }, + function(value) { Scene.setEngineMaxDrawnTransparentItems(value); }, + function () { return Scene.getEngineMaxDrawnTransparentItems(); } ); -panel.newSlider("Max Drawn Opaques", -1, 1000, - function(value) { Scene.setEngineMaxDrawnOpaqueItems(value); }, - function() { return Scene.getEngineMaxDrawnOpaqueItems(); }, - function(value) { return (value); } +var overlaysCounter = new CounterWidget(panel, "Overlays", + function () { return Scene.getEngineNumFeedOverlay3DItems(); }, + function () { return Scene.getEngineNumDrawnOverlay3DItems(); }, + function(value) { Scene.setEngineMaxDrawnOverlay3DItems(value); }, + function () { return Scene.getEngineMaxDrawnOverlay3DItems(); } ); -panel.newSlider("Num Feed Transparents", 0, 100, - function(value) { }, - function() { return Scene.getEngineNumFeedTransparentItems(); }, - function(value) { return (value); } -); - -panel.newSlider("Num Drawn Transparents", 0, 100, - function(value) { }, - function() { return Scene.getEngineNumDrawnTransparentItems(); }, - function(value) { return (value); } -); - -panel.newSlider("Max Drawn Transparents", -1, 100, - function(value) { Scene.setEngineMaxDrawnTransparentItems(value); }, - function() { return Scene.getEngineMaxDrawnTransparentItems(); }, - function(value) { return (value); } -); - -panel.newSlider("Num Feed Overlay3Ds", 0, 100, - function(value) { }, - function() { return Scene.getEngineNumFeedOverlay3DItems(); }, - function(value) { return (value); } -); - -panel.newSlider("Num Drawn Overlay3Ds", 0, 100, - function(value) { }, - function() { return Scene.getEngineNumDrawnOverlay3DItems(); }, - function(value) { return (value); } -); - -panel.newSlider("Max Drawn Overlay3Ds", -1, 100, - function(value) { Scene.setEngineMaxDrawnOverlay3DItems(value); }, - function() { return Scene.getEngineMaxDrawnOverlay3DItems(); }, - function(value) { return (value); } -); panel.newCheckbox("Display status", function(value) { Scene.setEngineDisplayItemStatus(value); }, @@ -75,31 +71,9 @@ panel.newCheckbox("Display status", var tickTackPeriod = 500; function updateCounters() { - var numFeedOpaques = panel.get("Num Feed Opaques"); - var numFeedTransparents = panel.get("Num Feed Transparents"); - var numFeedOverlay3Ds = panel.get("Num Feed Overlay3Ds"); - - panel.set("Num Feed Opaques", numFeedOpaques); - panel.set("Num Drawn Opaques", panel.get("Num Drawn Opaques")); - panel.set("Num Feed Transparents", numFeedTransparents); - panel.set("Num Drawn Transparents", panel.get("Num Drawn Transparents")); - panel.set("Num Feed Overlay3Ds", numFeedOverlay3Ds); - panel.set("Num Drawn Overlay3Ds", panel.get("Num Drawn Overlay3Ds")); - - var numMax = Math.max(numFeedOpaques * 1.2, 1); - panel.getWidget("Num Feed Opaques").setMaxValue(numMax); - panel.getWidget("Num Drawn Opaques").setMaxValue(numMax); - panel.getWidget("Max Drawn Opaques").setMaxValue(numMax); - - numMax = Math.max(numFeedTransparents * 1.2, 1); - panel.getWidget("Num Feed Transparents").setMaxValue(numMax); - panel.getWidget("Num Drawn Transparents").setMaxValue(numMax); - panel.getWidget("Max Drawn Transparents").setMaxValue(numMax); - - numMax = Math.max(numFeedOverlay3Ds * 1.2, 1); - panel.getWidget("Num Feed Overlay3Ds").setMaxValue(numMax); - panel.getWidget("Num Drawn Overlay3Ds").setMaxValue(numMax); - panel.getWidget("Max Drawn Overlay3Ds").setMaxValue(numMax); + opaquesCounter.update(); + transparentsCounter.update(); + overlaysCounter.update(); } Script.setInterval(updateCounters, tickTackPeriod); From d6322903a2c39fc9e693e866218b06027053b74b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 11 Aug 2015 10:12:46 -0700 Subject: [PATCH 002/102] quiet compiler --- libraries/entities/src/EntityItemProperties.h | 2 +- libraries/entities/src/PolyLineEntityItem.cpp | 5 +- libraries/fbx/src/FBXReader.cpp | 22 +- libraries/render-utils/src/Model.cpp | 202 ++++++++---------- 4 files changed, 107 insertions(+), 124 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 8085c24d90..e7c280686a 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -154,9 +154,9 @@ public: DEFINE_PROPERTY_REF(PROP_HREF, Href, href, QString); DEFINE_PROPERTY_REF(PROP_DESCRIPTION, Description, description, QString); DEFINE_PROPERTY(PROP_FACE_CAMERA, FaceCamera, faceCamera, bool); + DEFINE_PROPERTY_REF(PROP_ACTION_DATA, ActionData, actionData, QByteArray); DEFINE_PROPERTY(PROP_NORMALS, Normals, normals, QVector); DEFINE_PROPERTY(PROP_STROKE_WIDTHS, StrokeWidths, strokeWidths, QVector); - DEFINE_PROPERTY_REF(PROP_ACTION_DATA, ActionData, actionData, QByteArray); DEFINE_PROPERTY_REF(PROP_X_TEXTURE_URL, XTextureURL, xTextureURL, QString); DEFINE_PROPERTY_REF(PROP_Y_TEXTURE_URL, YTextureURL, yTextureURL, QString); DEFINE_PROPERTY_REF(PROP_Z_TEXTURE_URL, ZTextureURL, zTextureURL, QString); diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index 9ade80f3be..196fde47fb 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -170,9 +170,10 @@ bool PolyLineEntityItem::setLinePoints(const QVector& points) { for (int i = 0; i < points.size(); i++) { glm::vec3 point = points.at(i); - glm::vec3 pos = getPosition(); glm::vec3 halfBox = getDimensions() * 0.5f; - if ( (point.x < - halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < - halfBox.z || point.z > halfBox.z) ) { + if ((point.x < - halfBox.x || point.x > halfBox.x) || + (point.y < -halfBox.y || point.y > halfBox.y) || + (point.z < - halfBox.z || point.z > halfBox.z)) { qDebug() << "Point is outside entity's bounding box"; return false; } diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 5e7647263a..ebffa4410a 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -976,7 +976,7 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) { data.extracted.mesh.meshIndex = meshIndex++; QVector materials; QVector textures; - bool isMaterialPerPolygon = false; + // bool isMaterialPerPolygon = false; foreach (const FBXNode& child, object.children) { if (child.name == "Vertices") { @@ -1107,13 +1107,13 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) { foreach (const FBXNode& subdata, child.children) { if (subdata.name == "Materials") { materials = getIntVector(subdata); - } else if (subdata.name == "MappingInformationType") { - if (subdata.properties.at(0) == "ByPolygon") { - isMaterialPerPolygon = true; - } else { - isMaterialPerPolygon = false; - } - } + } // else if (subdata.name == "MappingInformationType") { + // if (subdata.properties.at(0) == "ByPolygon") + // isMaterialPerPolygon = true; + // } else { + // isMaterialPerPolygon = false; + // } + // } } @@ -1126,12 +1126,6 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) { } } - - bool isMultiMaterial = false; - if (isMaterialPerPolygon) { - isMultiMaterial = true; - } - // convert the polygons to quads and triangles int polygonIndex = 0; QHash, int> materialTextureParts; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 3080d965a1..8a9a3f68dc 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -112,14 +112,14 @@ void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key, gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader)); gpu::Shader::makeProgram(*program, slotBindings); - - + + auto locations = std::make_shared(); initLocations(program, *locations); - + auto state = std::make_shared(); - + // Backface on shadow if (key.isShadow()) { state->setCullMode(gpu::State::CULL_FRONT); @@ -140,36 +140,36 @@ void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key, // Good to go add the brand new pipeline auto pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); insert(value_type(key.getRaw(), RenderPipeline(pipeline, locations))); - - + + if (!key.isWireFrame()) { - + RenderKey wireframeKey(key.getRaw() | RenderKey::IS_WIREFRAME); auto wireframeState = std::make_shared(state->getValues()); - + wireframeState->setFillMode(gpu::State::FILL_LINE); - + // create a new RenderPipeline with the same shader side and the mirrorState auto wireframePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, wireframeState)); insert(value_type(wireframeKey.getRaw(), RenderPipeline(wireframePipeline, locations))); } - + // If not a shadow pass, create the mirror version from the same state, just change the FrontFace if (!key.isShadow()) { - + RenderKey mirrorKey(key.getRaw() | RenderKey::IS_MIRROR); auto mirrorState = std::make_shared(state->getValues()); // create a new RenderPipeline with the same shader side and the mirrorState auto mirrorPipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, mirrorState)); insert(value_type(mirrorKey.getRaw(), RenderPipeline(mirrorPipeline, locations))); - + if (!key.isWireFrame()) { RenderKey wireframeKey(key.getRaw() | RenderKey::IS_MIRROR | RenderKey::IS_WIREFRAME); auto wireframeState = std::make_shared(state->getValues()); - + wireframeState->setFillMode(gpu::State::FILL_LINE); - + // create a new RenderPipeline with the same shader side and the mirrorState auto wireframePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, wireframeState)); insert(value_type(wireframeKey.getRaw(), RenderPipeline(wireframePipeline, locations))); @@ -214,12 +214,12 @@ void Model::setScaleInternal(const glm::vec3& scale) { } } -void Model::setOffset(const glm::vec3& offset) { - _offset = offset; - +void Model::setOffset(const glm::vec3& offset) { + _offset = offset; + // if someone manually sets our offset, then we are no longer snapped to center - _snapModelToRegistrationPoint = false; - _snappedToRegistrationPoint = false; + _snapModelToRegistrationPoint = false; + _snappedToRegistrationPoint = false; } QVector Model::createJointStates(const FBXGeometry& geometry) { @@ -267,7 +267,7 @@ void Model::init() { auto modelLightmapNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag))); // Fill the renderPipelineLib - + _renderPipelineLib.addRenderPipeline( RenderKey(0), modelVertex, modelPixel); @@ -284,7 +284,7 @@ void Model::init() { RenderKey(RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), modelNormalMapVertex, modelNormalSpecularMapPixel); - + _renderPipelineLib.addRenderPipeline( RenderKey(RenderKey::IS_TRANSLUCENT), modelVertex, modelTranslucentPixel); @@ -292,7 +292,7 @@ void Model::init() { _renderPipelineLib.addRenderPipeline( RenderKey(RenderKey::IS_TRANSLUCENT | RenderKey::HAS_LIGHTMAP), modelVertex, modelTranslucentPixel); - + _renderPipelineLib.addRenderPipeline( RenderKey(RenderKey::HAS_TANGENTS | RenderKey::IS_TRANSLUCENT), modelNormalMapVertex, modelTranslucentPixel); @@ -440,15 +440,15 @@ bool Model::updateGeometry() { } _geometry->setLoadPriority(this, -_lodDistance); _geometry->ensureLoading(); - + if (needToRebuild) { const FBXGeometry& fbxGeometry = geometry->getFBXGeometry(); foreach (const FBXMesh& mesh, fbxGeometry.meshes) { MeshState state; state.clusterMatrices.resize(mesh.clusters.size()); state.cauterizedClusterMatrices.resize(mesh.clusters.size()); - _meshStates.append(state); - + _meshStates.append(state); + auto buffer = std::make_shared(); if (!mesh.blendshapes.isEmpty()) { buffer->resize((mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3)); @@ -486,7 +486,7 @@ void Model::initJointStates(QVector states) { rightShoulderJointIndex); } -bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance, +bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, QString& extraInfo, bool pickAgainstTriangles) { bool intersectedSomething = false; @@ -495,7 +495,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g if (!isActive()) { return intersectedSomething; } - + // extents is the entity relative, scaled, centered extents of the entity glm::vec3 position = _translation; glm::mat4 rotation = glm::mat4_cast(_rotation); @@ -504,7 +504,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix); Extents modelExtents = getMeshExtents(); // NOTE: unrotated - + glm::vec3 dimensions = modelExtents.maximum - modelExtents.minimum; glm::vec3 corner = -(dimensions * _registrationPoint); // since we're going to do the ray picking in the model frame of reference AABox modelFrameBox(corner, dimensions); @@ -543,7 +543,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g int t = 0; foreach (const Triangle& triangle, meshTriangles) { t++; - + float thisTriangleDistance; if (findRayTriangleIntersection(origin, direction, triangle, thisTriangleDistance)) { if (thisTriangleDistance < bestDistance) { @@ -562,7 +562,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g extraInfo = geometry.getModelNameOfMesh(subMeshIndex); } } - } + } subMeshIndex++; } _mutex.unlock(); @@ -570,7 +570,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g if (intersectedSomething) { distance = bestDistance; } - + return intersectedSomething; } @@ -582,22 +582,22 @@ bool Model::convexHullContains(glm::vec3 point) { if (!isActive()) { return false; } - + // extents is the entity relative, scaled, centered extents of the entity glm::vec3 position = _translation; glm::mat4 rotation = glm::mat4_cast(_rotation); glm::mat4 translation = glm::translate(position); glm::mat4 modelToWorldMatrix = translation * rotation; glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix); - + Extents modelExtents = getMeshExtents(); // NOTE: unrotated - + glm::vec3 dimensions = modelExtents.maximum - modelExtents.minimum; glm::vec3 corner = -(dimensions * _registrationPoint); AABox modelFrameBox(corner, dimensions); - + glm::vec3 modelFramePoint = glm::vec3(worldToModelMatrix * glm::vec4(point, 1.0f)); - + // we can use the AABox's contains() by mapping our point into the model frame // and testing there. if (modelFrameBox.contains(modelFramePoint)){ @@ -605,7 +605,7 @@ bool Model::convexHullContains(glm::vec3 point) { if (!_calculatedMeshTrianglesValid) { recalculateMeshBoxes(true); } - + // If we are inside the models box, then consider the submeshes... int subMeshIndex = 0; foreach(const AABox& subMeshBox, _calculatedMeshBoxes) { @@ -619,7 +619,7 @@ bool Model::convexHullContains(glm::vec3 point) { insideMesh = false; break; } - + } if (insideMesh) { // It's inside this mesh, return true. @@ -658,7 +658,7 @@ void Model::recalculateMeshPartOffsets() { // Any script might trigger findRayIntersectionAgainstSubMeshes (and maybe convexHullContains), so these // can occur multiple times. In addition, rendering does it's own ray picking in order to decide which // entity-scripts to call. I think it would be best to do the picking once-per-frame (in cpu, or gpu if possible) -// and then the calls use the most recent such result. +// and then the calls use the most recent such result. void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { PROFILE_RANGE(__FUNCTION__); bool calculatedMeshTrianglesNeeded = pickAgainstTriangles && !_calculatedMeshTrianglesValid; @@ -703,7 +703,7 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { glm::vec3 mv1 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i1], 1.0f)); glm::vec3 mv2 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i2], 1.0f)); glm::vec3 mv3 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i3], 1.0f)); - + // track the mesh parts in model space if (!atLeastOnePointInBounds) { thisPartBounds.setBox(mv0, 0.0f); @@ -719,18 +719,18 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { glm::vec3 v1 = calculateScaledOffsetPoint(mv1); glm::vec3 v2 = calculateScaledOffsetPoint(mv2); glm::vec3 v3 = calculateScaledOffsetPoint(mv3); - + // Sam's recommended triangle slices Triangle tri1 = { v0, v1, v3 }; Triangle tri2 = { v1, v2, v3 }; - + // NOTE: Random guy on the internet's recommended triangle slices //Triangle tri1 = { v0, v1, v2 }; //Triangle tri2 = { v2, v3, v0 }; - + thisMeshTriangles.push_back(tri1); thisMeshTriangles.push_back(tri2); - + } } @@ -792,7 +792,7 @@ void Model::renderSetup(RenderArgs* args) { _dilatedTextures.append(dilated); } } - + if (!_meshGroupsKnown && isLoaded()) { segregateMeshGroups(); } @@ -805,7 +805,7 @@ public: transparent(transparent), model(model), url(model->getURL()), meshIndex(meshIndex), partIndex(partIndex) { } typedef render::Payload Payload; typedef Payload::DataPointer Pointer; - + bool transparent; Model* model; QUrl url; @@ -814,14 +814,14 @@ public: }; namespace render { - template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) { + template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) { if (!payload->model->isVisible()) { return ItemKey::Builder().withInvisible().build(); } return payload->transparent ? ItemKey::Builder::transparentShape() : ItemKey::Builder::opaqueShape(); } - - template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload) { + + template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload) { if (payload) { return payload->model->getPartBounds(payload->meshIndex, payload->partIndex); } @@ -875,7 +875,7 @@ bool Model::addToScene(std::shared_ptr scene, render::PendingChan _renderItems.insert(item, renderPayload); somethingAdded = true; } - + _readyWhenAdded = readyToAddToScene(); return somethingAdded; @@ -907,7 +907,7 @@ bool Model::addToScene(std::shared_ptr scene, render::PendingChan _renderItems.insert(item, renderPayload); somethingAdded = true; } - + _readyWhenAdded = readyToAddToScene(); return somethingAdded; @@ -929,7 +929,7 @@ void Model::renderDebugMeshBoxes(gpu::Batch& batch) { _debugMeshBoxesID = DependencyManager::get()->allocateID(); } QVector points; - + glm::vec3 brn = box.getCorner(); glm::vec3 bln = brn + glm::vec3(box.getDimensions().x, 0, 0); glm::vec3 brf = brn + glm::vec3(0, 0, box.getDimensions().z); @@ -963,12 +963,12 @@ void Model::renderDebugMeshBoxes(gpu::Batch& batch) { { 1.0f, 1.0f, 0.0f, 1.0f }, // yellow { 0.0f, 1.0f, 1.0f, 1.0f }, // cyan { 1.0f, 1.0f, 1.0f, 1.0f }, // white - { 0.0f, 0.5f, 0.0f, 1.0f }, - { 0.0f, 0.0f, 0.5f, 1.0f }, - { 0.5f, 0.0f, 0.5f, 1.0f }, - { 0.5f, 0.5f, 0.0f, 1.0f }, + { 0.0f, 0.5f, 0.0f, 1.0f }, + { 0.0f, 0.0f, 0.5f, 1.0f }, + { 0.5f, 0.0f, 0.5f, 1.0f }, + { 0.5f, 0.5f, 0.0f, 1.0f }, { 0.0f, 0.5f, 0.5f, 1.0f } }; - + DependencyManager::get()->updateVertices(_debugMeshBoxesID, points, color[colorNdx]); DependencyManager::get()->renderVertices(batch, gpu::LINES, _debugMeshBoxesID); colorNdx++; @@ -1003,7 +1003,7 @@ Extents Model::getUnscaledMeshExtents() const { if (!isActive()) { return Extents(); } - + const Extents& extents = _geometry->getFBXGeometry().meshExtents; // even though our caller asked for "unscaled" we need to include any fst scaling, translation, and rotation, which @@ -1011,7 +1011,7 @@ Extents Model::getUnscaledMeshExtents() const { glm::vec3 minimum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f)); glm::vec3 maximum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f)); Extents scaledExtents = { minimum, maximum }; - + return scaledExtents; } @@ -1020,12 +1020,12 @@ Extents Model::calculateScaledOffsetExtents(const Extents& extents) const { glm::vec3 minimum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f)); glm::vec3 maximum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f)); - Extents scaledOffsetExtents = { ((minimum + _offset) * _scale), + Extents scaledOffsetExtents = { ((minimum + _offset) * _scale), ((maximum + _offset) * _scale) }; Extents rotatedExtents = scaledOffsetExtents.getRotated(_rotation); - Extents translatedExtents = { rotatedExtents.minimum + _translation, + Extents translatedExtents = { rotatedExtents.minimum + _translation, rotatedExtents.maximum + _translation }; return translatedExtents; @@ -1084,7 +1084,7 @@ void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bo onInvalidate(); - // if so instructed, keep the current geometry until the new one is loaded + // if so instructed, keep the current geometry until the new one is loaded _nextGeometry = DependencyManager::get()->getGeometry(url, fallback, delayLoad); _nextLODHysteresis = NetworkGeometry::NO_HYSTERESIS; if (!retainCurrent || !isActive() || (_nextGeometry && _nextGeometry->isLoaded())) { @@ -1094,14 +1094,14 @@ void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bo void Model::geometryRefreshed() { QObject* sender = QObject::sender(); - + if (sender == _geometry) { _readyWhenAdded = false; // reset out render items. _needsReload = true; invalidCalculatedMeshBoxes(); - + onInvalidate(); - + // if so instructed, keep the current geometry until the new one is loaded _nextGeometry = DependencyManager::get()->getGeometry(_url); _nextLODHysteresis = NetworkGeometry::NO_HYSTERESIS; @@ -1121,7 +1121,7 @@ const QSharedPointer Model::getCollisionGeometry(bool delayLoad if (_collisionGeometry && _collisionGeometry->isLoaded()) { return _collisionGeometry; } - + return QSharedPointer(); } @@ -1176,11 +1176,11 @@ public: Blender(Model* model, int blendNumber, const QWeakPointer& geometry, const QVector& meshes, const QVector& blendshapeCoefficients); - + virtual void run(); private: - + QPointer _model; int _blendNumber; QWeakPointer _geometry; @@ -1254,10 +1254,10 @@ void Model::setScaleToFit(bool scaleToFit, float largestDimension, bool forceRes } return; } - + if (forceRescale || _scaleToFit != scaleToFit || glm::length(_scaleToFitDimensions) != largestDimension) { _scaleToFit = scaleToFit; - + // we only need to do this work if we're "turning on" scale to fit. if (scaleToFit) { Extents modelMeshExtents = getUnscaledMeshExtents(); @@ -1278,7 +1278,7 @@ void Model::scaleToFit() { // we didn't yet have an active mesh. We can only enter this scaleToFit() in this state // if we now do have an active mesh, so we take this opportunity to actually determine // the correct scale. - if (_scaleToFit && _scaleToFitDimensions.y == FAKE_DIMENSION_PLACEHOLDER + if (_scaleToFit && _scaleToFitDimensions.y == FAKE_DIMENSION_PLACEHOLDER && _scaleToFitDimensions.z == FAKE_DIMENSION_PLACEHOLDER) { setScaleToFit(_scaleToFit, _scaleToFitDimensions.x); } @@ -1313,7 +1313,7 @@ void Model::simulate(float deltaTime, bool fullUpdate) { PROFILE_RANGE(__FUNCTION__); fullUpdate = updateGeometry() || fullUpdate || (_scaleToFit && !_scaledToFit) || (_snapModelToRegistrationPoint && !_snappedToRegistrationPoint); - + if (isActive() && fullUpdate) { // NOTE: This is overly aggressive and we are invalidating the MeshBoxes when in fact they may not be invalid // they really only become invalid if something about the transform to world space has changed. This is @@ -1440,7 +1440,7 @@ void Model::setBlendedVertices(int blendNumber, const QWeakPointergetFBXGeometry(); + const FBXGeometry& fbxGeometry = _geometry->getFBXGeometry(); int index = 0; for (int i = 0; i < fbxGeometry.meshes.size(); i++) { const FBXMesh& mesh = fbxGeometry.meshes.at(i); @@ -1461,7 +1461,7 @@ void Model::setGeometry(const QSharedPointer& newGeometry) { if (_geometry == newGeometry) { return; } - + if (_geometry) { _geometry->disconnect(_geometry.data(), &Resource::onRefresh, this, &Model::geometryRefreshed); } @@ -1474,10 +1474,10 @@ void Model::applyNextGeometry() { deleteGeometry(); _dilatedTextures.clear(); _lodHysteresis = _nextLODHysteresis; - + // we retain a reference to the base geometry so that its reference count doesn't fall to zero setGeometry(_nextGeometry); - + _meshGroupsKnown = false; _readyWhenAdded = false; // in case any of our users are using scenes _needsReload = false; // we are loaded now! @@ -1509,9 +1509,9 @@ AABox Model::getPartBounds(int meshIndex, int partIndex) { return calculateScaledOffsetAABox(_geometry->getFBXGeometry().meshExtents); } } - + if (_geometry->getFBXGeometry().meshes.size() > meshIndex) { - + // FIX ME! - This is currently a hack because for some mesh parts our efforts to calculate the bounding // box of the mesh part fails. It seems to create boxes that are not consistent with where the // geometry actually renders. If instead we make all the parts share the bounds of the entire subMesh @@ -1536,7 +1536,7 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran if (!_readyWhenAdded) { return; // bail asap } - + // We need to make sure we have valid offsets calculated before we can render if (!_calculatedMeshPartOffsetValid) { _mutex.lock(); @@ -1561,13 +1561,13 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran // guard against partially loaded meshes if (meshIndex >= networkMeshes.size() || meshIndex >= geometry.meshes.size() || meshIndex >= _meshStates.size() ) { - return; + return; } const NetworkMesh& networkMesh = networkMeshes.at(meshIndex); const FBXMesh& mesh = geometry.meshes.at(meshIndex); const MeshState& state = _meshStates.at(meshIndex); - + bool translucentMesh = translucent; // networkMesh.getTranslucentPartCount(mesh) == networkMesh.parts.size(); bool hasTangents = !mesh.tangents.isEmpty(); bool hasSpecular = mesh.hasSpecularTexture(); @@ -1597,7 +1597,7 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran DependencyManager::get()->renderWireCube(batch, 1.0f, cubeColor); } #endif //def DEBUG_BOUNDING_PARTS - + if (wireframe) { translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false; } @@ -1614,14 +1614,14 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown // to false to rebuild out mesh groups. - + if (meshIndex < 0 || meshIndex >= networkMeshes.size() || meshIndex > geometry.meshes.size()) { _meshGroupsKnown = false; // regenerate these lists next time around. _readyWhenAdded = false; // in case any of our users are using scenes invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid return; // FIXME! } - + batch.setIndexBuffer(gpu::UINT32, (networkMesh._indexBuffer), 0); int vertexCount = mesh.vertices.size(); if (vertexCount == 0) { @@ -1633,7 +1633,7 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran if (_transforms.empty()) { _transforms.push_back(Transform()); } - + if (isSkinned) { const float* bones; if (_cauterizeBones) { @@ -1682,7 +1682,7 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran qCDebug(renderutils) << "WARNING: material == nullptr!!!"; } #endif - + if (material != nullptr) { // apply material properties @@ -1724,12 +1724,12 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran batch._glUniformMatrix4fv(locations->texcoordMatrices, 2, false, (const float*) &texcoordTransform); } - if (!mesh.tangents.isEmpty()) { + if (!mesh.tangents.isEmpty()) { NetworkTexture* normalMap = networkPart.normalTexture.data(); batch.setResourceTexture(1, (!normalMap || !normalMap->isLoaded()) ? textureCache->getBlueTexture() : normalMap->getGPUTexture()); } - + if (locations->specularTextureUnit >= 0) { NetworkTexture* specularMap = networkPart.specularTexture.data(); batch.setResourceTexture(locations->specularTextureUnit, (!specularMap || !specularMap->isLoaded()) ? @@ -1747,18 +1747,18 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran float emissiveOffset = part.emissiveParams.x; float emissiveScale = part.emissiveParams.y; batch._glUniform2f(locations->emissiveParams, emissiveOffset, emissiveScale); - + NetworkTexture* emissiveMap = networkPart.emissiveTexture.data(); batch.setResourceTexture(locations->emissiveTextureUnit, (!emissiveMap || !emissiveMap->isLoaded()) ? textureCache->getGrayTexture() : emissiveMap->getGPUTexture()); } - + if (translucent && locations->lightBufferUnit >= 0) { DependencyManager::get()->setupTransparent(args, locations->lightBufferUnit); } } } - + qint64 offset; { // FIXME_STUTTER: We should n't have any lock here @@ -1798,7 +1798,7 @@ void Model::segregateMeshGroups() { qDebug() << "WARNING!!!! Mesh Sizes don't match! We will not segregate mesh groups yet."; return; } - + _transparentRenderItems.clear(); _opaqueRenderItems.clear(); @@ -1807,18 +1807,6 @@ void Model::segregateMeshGroups() { const NetworkMesh& networkMesh = networkMeshes.at(i); const FBXMesh& mesh = geometry.meshes.at(i); const MeshState& state = _meshStates.at(i); - - - bool translucentMesh = networkMesh.getTranslucentPartCount(mesh) == networkMesh.parts.size(); - bool hasTangents = !mesh.tangents.isEmpty(); - bool hasSpecular = mesh.hasSpecularTexture(); - bool hasLightmap = mesh.hasEmissiveTexture(); - bool isSkinned = state.clusterMatrices.size() > 1; - bool wireframe = isWireframe(); - - if (wireframe) { - translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false; - } // Create the render payloads int totalParts = mesh.parts.size(); @@ -1831,7 +1819,7 @@ void Model::segregateMeshGroups() { } } _meshGroupsKnown = true; -} +} void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args, @@ -1851,7 +1839,7 @@ void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, f gpu::ShaderPointer program = (*pipeline).second._pipeline->getProgram(); locations = (*pipeline).second._locations.get(); - + // Setup the One pipeline batch.setPipeline((*pipeline).second._pipeline); @@ -1865,7 +1853,7 @@ void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, f } if ((locations->normalFittingMapUnit > -1)) { - batch.setResourceTexture(locations->normalFittingMapUnit, + batch.setResourceTexture(locations->normalFittingMapUnit, DependencyManager::get()->getNormalFittingTexture()); } } From dab584833059bb529b3aa5179417bbbac4f691e6 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 11 Aug 2015 10:21:30 -0700 Subject: [PATCH 003/102] quiet compiler --- libraries/gpu/src/gpu/State.h | 816 +++++++++++++++++----------------- 1 file changed, 408 insertions(+), 408 deletions(-) diff --git a/libraries/gpu/src/gpu/State.h b/libraries/gpu/src/gpu/State.h index 5e53284f36..42177e74dc 100755 --- a/libraries/gpu/src/gpu/State.h +++ b/libraries/gpu/src/gpu/State.h @@ -1,408 +1,408 @@ -// -// State -// libraries/gpu/src/gpu -// -// Created by Sam Gateau on 3/8/2015. -// 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_gpu_State_h -#define hifi_gpu_State_h - -#include "Format.h" - -#include -#include -#include -#include - -// Why a macro and not a fancy template you will ask me ? -// Because some of the fields are bool packed tightly in the State::Cache class -// and it s just not good anymore for template T& variable manipulation... -#define SET_FIELD(field, defaultValue, value, dest) {\ - dest = value;\ - if (value == defaultValue) {\ - _signature.reset(field);\ - } else {\ - _signature.set(field);\ - }\ - _stamp++;\ -}\ - - -namespace gpu { - -class GPUObject; - -class State { -public: - State(); - virtual ~State(); - - Stamp getStamp() const { return _stamp; } - - typedef ::gpu::ComparisonFunction ComparisonFunction; - - enum FillMode { - FILL_POINT = 0, - FILL_LINE, - FILL_FACE, - - NUM_FILL_MODES, - }; - - enum CullMode { - CULL_NONE = 0, - CULL_FRONT, - CULL_BACK, - - NUM_CULL_MODES, - }; - - enum StencilOp { - STENCIL_OP_KEEP = 0, - STENCIL_OP_ZERO, - STENCIL_OP_REPLACE, - STENCIL_OP_INCR_SAT, - STENCIL_OP_DECR_SAT, - STENCIL_OP_INVERT, - STENCIL_OP_INCR, - STENCIL_OP_DECR, - - NUM_STENCIL_OPS, - }; - - enum BlendArg { - ZERO = 0, - ONE, - SRC_COLOR, - INV_SRC_COLOR, - SRC_ALPHA, - INV_SRC_ALPHA, - DEST_ALPHA, - INV_DEST_ALPHA, - DEST_COLOR, - INV_DEST_COLOR, - SRC_ALPHA_SAT, - FACTOR_COLOR, - INV_FACTOR_COLOR, - FACTOR_ALPHA, - INV_FACTOR_ALPHA, - - NUM_BLEND_ARGS, - }; - - enum BlendOp { - BLEND_OP_ADD = 0, - BLEND_OP_SUBTRACT, - BLEND_OP_REV_SUBTRACT, - BLEND_OP_MIN, - BLEND_OP_MAX, - - NUM_BLEND_OPS, - }; - - enum ColorMask - { - WRITE_NONE = 0, - WRITE_RED = 1, - WRITE_GREEN = 2, - WRITE_BLUE = 4, - WRITE_ALPHA = 8, - WRITE_ALL = (WRITE_RED | WRITE_GREEN | WRITE_BLUE | WRITE_ALPHA ), - }; - - class DepthTest { - uint8 _function = LESS; - uint8 _writeMask = true; - uint8 _enabled = false; - uint8 _spare = 0; - public: - DepthTest(bool enabled = false, bool writeMask = true, ComparisonFunction func = LESS) : - _function(func), _writeMask(writeMask), _enabled(enabled) {} - - bool isEnabled() const { return _enabled; } - ComparisonFunction getFunction() const { return ComparisonFunction(_function); } - bool getWriteMask() const { return _writeMask; } - - int32 getRaw() const { return *(reinterpret_cast(this)); } - DepthTest(int32 raw) { *(reinterpret_cast(this)) = raw; } - bool operator== (const DepthTest& right) const { return getRaw() == right.getRaw(); } - bool operator!= (const DepthTest& right) const { return getRaw() != right.getRaw(); } - }; - - class StencilTest { - static const int FUNC_MASK = 0x000f; - static const int FAIL_OP_MASK = 0x00f0; - static const int DEPTH_FAIL_OP_MASK = 0x0f00; - static const int PASS_OP_MASK = 0xf000; - static const int FAIL_OP_OFFSET = 4; - static const int DEPTH_FAIL_OP_OFFSET = 8; - static const int PASS_OP_OFFSET = 12; - - uint16 _functionAndOperations; - uint8 _reference = 0; - uint8 _readMask = 0xff; - public: - - StencilTest(uint8 reference = 0, uint8 readMask =0xFF, ComparisonFunction func = ALWAYS, StencilOp failOp = STENCIL_OP_KEEP, StencilOp depthFailOp = STENCIL_OP_KEEP, StencilOp passOp = STENCIL_OP_KEEP) : - _functionAndOperations(func | (failOp << FAIL_OP_OFFSET) | (depthFailOp << DEPTH_FAIL_OP_OFFSET) | (passOp << PASS_OP_OFFSET)), - _reference(reference), _readMask(readMask) - {} - - ComparisonFunction getFunction() const { return ComparisonFunction(_functionAndOperations & FUNC_MASK); } - StencilOp getFailOp() const { return StencilOp((_functionAndOperations & FAIL_OP_MASK) >> FAIL_OP_OFFSET); } - StencilOp getDepthFailOp() const { return StencilOp((_functionAndOperations & DEPTH_FAIL_OP_MASK) >> DEPTH_FAIL_OP_OFFSET); } - StencilOp getPassOp() const { return StencilOp((_functionAndOperations & PASS_OP_MASK) >> PASS_OP_OFFSET); } - - uint8 getReference() const { return _reference; } - uint8 getReadMask() const { return _readMask; } - - int32 getRaw() const { return *(reinterpret_cast(this)); } - StencilTest(int32 raw) { *(reinterpret_cast(this)) = raw; } - bool operator== (const StencilTest& right) const { return getRaw() == right.getRaw(); } - bool operator!= (const StencilTest& right) const { return getRaw() != right.getRaw(); } - }; - - class StencilActivation { - uint8 _frontWriteMask = 0xFF; - uint8 _backWriteMask = 0xFF; - uint16 _enabled = 0; - public: - - StencilActivation(bool enabled, uint8 frontWriteMask = 0xFF, uint8 backWriteMask = 0xFF) : - _frontWriteMask(frontWriteMask), _backWriteMask(backWriteMask), _enabled(enabled) {} - - bool isEnabled() const { return (_enabled != 0); } - uint8 getWriteMaskFront() const { return _frontWriteMask; } - uint8 getWriteMaskBack() const { return _backWriteMask; } - - int32 getRaw() const { return *(reinterpret_cast(this)); } - StencilActivation(int32 raw) { *(reinterpret_cast(this)) = raw; } - bool operator== (const StencilActivation& right) const { return getRaw() == right.getRaw(); } - bool operator!= (const StencilActivation& right) const { return getRaw() != right.getRaw(); } - }; - - class BlendFunction { - static const int COLOR_MASK = 0x0f; - static const int ALPHA_MASK = 0xf0; - static const int ALPHA_OFFSET = 4; - - uint8 _enabled; - uint8 _source; - uint8 _destination; - uint8 _operation; - public: - - BlendFunction(bool enabled, - BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, - BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) : - _enabled(enabled), - _source(sourceColor | (sourceAlpha << ALPHA_OFFSET)), - _destination(destinationColor | (destinationAlpha << ALPHA_OFFSET)), - _operation(operationColor | (operationAlpha << ALPHA_OFFSET)) {} - - BlendFunction(bool enabled, BlendArg source = ONE, BlendOp operation = BLEND_OP_ADD, BlendArg destination = ZERO) : - _enabled(enabled), - _source(source | (source << ALPHA_OFFSET)), - _destination(destination | (destination << ALPHA_OFFSET)), - _operation(operation | (operation << ALPHA_OFFSET)) {} - - bool isEnabled() const { return (_enabled != 0); } - - BlendArg getSourceColor() const { return BlendArg(_source & COLOR_MASK); } - BlendArg getDestinationColor() const { return BlendArg(_destination & COLOR_MASK); } - BlendOp getOperationColor() const { return BlendOp(_operation & COLOR_MASK); } - - BlendArg getSourceAlpha() const { return BlendArg((_source & ALPHA_MASK) >> ALPHA_OFFSET); } - BlendArg getDestinationAlpha() const { return BlendArg((_destination & ALPHA_MASK) >> ALPHA_OFFSET); } - BlendOp getOperationAlpha() const { return BlendOp((_operation & ALPHA_MASK) >> ALPHA_OFFSET); } - - int32 getRaw() const { return *(reinterpret_cast(this)); } - BlendFunction(int32 raw) { *(reinterpret_cast(this)) = raw; } - bool operator== (const BlendFunction& right) const { return getRaw() == right.getRaw(); } - bool operator!= (const BlendFunction& right) const { return getRaw() != right.getRaw(); } - }; - - // The Data class is the full explicit description of the State class fields value. - // Useful for having one const static called Default for reference or for the gpu::Backend to keep track of the current value - class Data { - public: - float depthBias = 0.0f; - float depthBiasSlopeScale = 0.0f; - - DepthTest depthTest = DepthTest(false, true, LESS); - - StencilActivation stencilActivation = StencilActivation(false); - StencilTest stencilTestFront = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); - StencilTest stencilTestBack = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); - - uint32 sampleMask = 0xFFFFFFFF; - - BlendFunction blendFunction = BlendFunction(false); - - uint8 fillMode = FILL_FACE; - uint8 cullMode = CULL_NONE; - - uint8 colorWriteMask = WRITE_ALL; - - bool frontFaceClockwise : 1; - bool depthClampEnable : 1; - bool scissorEnable : 1; - bool multisampleEnable : 1; - bool antialisedLineEnable : 1; - bool alphaToCoverageEnable : 1; - - Data() : - frontFaceClockwise(false), - depthClampEnable(false), - scissorEnable(false), - multisampleEnable(false), - antialisedLineEnable(true), - alphaToCoverageEnable(false) - {} - }; - - // The unique default values for all the fields - static const Data DEFAULT; - void setFillMode(FillMode fill) { SET_FIELD(FILL_MODE, DEFAULT.fillMode, fill, _values.fillMode); } - FillMode getFillMode() const { return FillMode(_values.fillMode); } - - void setCullMode(CullMode cull) { SET_FIELD(CULL_MODE, DEFAULT.cullMode, cull, _values.cullMode); } - CullMode getCullMode() const { return CullMode(_values.cullMode); } - - void setFrontFaceClockwise(bool isClockwise) { SET_FIELD(FRONT_FACE_CLOCKWISE, DEFAULT.frontFaceClockwise, isClockwise, _values.frontFaceClockwise); } - bool isFrontFaceClockwise() const { return _values.frontFaceClockwise; } - - void setDepthClampEnable(bool enable) { SET_FIELD(DEPTH_CLAMP_ENABLE, DEFAULT.depthClampEnable, enable, _values.depthClampEnable); } - bool isDepthClampEnable() const { return _values.depthClampEnable; } - - void setScissorEnable(bool enable) { SET_FIELD(SCISSOR_ENABLE, DEFAULT.scissorEnable, enable, _values.scissorEnable); } - bool isScissorEnable() const { return _values.scissorEnable; } - - void setMultisampleEnable(bool enable) { SET_FIELD(MULTISAMPLE_ENABLE, DEFAULT.multisampleEnable, enable, _values.multisampleEnable); } - bool isMultisampleEnable() const { return _values.multisampleEnable; } - - void setAntialiasedLineEnable(bool enable) { SET_FIELD(ANTIALISED_LINE_ENABLE, DEFAULT.antialisedLineEnable, enable, _values.antialisedLineEnable); } - bool isAntialiasedLineEnable() const { return _values.antialisedLineEnable; } - - // Depth Bias - void setDepthBias(float bias) { SET_FIELD(DEPTH_BIAS, DEFAULT.depthBias, bias, _values.depthBias); } - float getDepthBias() const { return _values.depthBias; } - - void setDepthBiasSlopeScale(float scale) { SET_FIELD(DEPTH_BIAS_SLOPE_SCALE, DEFAULT.depthBiasSlopeScale, scale, _values.depthBiasSlopeScale); } - float getDepthBiasSlopeScale() const { return _values.depthBiasSlopeScale; } - - // Depth Test - void setDepthTest(DepthTest depthTest) { SET_FIELD(DEPTH_TEST, DEFAULT.depthTest, depthTest, _values.depthTest); } - void setDepthTest(bool enable, bool writeMask, ComparisonFunction func) { setDepthTest(DepthTest(enable, writeMask, func)); } - DepthTest getDepthTest() const { return _values.depthTest; } - - bool isDepthTestEnabled() const { return getDepthTest().isEnabled(); } - bool getDepthTestWriteMask() const { return getDepthTest().getWriteMask(); } - ComparisonFunction getDepthTestFunc() const { return getDepthTest().getFunction(); } - - // Stencil test - void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest, uint8 backWriteMask, StencilTest backTest) { - SET_FIELD(STENCIL_ACTIVATION, DEFAULT.stencilActivation, StencilActivation(enabled, frontWriteMask, backWriteMask), _values.stencilActivation); - SET_FIELD(STENCIL_TEST_FRONT, DEFAULT.stencilTestFront, frontTest, _values.stencilTestFront); - SET_FIELD(STENCIL_TEST_BACK, DEFAULT.stencilTestBack, backTest, _values.stencilTestBack); } - void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest) { - setStencilTest(enabled, frontWriteMask, frontTest, frontWriteMask, frontTest); } - - StencilActivation getStencilActivation() const { return _values.stencilActivation; } - StencilTest getStencilTestFront() const { return _values.stencilTestFront; } - StencilTest getStencilTestBack() const { return _values.stencilTestBack; } - - bool isStencilEnabled() const { return getStencilActivation().isEnabled(); } - uint8 getStencilWriteMaskFront() const { return getStencilActivation().getWriteMaskFront(); } - uint8 getStencilWriteMaskBack() const { return getStencilActivation().getWriteMaskBack(); } - - // Alpha to coverage - void setAlphaToCoverageEnable(bool enable) { SET_FIELD(ALPHA_TO_COVERAGE_ENABLE, DEFAULT.alphaToCoverageEnable, enable, _values.alphaToCoverageEnable); } - bool isAlphaToCoverageEnabled() const { return _values.alphaToCoverageEnable; } - - // Sample mask - void setSampleMask(uint32 mask) { SET_FIELD(SAMPLE_MASK, DEFAULT.sampleMask, mask, _values.sampleMask); } - uint32 getSampleMask() const { return _values.sampleMask; } - - // Blend Function - void setBlendFunction(BlendFunction function) { SET_FIELD(BLEND_FUNCTION, DEFAULT.blendFunction, function, _values.blendFunction); } - BlendFunction getBlendFunction() const { return _values.blendFunction; } - - void setBlendFunction(bool enabled, BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) { - setBlendFunction(BlendFunction(enabled, sourceColor, operationColor, destinationColor, sourceAlpha, operationAlpha, destinationAlpha)); } - void setBlendFunction(bool enabled, BlendArg source, BlendOp operation, BlendArg destination) { - setBlendFunction(BlendFunction(enabled, source, operation, destination)); } - - bool isBlendEnabled() const { return getBlendFunction().isEnabled(); } - - // Color write mask - void setColorWriteMask(uint8 mask) { SET_FIELD(COLOR_WRITE_MASK, DEFAULT.colorWriteMask, mask, _values.colorWriteMask); } - void setColorWriteMask(bool red, bool green, bool blue, bool alpha) { uint32 value = ((WRITE_RED * red) | (WRITE_GREEN * green) | (WRITE_BLUE * blue) | (WRITE_ALPHA * alpha)); SET_FIELD(COLOR_WRITE_MASK, DEFAULT.colorWriteMask, value, _values.colorWriteMask); } - uint8 getColorWriteMask() const { return _values.colorWriteMask; } - - // All the possible fields - enum Field { - FILL_MODE, - CULL_MODE, - FRONT_FACE_CLOCKWISE, - DEPTH_CLAMP_ENABLE, - SCISSOR_ENABLE, - MULTISAMPLE_ENABLE, - ANTIALISED_LINE_ENABLE, - - DEPTH_BIAS, - DEPTH_BIAS_SLOPE_SCALE, - - DEPTH_TEST, - - STENCIL_ACTIVATION, - STENCIL_TEST_FRONT, - STENCIL_TEST_BACK, - - SAMPLE_MASK, - ALPHA_TO_COVERAGE_ENABLE, - - BLEND_FUNCTION, - - COLOR_WRITE_MASK, - - NUM_FIELDS, // not a valid field, just the count - }; - - // The signature of the state tells which fields of the state are not default - // this way during rendering the Backend can compare it's current state and try to minimize the job to do - typedef std::bitset Signature; - - Signature getSignature() const { return _signature; } - - static Signature evalSignature(const Data& state); - - // For convenience, create a State from the values directly - State(const Data& values); - const Data& getValues() const { return _values; } - -protected: - State(const State& state); - State& operator=(const State& state); - - Data _values; - Signature _signature{0}; - Stamp _stamp{0}; - - // This shouldn't be used by anything else than the Backend class with the proper casting. - mutable GPUObject* _gpuObject = nullptr; - void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } - GPUObject* getGPUObject() const { return _gpuObject; } - friend class Backend; -}; - -typedef std::shared_ptr< State > StatePointer; -typedef std::vector< StatePointer > States; - -}; - -#endif +// +// State +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 3/8/2015. +// 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_gpu_State_h +#define hifi_gpu_State_h + +#include "Format.h" + +#include +#include +#include +#include + +// Why a macro and not a fancy template you will ask me ? +// Because some of the fields are bool packed tightly in the State::Cache class +// and it s just not good anymore for template T& variable manipulation... +#define SET_FIELD(field, defaultValue, value, dest) {\ + dest = value;\ + if (value == defaultValue) {\ + _signature.reset(field);\ + } else {\ + _signature.set(field);\ + }\ + _stamp++;\ +}\ + + +namespace gpu { + +class GPUObject; + +class State { +public: + State(); + virtual ~State(); + + Stamp getStamp() const { return _stamp; } + + typedef ::gpu::ComparisonFunction ComparisonFunction; + + enum FillMode { + FILL_POINT = 0, + FILL_LINE, + FILL_FACE, + + NUM_FILL_MODES, + }; + + enum CullMode { + CULL_NONE = 0, + CULL_FRONT, + CULL_BACK, + + NUM_CULL_MODES, + }; + + enum StencilOp { + STENCIL_OP_KEEP = 0, + STENCIL_OP_ZERO, + STENCIL_OP_REPLACE, + STENCIL_OP_INCR_SAT, + STENCIL_OP_DECR_SAT, + STENCIL_OP_INVERT, + STENCIL_OP_INCR, + STENCIL_OP_DECR, + + NUM_STENCIL_OPS, + }; + + enum BlendArg { + ZERO = 0, + ONE, + SRC_COLOR, + INV_SRC_COLOR, + SRC_ALPHA, + INV_SRC_ALPHA, + DEST_ALPHA, + INV_DEST_ALPHA, + DEST_COLOR, + INV_DEST_COLOR, + SRC_ALPHA_SAT, + FACTOR_COLOR, + INV_FACTOR_COLOR, + FACTOR_ALPHA, + INV_FACTOR_ALPHA, + + NUM_BLEND_ARGS, + }; + + enum BlendOp { + BLEND_OP_ADD = 0, + BLEND_OP_SUBTRACT, + BLEND_OP_REV_SUBTRACT, + BLEND_OP_MIN, + BLEND_OP_MAX, + + NUM_BLEND_OPS, + }; + + enum ColorMask + { + WRITE_NONE = 0, + WRITE_RED = 1, + WRITE_GREEN = 2, + WRITE_BLUE = 4, + WRITE_ALPHA = 8, + WRITE_ALL = (WRITE_RED | WRITE_GREEN | WRITE_BLUE | WRITE_ALPHA ), + }; + + class DepthTest { + uint8 _function = LESS; + uint8 _writeMask = true; + uint8 _enabled = false; + uint8 _spare = 0; + public: + DepthTest(bool enabled = false, bool writeMask = true, ComparisonFunction func = LESS) : + _function(func), _writeMask(writeMask), _enabled(enabled) {} + + bool isEnabled() const { return _enabled != 0; } + ComparisonFunction getFunction() const { return ComparisonFunction(_function); } + bool getWriteMask() const { return _writeMask; } + + int32 getRaw() const { return *(reinterpret_cast(this)); } + DepthTest(int32 raw) { *(reinterpret_cast(this)) = raw; } + bool operator== (const DepthTest& right) const { return getRaw() == right.getRaw(); } + bool operator!= (const DepthTest& right) const { return getRaw() != right.getRaw(); } + }; + + class StencilTest { + static const int FUNC_MASK = 0x000f; + static const int FAIL_OP_MASK = 0x00f0; + static const int DEPTH_FAIL_OP_MASK = 0x0f00; + static const int PASS_OP_MASK = 0xf000; + static const int FAIL_OP_OFFSET = 4; + static const int DEPTH_FAIL_OP_OFFSET = 8; + static const int PASS_OP_OFFSET = 12; + + uint16 _functionAndOperations; + uint8 _reference = 0; + uint8 _readMask = 0xff; + public: + + StencilTest(uint8 reference = 0, uint8 readMask =0xFF, ComparisonFunction func = ALWAYS, StencilOp failOp = STENCIL_OP_KEEP, StencilOp depthFailOp = STENCIL_OP_KEEP, StencilOp passOp = STENCIL_OP_KEEP) : + _functionAndOperations(func | (failOp << FAIL_OP_OFFSET) | (depthFailOp << DEPTH_FAIL_OP_OFFSET) | (passOp << PASS_OP_OFFSET)), + _reference(reference), _readMask(readMask) + {} + + ComparisonFunction getFunction() const { return ComparisonFunction(_functionAndOperations & FUNC_MASK); } + StencilOp getFailOp() const { return StencilOp((_functionAndOperations & FAIL_OP_MASK) >> FAIL_OP_OFFSET); } + StencilOp getDepthFailOp() const { return StencilOp((_functionAndOperations & DEPTH_FAIL_OP_MASK) >> DEPTH_FAIL_OP_OFFSET); } + StencilOp getPassOp() const { return StencilOp((_functionAndOperations & PASS_OP_MASK) >> PASS_OP_OFFSET); } + + uint8 getReference() const { return _reference; } + uint8 getReadMask() const { return _readMask; } + + int32 getRaw() const { return *(reinterpret_cast(this)); } + StencilTest(int32 raw) { *(reinterpret_cast(this)) = raw; } + bool operator== (const StencilTest& right) const { return getRaw() == right.getRaw(); } + bool operator!= (const StencilTest& right) const { return getRaw() != right.getRaw(); } + }; + + class StencilActivation { + uint8 _frontWriteMask = 0xFF; + uint8 _backWriteMask = 0xFF; + uint16 _enabled = 0; + public: + + StencilActivation(bool enabled, uint8 frontWriteMask = 0xFF, uint8 backWriteMask = 0xFF) : + _frontWriteMask(frontWriteMask), _backWriteMask(backWriteMask), _enabled(enabled) {} + + bool isEnabled() const { return (_enabled != 0); } + uint8 getWriteMaskFront() const { return _frontWriteMask; } + uint8 getWriteMaskBack() const { return _backWriteMask; } + + int32 getRaw() const { return *(reinterpret_cast(this)); } + StencilActivation(int32 raw) { *(reinterpret_cast(this)) = raw; } + bool operator== (const StencilActivation& right) const { return getRaw() == right.getRaw(); } + bool operator!= (const StencilActivation& right) const { return getRaw() != right.getRaw(); } + }; + + class BlendFunction { + static const int COLOR_MASK = 0x0f; + static const int ALPHA_MASK = 0xf0; + static const int ALPHA_OFFSET = 4; + + uint8 _enabled; + uint8 _source; + uint8 _destination; + uint8 _operation; + public: + + BlendFunction(bool enabled, + BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, + BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) : + _enabled(enabled), + _source(sourceColor | (sourceAlpha << ALPHA_OFFSET)), + _destination(destinationColor | (destinationAlpha << ALPHA_OFFSET)), + _operation(operationColor | (operationAlpha << ALPHA_OFFSET)) {} + + BlendFunction(bool enabled, BlendArg source = ONE, BlendOp operation = BLEND_OP_ADD, BlendArg destination = ZERO) : + _enabled(enabled), + _source(source | (source << ALPHA_OFFSET)), + _destination(destination | (destination << ALPHA_OFFSET)), + _operation(operation | (operation << ALPHA_OFFSET)) {} + + bool isEnabled() const { return (_enabled != 0); } + + BlendArg getSourceColor() const { return BlendArg(_source & COLOR_MASK); } + BlendArg getDestinationColor() const { return BlendArg(_destination & COLOR_MASK); } + BlendOp getOperationColor() const { return BlendOp(_operation & COLOR_MASK); } + + BlendArg getSourceAlpha() const { return BlendArg((_source & ALPHA_MASK) >> ALPHA_OFFSET); } + BlendArg getDestinationAlpha() const { return BlendArg((_destination & ALPHA_MASK) >> ALPHA_OFFSET); } + BlendOp getOperationAlpha() const { return BlendOp((_operation & ALPHA_MASK) >> ALPHA_OFFSET); } + + int32 getRaw() const { return *(reinterpret_cast(this)); } + BlendFunction(int32 raw) { *(reinterpret_cast(this)) = raw; } + bool operator== (const BlendFunction& right) const { return getRaw() == right.getRaw(); } + bool operator!= (const BlendFunction& right) const { return getRaw() != right.getRaw(); } + }; + + // The Data class is the full explicit description of the State class fields value. + // Useful for having one const static called Default for reference or for the gpu::Backend to keep track of the current value + class Data { + public: + float depthBias = 0.0f; + float depthBiasSlopeScale = 0.0f; + + DepthTest depthTest = DepthTest(false, true, LESS); + + StencilActivation stencilActivation = StencilActivation(false); + StencilTest stencilTestFront = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); + StencilTest stencilTestBack = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); + + uint32 sampleMask = 0xFFFFFFFF; + + BlendFunction blendFunction = BlendFunction(false); + + uint8 fillMode = FILL_FACE; + uint8 cullMode = CULL_NONE; + + uint8 colorWriteMask = WRITE_ALL; + + bool frontFaceClockwise : 1; + bool depthClampEnable : 1; + bool scissorEnable : 1; + bool multisampleEnable : 1; + bool antialisedLineEnable : 1; + bool alphaToCoverageEnable : 1; + + Data() : + frontFaceClockwise(false), + depthClampEnable(false), + scissorEnable(false), + multisampleEnable(false), + antialisedLineEnable(true), + alphaToCoverageEnable(false) + {} + }; + + // The unique default values for all the fields + static const Data DEFAULT; + void setFillMode(FillMode fill) { SET_FIELD(FILL_MODE, DEFAULT.fillMode, fill, _values.fillMode); } + FillMode getFillMode() const { return FillMode(_values.fillMode); } + + void setCullMode(CullMode cull) { SET_FIELD(CULL_MODE, DEFAULT.cullMode, cull, _values.cullMode); } + CullMode getCullMode() const { return CullMode(_values.cullMode); } + + void setFrontFaceClockwise(bool isClockwise) { SET_FIELD(FRONT_FACE_CLOCKWISE, DEFAULT.frontFaceClockwise, isClockwise, _values.frontFaceClockwise); } + bool isFrontFaceClockwise() const { return _values.frontFaceClockwise; } + + void setDepthClampEnable(bool enable) { SET_FIELD(DEPTH_CLAMP_ENABLE, DEFAULT.depthClampEnable, enable, _values.depthClampEnable); } + bool isDepthClampEnable() const { return _values.depthClampEnable; } + + void setScissorEnable(bool enable) { SET_FIELD(SCISSOR_ENABLE, DEFAULT.scissorEnable, enable, _values.scissorEnable); } + bool isScissorEnable() const { return _values.scissorEnable; } + + void setMultisampleEnable(bool enable) { SET_FIELD(MULTISAMPLE_ENABLE, DEFAULT.multisampleEnable, enable, _values.multisampleEnable); } + bool isMultisampleEnable() const { return _values.multisampleEnable; } + + void setAntialiasedLineEnable(bool enable) { SET_FIELD(ANTIALISED_LINE_ENABLE, DEFAULT.antialisedLineEnable, enable, _values.antialisedLineEnable); } + bool isAntialiasedLineEnable() const { return _values.antialisedLineEnable; } + + // Depth Bias + void setDepthBias(float bias) { SET_FIELD(DEPTH_BIAS, DEFAULT.depthBias, bias, _values.depthBias); } + float getDepthBias() const { return _values.depthBias; } + + void setDepthBiasSlopeScale(float scale) { SET_FIELD(DEPTH_BIAS_SLOPE_SCALE, DEFAULT.depthBiasSlopeScale, scale, _values.depthBiasSlopeScale); } + float getDepthBiasSlopeScale() const { return _values.depthBiasSlopeScale; } + + // Depth Test + void setDepthTest(DepthTest depthTest) { SET_FIELD(DEPTH_TEST, DEFAULT.depthTest, depthTest, _values.depthTest); } + void setDepthTest(bool enable, bool writeMask, ComparisonFunction func) { setDepthTest(DepthTest(enable, writeMask, func)); } + DepthTest getDepthTest() const { return _values.depthTest; } + + bool isDepthTestEnabled() const { return getDepthTest().isEnabled(); } + bool getDepthTestWriteMask() const { return getDepthTest().getWriteMask(); } + ComparisonFunction getDepthTestFunc() const { return getDepthTest().getFunction(); } + + // Stencil test + void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest, uint8 backWriteMask, StencilTest backTest) { + SET_FIELD(STENCIL_ACTIVATION, DEFAULT.stencilActivation, StencilActivation(enabled, frontWriteMask, backWriteMask), _values.stencilActivation); + SET_FIELD(STENCIL_TEST_FRONT, DEFAULT.stencilTestFront, frontTest, _values.stencilTestFront); + SET_FIELD(STENCIL_TEST_BACK, DEFAULT.stencilTestBack, backTest, _values.stencilTestBack); } + void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest) { + setStencilTest(enabled, frontWriteMask, frontTest, frontWriteMask, frontTest); } + + StencilActivation getStencilActivation() const { return _values.stencilActivation; } + StencilTest getStencilTestFront() const { return _values.stencilTestFront; } + StencilTest getStencilTestBack() const { return _values.stencilTestBack; } + + bool isStencilEnabled() const { return getStencilActivation().isEnabled(); } + uint8 getStencilWriteMaskFront() const { return getStencilActivation().getWriteMaskFront(); } + uint8 getStencilWriteMaskBack() const { return getStencilActivation().getWriteMaskBack(); } + + // Alpha to coverage + void setAlphaToCoverageEnable(bool enable) { SET_FIELD(ALPHA_TO_COVERAGE_ENABLE, DEFAULT.alphaToCoverageEnable, enable, _values.alphaToCoverageEnable); } + bool isAlphaToCoverageEnabled() const { return _values.alphaToCoverageEnable; } + + // Sample mask + void setSampleMask(uint32 mask) { SET_FIELD(SAMPLE_MASK, DEFAULT.sampleMask, mask, _values.sampleMask); } + uint32 getSampleMask() const { return _values.sampleMask; } + + // Blend Function + void setBlendFunction(BlendFunction function) { SET_FIELD(BLEND_FUNCTION, DEFAULT.blendFunction, function, _values.blendFunction); } + BlendFunction getBlendFunction() const { return _values.blendFunction; } + + void setBlendFunction(bool enabled, BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) { + setBlendFunction(BlendFunction(enabled, sourceColor, operationColor, destinationColor, sourceAlpha, operationAlpha, destinationAlpha)); } + void setBlendFunction(bool enabled, BlendArg source, BlendOp operation, BlendArg destination) { + setBlendFunction(BlendFunction(enabled, source, operation, destination)); } + + bool isBlendEnabled() const { return getBlendFunction().isEnabled(); } + + // Color write mask + void setColorWriteMask(uint8 mask) { SET_FIELD(COLOR_WRITE_MASK, DEFAULT.colorWriteMask, mask, _values.colorWriteMask); } + void setColorWriteMask(bool red, bool green, bool blue, bool alpha) { uint32 value = ((WRITE_RED * red) | (WRITE_GREEN * green) | (WRITE_BLUE * blue) | (WRITE_ALPHA * alpha)); SET_FIELD(COLOR_WRITE_MASK, DEFAULT.colorWriteMask, value, _values.colorWriteMask); } + uint8 getColorWriteMask() const { return _values.colorWriteMask; } + + // All the possible fields + enum Field { + FILL_MODE, + CULL_MODE, + FRONT_FACE_CLOCKWISE, + DEPTH_CLAMP_ENABLE, + SCISSOR_ENABLE, + MULTISAMPLE_ENABLE, + ANTIALISED_LINE_ENABLE, + + DEPTH_BIAS, + DEPTH_BIAS_SLOPE_SCALE, + + DEPTH_TEST, + + STENCIL_ACTIVATION, + STENCIL_TEST_FRONT, + STENCIL_TEST_BACK, + + SAMPLE_MASK, + ALPHA_TO_COVERAGE_ENABLE, + + BLEND_FUNCTION, + + COLOR_WRITE_MASK, + + NUM_FIELDS, // not a valid field, just the count + }; + + // The signature of the state tells which fields of the state are not default + // this way during rendering the Backend can compare it's current state and try to minimize the job to do + typedef std::bitset Signature; + + Signature getSignature() const { return _signature; } + + static Signature evalSignature(const Data& state); + + // For convenience, create a State from the values directly + State(const Data& values); + const Data& getValues() const { return _values; } + +protected: + State(const State& state); + State& operator=(const State& state); + + Data _values; + Signature _signature{0}; + Stamp _stamp{0}; + + // This shouldn't be used by anything else than the Backend class with the proper casting. + mutable GPUObject* _gpuObject = nullptr; + void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } + GPUObject* getGPUObject() const { return _gpuObject; } + friend class Backend; +}; + +typedef std::shared_ptr< State > StatePointer; +typedef std::vector< StatePointer > States; + +}; + +#endif From b25f6df7af349cfceb407ba20fe5d0d5efce29ab Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 11 Aug 2015 10:22:56 -0700 Subject: [PATCH 004/102] quiet compiler --- interface/src/avatar/AvatarManager.cpp | 2 +- libraries/gpu/src/gpu/State.h | 2 +- libraries/physics/src/ObjectActionSpring.cpp | 2 +- libraries/shared/src/PhysicsCollisionGroups.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index ee59a01e07..1644f22b09 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -279,7 +279,7 @@ void AvatarManager::handleCollisionEvents(CollisionEvents& collisionEvents) { const QString& collisionSoundURL = myAvatar->getCollisionSoundURL(); if (!collisionSoundURL.isEmpty()) { const float velocityChange = glm::length(collision.velocityChange); - const float MIN_AVATAR_COLLISION_ACCELERATION = 0.01; + const float MIN_AVATAR_COLLISION_ACCELERATION = 0.01f; const bool isSound = (collision.type == CONTACT_EVENT_TYPE_START) && (velocityChange > MIN_AVATAR_COLLISION_ACCELERATION); if (!isSound) { diff --git a/libraries/gpu/src/gpu/State.h b/libraries/gpu/src/gpu/State.h index 5e53284f36..1b4a02e301 100755 --- a/libraries/gpu/src/gpu/State.h +++ b/libraries/gpu/src/gpu/State.h @@ -125,7 +125,7 @@ public: bool isEnabled() const { return _enabled; } ComparisonFunction getFunction() const { return ComparisonFunction(_function); } - bool getWriteMask() const { return _writeMask; } + uint8 getWriteMask() const { return _writeMask; } int32 getRaw() const { return *(reinterpret_cast(this)); } DepthTest(int32 raw) { *(reinterpret_cast(this)) = raw; } diff --git a/libraries/physics/src/ObjectActionSpring.cpp b/libraries/physics/src/ObjectActionSpring.cpp index 196cc8d3ea..313b089d1c 100644 --- a/libraries/physics/src/ObjectActionSpring.cpp +++ b/libraries/physics/src/ObjectActionSpring.cpp @@ -92,7 +92,7 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) { // dQ = Q1 * Q0^ btQuaternion deltaQ = target * bodyRotation.inverse(); float angle = deltaQ.getAngle(); - const float MIN_ANGLE = 1.0e-4; + const float MIN_ANGLE = 1.0e-4f; if (angle > MIN_ANGLE) { targetVelocity = (angle / _angularTimeScale) * deltaQ.getAxis(); } diff --git a/libraries/shared/src/PhysicsCollisionGroups.h b/libraries/shared/src/PhysicsCollisionGroups.h index 08d83a29ca..42599a1b28 100644 --- a/libraries/shared/src/PhysicsCollisionGroups.h +++ b/libraries/shared/src/PhysicsCollisionGroups.h @@ -44,7 +44,7 @@ const int16_t COLLISION_GROUP_OTHER_AVATAR = 1 << 6; const int16_t COLLISION_GROUP_MY_ATTACHMENT = 1 << 7; const int16_t COLLISION_GROUP_OTHER_ATTACHMENT = 1 << 8; // ... -const int16_t COLLISION_GROUP_COLLISIONLESS = 1 << 15; +const int16_t COLLISION_GROUP_COLLISIONLESS = 1 << 14; /* Note: In order for objectA to collide with objectB at the filter stage From 804c1ecf8e2523545553b62da2d6587b883e63d0 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 11 Aug 2015 10:46:53 -0700 Subject: [PATCH 005/102] quiet compiler --- libraries/gpu/src/gpu/State.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/gpu/src/gpu/State.h b/libraries/gpu/src/gpu/State.h index 42177e74dc..7ab723ac63 100755 --- a/libraries/gpu/src/gpu/State.h +++ b/libraries/gpu/src/gpu/State.h @@ -125,7 +125,7 @@ public: bool isEnabled() const { return _enabled != 0; } ComparisonFunction getFunction() const { return ComparisonFunction(_function); } - bool getWriteMask() const { return _writeMask; } + uint8 getWriteMask() const { return _writeMask != 0; } int32 getRaw() const { return *(reinterpret_cast(this)); } DepthTest(int32 raw) { *(reinterpret_cast(this)) = raw; } @@ -301,7 +301,7 @@ public: DepthTest getDepthTest() const { return _values.depthTest; } bool isDepthTestEnabled() const { return getDepthTest().isEnabled(); } - bool getDepthTestWriteMask() const { return getDepthTest().getWriteMask(); } + uint8 getDepthTestWriteMask() const { return getDepthTest().getWriteMask(); } ComparisonFunction getDepthTestFunc() const { return getDepthTest().getFunction(); } // Stencil test From fedbfe88815d25b11e68e0963162549a398d38c0 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 11 Aug 2015 11:00:04 -0700 Subject: [PATCH 006/102] fix jumbled merge --- libraries/gpu/src/gpu/State.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/gpu/src/gpu/State.h b/libraries/gpu/src/gpu/State.h index 7ab723ac63..5500f20e06 100755 --- a/libraries/gpu/src/gpu/State.h +++ b/libraries/gpu/src/gpu/State.h @@ -125,7 +125,7 @@ public: bool isEnabled() const { return _enabled != 0; } ComparisonFunction getFunction() const { return ComparisonFunction(_function); } - uint8 getWriteMask() const { return _writeMask != 0; } + uint8 getWriteMask() const { return _writeMask; } int32 getRaw() const { return *(reinterpret_cast(this)); } DepthTest(int32 raw) { *(reinterpret_cast(this)) = raw; } From 4fe8f49d4ccd548641cf9c7a3fca61b254fe7378 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 11 Aug 2015 23:47:40 -0700 Subject: [PATCH 007/102] move origin to center of domain --- examples/edit.js | 8 ++++++-- interface/src/Util.cpp | 2 ++ libraries/entities/src/AddEntityOperator.cpp | 2 ++ libraries/entities/src/EntityItem.cpp | 13 +++++++++++-- libraries/entities/src/EntityItem.h | 1 + libraries/entities/src/EntityItemProperties.h | 2 +- libraries/entities/src/EntitySimulation.cpp | 6 ++++-- libraries/entities/src/EntityTreeElement.cpp | 8 ++++---- libraries/entities/src/MovingEntitiesOperator.cpp | 2 +- libraries/entities/src/UpdateEntityOperator.cpp | 4 ++-- libraries/networking/src/udt/PacketHeaders.h | 1 + libraries/octree/src/OctreeConstants.h | 3 ++- libraries/octree/src/OctreeElement.cpp | 5 +++-- 13 files changed, 40 insertions(+), 17 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 0f9c9fc4dd..4cc38a0c3d 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -1019,9 +1019,13 @@ function getPositionToCreateEntity() { var placementPosition = Vec3.sum(Camera.position, offset); var cameraPosition = Camera.position; + + var HALF_TREE_SCALE = 16384 / 2; - var cameraOutOfBounds = cameraPosition.x < 0 || cameraPosition.y < 0 || cameraPosition.z < 0; - var placementOutOfBounds = placementPosition.x < 0 || placementPosition.y < 0 || placementPosition.z < 0; + var cameraOutOfBounds = cameraPosition.x < -HALF_TREE_SCALE || cameraPosition.y < -HALF_TREE_SCALE || + cameraPosition.z < -HALF_TREE_SCALE; + var placementOutOfBounds = placementPosition.x < -HALF_TREE_SCALE || placementPosition.y < -HALF_TREE_SCALE || + placementPosition.z < -HALF_TREE_SCALE; if (cameraOutOfBounds && placementOutOfBounds) { return null; diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 3a01367fc7..f62a6b8fc5 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -43,6 +43,8 @@ void renderWorldBox(gpu::Batch& batch) { auto transform = Transform{}; batch.setModelTransform(transform); + + // FIXME - new origin tweaks need to be done to this geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(TREE_SCALE, 0.0f, 0.0f), red); geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, TREE_SCALE, 0.0f), green); geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, TREE_SCALE), blue); diff --git a/libraries/entities/src/AddEntityOperator.cpp b/libraries/entities/src/AddEntityOperator.cpp index b85d12c2da..db9a18a3e9 100644 --- a/libraries/entities/src/AddEntityOperator.cpp +++ b/libraries/entities/src/AddEntityOperator.cpp @@ -25,6 +25,8 @@ AddEntityOperator::AddEntityOperator(EntityTree* tree, { // caller must have verified existence of newEntity assert(_newEntity); + + // FIXME - how does this change for new origin??? _newEntityBox = _newEntity->getMaximumAACube().clamp(0.0f, (float)TREE_SCALE); } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 205d1c339e..97704985aa 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -634,7 +634,11 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // but since we're using macros below we have to temporarily modify overwriteLocalData. bool oldOverwrite = overwriteLocalData; overwriteLocalData = overwriteLocalData && !weOwnSimulation; - READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition); + if (args.bitstreamVersion >= VERSION_ENTITIES_CENTER_ORIGIN) { + READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition); + } else { + READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePositionOldOrigin); + } READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation); READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocity); READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity); @@ -656,7 +660,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef } else { // legacy order of packing here // TODO: purge this logic in a few months from now (2015.07) - READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition); + READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePositionOldOrigin); READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions); READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation); READ_ENTITY_PROPERTY(PROP_DENSITY, float, updateDensity); @@ -1307,6 +1311,11 @@ void EntityItem::updatePosition(const glm::vec3& value) { } } +void EntityItem::updatePositionOldOrigin(const glm::vec3& value) { + glm::vec3 newValue = value - glm::vec3(HALF_TREE_SCALE); + updatePosition(newValue); +} + void EntityItem::updateDimensions(const glm::vec3& value) { auto delta = glm::distance(getDimensions(), value); if (delta > IGNORE_DIMENSIONS_DELTA) { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 57f8883cea..12e6c1b3e7 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -361,6 +361,7 @@ public: // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags void updatePosition(const glm::vec3& value); + void updatePositionOldOrigin(const glm::vec3& value); void updateDimensions(const glm::vec3& value); void updateRotation(const glm::quat& rotation); void updateDensity(float value); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 8085c24d90..1e8cf51ef3 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -253,7 +253,7 @@ void EntityItemPropertiesFromScriptValueHonorReadOnly(const QScriptValue &object // define these inline here so the macros work inline void EntityItemProperties::setPosition(const glm::vec3& value) - { _position = glm::clamp(value, 0.0f, (float)TREE_SCALE); _positionChanged = true; } + { _position = glm::clamp(value, (float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); _positionChanged = true; } inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { debug << "EntityItemProperties[" << "\n"; diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index f2bd1e873e..c614b62c91 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -113,7 +113,8 @@ void EntitySimulation::sortEntitiesThatMoved() { // External changes to entity position/shape are expected to be sorted outside of the EntitySimulation. PerformanceTimer perfTimer("sortingEntities"); MovingEntitiesOperator moveOperator(_entityTree); - AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), (float)TREE_SCALE); + AACube domainBounds(glm::vec3((float)-HALF_TREE_SCALE, (float)-HALF_TREE_SCALE, (float)-HALF_TREE_SCALE), + (float)TREE_SCALE); SetOfEntities::iterator itemItr = _entitiesToSort.begin(); while (itemItr != _entitiesToSort.end()) { EntityItemPointer entity = *itemItr; @@ -195,7 +196,8 @@ void EntitySimulation::changeEntity(EntityItemPointer entity) { bool wasRemoved = false; uint32_t dirtyFlags = entity->getDirtyFlags(); if (dirtyFlags & EntityItem::DIRTY_POSITION) { - AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), (float)TREE_SCALE); + AACube domainBounds(glm::vec3((float)-HALF_TREE_SCALE, (float)-HALF_TREE_SCALE, (float)-HALF_TREE_SCALE), + (float)TREE_SCALE); AACube newCube = entity->getMaximumAACube(); if (!domainBounds.touches(newCube)) { qCDebug(entities) << "Entity " << entity->getEntityItemID() << " moved out of domain bounds."; diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 856550f297..a023f46c5e 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -444,14 +444,14 @@ bool EntityTreeElement::bestFitBounds(const AABox& bounds) const { } bool EntityTreeElement::containsBounds(const glm::vec3& minPoint, const glm::vec3& maxPoint) const { - glm::vec3 clampedMin = glm::clamp(minPoint, 0.0f, (float)TREE_SCALE); - glm::vec3 clampedMax = glm::clamp(maxPoint, 0.0f, (float)TREE_SCALE); + glm::vec3 clampedMin = glm::clamp(minPoint, (float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); + glm::vec3 clampedMax = glm::clamp(maxPoint, (float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); return _cube.contains(clampedMin) && _cube.contains(clampedMax); } bool EntityTreeElement::bestFitBounds(const glm::vec3& minPoint, const glm::vec3& maxPoint) const { - glm::vec3 clampedMin = glm::clamp(minPoint, 0.0f, (float)TREE_SCALE); - glm::vec3 clampedMax = glm::clamp(maxPoint, 0.0f, (float)TREE_SCALE); + glm::vec3 clampedMin = glm::clamp(minPoint, (float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); + glm::vec3 clampedMax = glm::clamp(maxPoint, (float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); if (_cube.contains(clampedMin) && _cube.contains(clampedMax)) { diff --git a/libraries/entities/src/MovingEntitiesOperator.cpp b/libraries/entities/src/MovingEntitiesOperator.cpp index ddfea13d07..7dd1ab849c 100644 --- a/libraries/entities/src/MovingEntitiesOperator.cpp +++ b/libraries/entities/src/MovingEntitiesOperator.cpp @@ -52,7 +52,7 @@ MovingEntitiesOperator::~MovingEntitiesOperator() { void MovingEntitiesOperator::addEntityToMoveList(EntityItemPointer entity, const AACube& newCube) { EntityTreeElement* oldContainingElement = _tree->getContainingElement(entity->getEntityItemID()); - AABox newCubeClamped = newCube.clamp(0.0f, (float)TREE_SCALE); + AABox newCubeClamped = newCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); if (_wantDebug) { qCDebug(entities) << "MovingEntitiesOperator::addEntityToMoveList() -----------------------------"; diff --git a/libraries/entities/src/UpdateEntityOperator.cpp b/libraries/entities/src/UpdateEntityOperator.cpp index 6720839da0..991d725f97 100644 --- a/libraries/entities/src/UpdateEntityOperator.cpp +++ b/libraries/entities/src/UpdateEntityOperator.cpp @@ -47,7 +47,7 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree, // which can handle all potential rotations? // the getMaximumAACube is the relaxed form. _oldEntityCube = _existingEntity->getMaximumAACube(); - _oldEntityBox = _oldEntityCube.clamp(0.0f, (float)TREE_SCALE); // clamp to domain bounds + _oldEntityBox = _oldEntityCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); // clamp to domain bounds // If the old properties doesn't contain the properties required to calculate a bounding box, // get them from the existing entity. Registration point is required to correctly calculate @@ -123,7 +123,7 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree, } } - _newEntityBox = _newEntityCube.clamp(0.0f, (float)TREE_SCALE); // clamp to domain bounds + _newEntityBox = _newEntityCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); // clamp to domain bounds if (_wantDebug) { diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 1aeadb1af9..613ea4913d 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -142,5 +142,6 @@ const PacketVersion VERSION_ENTITIES_HAVE_SIMULATION_OWNER_AND_ACTIONS_OVER_WIRE const PacketVersion VERSION_ENTITIES_NEW_PROTOCOL_LAYER = 35; const PacketVersion VERSION_POLYVOX_TEXTURES = 36; const PacketVersion VERSION_ENTITIES_POLYLINE = 37; +const PacketVersion VERSION_ENTITIES_CENTER_ORIGIN = 38; #endif // hifi_PacketHeaders_h \ No newline at end of file diff --git a/libraries/octree/src/OctreeConstants.h b/libraries/octree/src/OctreeConstants.h index 4a1baea2d5..acfa1d14c6 100644 --- a/libraries/octree/src/OctreeConstants.h +++ b/libraries/octree/src/OctreeConstants.h @@ -17,7 +17,8 @@ const quint64 CHANGE_FUDGE = 1000 * 200; // useconds of fudge in determining if we want to resend changed voxels -const int TREE_SCALE = 16384; // ~10 miles.. This is the number of meters of the 0.0 to 1.0 voxel universe +const int TREE_SCALE = 16384; // ~10 miles.. This is the number of meters of the 0.0 to 1.0 voxel universe +const int HALF_TREE_SCALE = TREE_SCALE / 2; // This controls the LOD. Larger number will make smaller voxels visible at greater distance. const float DEFAULT_OCTREE_SIZE_SCALE = TREE_SCALE * 400.0f; diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 85ea0caef0..2bbacccf95 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -191,6 +191,7 @@ void OctreeElement::calculateAACube() { // this tells you the "size" of the voxel float voxelScale = (float)TREE_SCALE / powf(2.0f, numberOfThreeBitSectionsInCode(getOctalCode())); corner *= (float)TREE_SCALE; + corner -= (float)HALF_TREE_SCALE; _cube.setBox(corner, voxelScale); } @@ -717,8 +718,8 @@ int OctreeElement::getMyChildContaining(const AACube& cube) const { } // Determine which of our children the minimum and maximum corners of the cube live in... - glm::vec3 cubeCornerMinimum = glm::clamp(cube.getCorner(), 0.0f, (float)TREE_SCALE); - glm::vec3 cubeCornerMaximum = glm::clamp(cube.calcTopFarLeft(), 0.0f, (float)TREE_SCALE); + glm::vec3 cubeCornerMinimum = glm::clamp(cube.getCorner(), (float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); + glm::vec3 cubeCornerMaximum = glm::clamp(cube.calcTopFarLeft(), (float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); if (_cube.contains(cubeCornerMinimum) && _cube.contains(cubeCornerMaximum)) { int childIndexCubeMinimum = getMyChildContainingPoint(cubeCornerMinimum); From 85603dab29a622d208b4030858ed1e8df36eb4f5 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 11 Aug 2015 23:51:07 -0700 Subject: [PATCH 008/102] bump entity packet version --- libraries/networking/src/udt/PacketHeaders.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 0146abdb7c..d2b116a9d5 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -67,7 +67,7 @@ PacketVersion versionForPacketType(PacketType::Value packetType) { case EntityAdd: case EntityEdit: case EntityData: - return VERSION_ENTITIES_POLYLINE; + return VERSION_ENTITIES_CENTER_ORIGIN; default: return 11; } From ea834609c2cb6c28198b2417e916f58a37529274 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 13 Aug 2015 10:33:31 -0700 Subject: [PATCH 009/102] Kill the AvatarAppearanceDialog and rewire necessary parts of PreferencesDialog. --- interface/src/ui/AvatarAppearanceDialog.cpp | 215 --------- interface/src/ui/AvatarAppearanceDialog.h | 64 --- interface/src/ui/DialogsManager.cpp | 10 - interface/src/ui/DialogsManager.h | 3 - interface/src/ui/PreferencesDialog.cpp | 38 +- interface/src/ui/PreferencesDialog.h | 5 +- interface/ui/avatarAppearance.ui | 471 -------------------- interface/ui/preferencesDialog.ui | 5 - 8 files changed, 32 insertions(+), 779 deletions(-) delete mode 100644 interface/src/ui/AvatarAppearanceDialog.cpp delete mode 100644 interface/src/ui/AvatarAppearanceDialog.h delete mode 100644 interface/ui/avatarAppearance.ui diff --git a/interface/src/ui/AvatarAppearanceDialog.cpp b/interface/src/ui/AvatarAppearanceDialog.cpp deleted file mode 100644 index 54e48dca26..0000000000 --- a/interface/src/ui/AvatarAppearanceDialog.cpp +++ /dev/null @@ -1,215 +0,0 @@ -// -// AvatarAppearanceDialog.cpp -// interface/src/ui -// -// Created by Stojce Slavkovski on 2/20/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 -#include - -#include -#include -#include -#include - -#include "Application.h" -#include "MainWindow.h" -#include "LODManager.h" -#include "Menu.h" -#include "AvatarAppearanceDialog.h" -#include "Snapshot.h" -#include "UserActivityLogger.h" -#include "UIUtil.h" -#include "ui/DialogsManager.h" -#include "ui/PreferencesDialog.h" - -AvatarAppearanceDialog::AvatarAppearanceDialog(QWidget* parent) : - QDialog(parent) { - - setAttribute(Qt::WA_DeleteOnClose); - - ui.setupUi(this); - - loadAvatarAppearance(); - - connect(ui.defaultButton, &QPushButton::clicked, this, &AvatarAppearanceDialog::accept); - - connect(ui.buttonBrowseHead, &QPushButton::clicked, this, &AvatarAppearanceDialog::openHeadModelBrowser); - connect(ui.buttonBrowseBody, &QPushButton::clicked, this, &AvatarAppearanceDialog::openBodyModelBrowser); - connect(ui.buttonBrowseFullAvatar, &QPushButton::clicked, this, &AvatarAppearanceDialog::openFullAvatarModelBrowser); - - connect(ui.useSeparateBodyAndHead, &QRadioButton::clicked, this, &AvatarAppearanceDialog::useSeparateBodyAndHead); - connect(ui.useFullAvatar, &QRadioButton::clicked, this, &AvatarAppearanceDialog::useFullAvatar); - - connect(Application::getInstance(), &Application::headURLChanged, this, &AvatarAppearanceDialog::headURLChanged); - connect(Application::getInstance(), &Application::bodyURLChanged, this, &AvatarAppearanceDialog::bodyURLChanged); - connect(Application::getInstance(), &Application::fullAvatarURLChanged, this, &AvatarAppearanceDialog::fullAvatarURLChanged); - - auto myAvatar = DependencyManager::get()->getMyAvatar(); - - ui.bodyNameLabel->setText("Body - " + myAvatar->getBodyModelName()); - ui.headNameLabel->setText("Head - " + myAvatar->getHeadModelName()); - ui.fullAvatarNameLabel->setText("Full Avatar - " + myAvatar->getFullAvartarModelName()); - - UIUtil::scaleWidgetFontSizes(this); -} - -void AvatarAppearanceDialog::useSeparateBodyAndHead(bool checked) { - QUrl headURL(ui.faceURLEdit->text()); - QUrl bodyURL(ui.skeletonURLEdit->text()); - DependencyManager::get()->getMyAvatar()->useHeadAndBodyURLs(headURL, bodyURL); - setUseFullAvatar(!checked); -} - -void AvatarAppearanceDialog::useFullAvatar(bool checked) { - QUrl fullAvatarURL(ui.fullAvatarURLEdit->text()); - DependencyManager::get()->getMyAvatar()->useFullAvatarURL(fullAvatarURL); - setUseFullAvatar(checked); -} - -void AvatarAppearanceDialog::setUseFullAvatar(bool useFullAvatar) { - _useFullAvatar = useFullAvatar; - ui.faceURLEdit->setEnabled(!_useFullAvatar); - ui.skeletonURLEdit->setEnabled(!_useFullAvatar); - ui.fullAvatarURLEdit->setEnabled(_useFullAvatar); - - ui.useFullAvatar->setChecked(_useFullAvatar); - ui.useSeparateBodyAndHead->setChecked(!_useFullAvatar); - - QPointer prefs = DependencyManager::get()->getPreferencesDialog(); - if (prefs) { // Preferences dialog may have been closed - prefs->avatarDescriptionChanged(); - } -} - -void AvatarAppearanceDialog::headURLChanged(const QString& newValue, const QString& modelName) { - ui.faceURLEdit->setText(newValue); - setUseFullAvatar(false); - ui.headNameLabel->setText("Head - " + modelName); -} - -void AvatarAppearanceDialog::bodyURLChanged(const QString& newValue, const QString& modelName) { - ui.skeletonURLEdit->setText(newValue); - setUseFullAvatar(false); - ui.bodyNameLabel->setText("Body - " + modelName); -} - -void AvatarAppearanceDialog::fullAvatarURLChanged(const QString& newValue, const QString& modelName) { - ui.fullAvatarURLEdit->setText(newValue); - setUseFullAvatar(true); - ui.fullAvatarNameLabel->setText("Full Avatar - " + modelName); -} - -void AvatarAppearanceDialog::accept() { - saveAvatarAppearance(); - - QPointer prefs = DependencyManager::get()->getPreferencesDialog(); - if (prefs) { // Preferences dialog may have been closed - prefs->avatarDescriptionChanged(); - } - - close(); - delete _marketplaceWindow; - _marketplaceWindow = NULL; -} - -void AvatarAppearanceDialog::setHeadUrl(QString modelUrl) { - ui.faceURLEdit->setText(modelUrl); -} - -void AvatarAppearanceDialog::setSkeletonUrl(QString modelUrl) { - ui.skeletonURLEdit->setText(modelUrl); -} - -void AvatarAppearanceDialog::openFullAvatarModelBrowser() { - auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars"; - auto WIDTH = 900; - auto HEIGHT = 700; - if (!_marketplaceWindow) { - _marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false); - } - _marketplaceWindow->setVisible(true); -} - -void AvatarAppearanceDialog::openHeadModelBrowser() { - auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars"; - auto WIDTH = 900; - auto HEIGHT = 700; - if (!_marketplaceWindow) { - _marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false); - } - _marketplaceWindow->setVisible(true); -} - -void AvatarAppearanceDialog::openBodyModelBrowser() { - auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars"; - auto WIDTH = 900; - auto HEIGHT = 700; - if (!_marketplaceWindow) { - _marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false); - } - _marketplaceWindow->setVisible(true); -} - -void AvatarAppearanceDialog::resizeEvent(QResizeEvent *resizeEvent) { - - // keep buttons panel at the bottom - ui.buttonsPanel->setGeometry(0, - size().height() - ui.buttonsPanel->height(), - size().width(), - ui.buttonsPanel->height()); - - // set width and height of srcollarea to match bottom panel and width - ui.scrollArea->setGeometry(ui.scrollArea->geometry().x(), ui.scrollArea->geometry().y(), - size().width(), - size().height() - ui.buttonsPanel->height() - ui.scrollArea->geometry().y()); - -} - -void AvatarAppearanceDialog::loadAvatarAppearance() { - - MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); - - _useFullAvatar = myAvatar->getUseFullAvatar(); - _fullAvatarURLString = myAvatar->getFullAvatarURLFromPreferences().toString(); - _headURLString = myAvatar->getHeadURLFromPreferences().toString(); - _bodyURLString = myAvatar->getBodyURLFromPreferences().toString(); - - ui.fullAvatarURLEdit->setText(_fullAvatarURLString); - ui.faceURLEdit->setText(_headURLString); - ui.skeletonURLEdit->setText(_bodyURLString); - setUseFullAvatar(_useFullAvatar); -} - -void AvatarAppearanceDialog::saveAvatarAppearance() { - - MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); - - QUrl headURL(ui.faceURLEdit->text()); - QString headURLString = headURL.toString(); - - QUrl bodyURL(ui.skeletonURLEdit->text()); - QString bodyURLString = bodyURL.toString(); - - QUrl fullAvatarURL(ui.fullAvatarURLEdit->text()); - QString fullAvatarURLString = fullAvatarURL.toString(); - - bool somethingChanged = - _useFullAvatar != myAvatar->getUseFullAvatar() || - fullAvatarURLString != myAvatar->getFullAvatarURLFromPreferences().toString() || - headURLString != myAvatar->getHeadURLFromPreferences().toString() || - bodyURLString != myAvatar->getBodyURLFromPreferences().toString(); - - if (somethingChanged) { - if (_useFullAvatar) { - myAvatar->useFullAvatarURL(fullAvatarURL); - } else { - myAvatar->useHeadAndBodyURLs(headURL, bodyURL); - } - } -} diff --git a/interface/src/ui/AvatarAppearanceDialog.h b/interface/src/ui/AvatarAppearanceDialog.h deleted file mode 100644 index be30caeedb..0000000000 --- a/interface/src/ui/AvatarAppearanceDialog.h +++ /dev/null @@ -1,64 +0,0 @@ -// -// AvatarAppearanceDialog.h -// interface/src/ui -// -// Created by Stojce Slavkovski on 2/20/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_AvatarAppearanceDialog_h -#define hifi_AvatarAppearanceDialog_h - -#include "ui_avatarAppearance.h" - -#include -#include - -#include "scripting/WebWindowClass.h" - -class AvatarAppearanceDialog : public QDialog { - Q_OBJECT - -public: - AvatarAppearanceDialog(QWidget* parent = nullptr); - -protected: - void resizeEvent(QResizeEvent* resizeEvent); - -private: - void loadAvatarAppearance(); - void saveAvatarAppearance(); - void openHeadModelBrowser(); - void openBodyModelBrowser(); - void openFullAvatarModelBrowser(); - void setUseFullAvatar(bool useFullAvatar); - - Ui_AvatarAppearanceDialog ui; - - bool _useFullAvatar; - QString _headURLString; - QString _bodyURLString; - QString _fullAvatarURLString; - - - QString _displayNameString; - - WebWindowClass* _marketplaceWindow = NULL; - -private slots: - void accept(); - void setHeadUrl(QString modelUrl); - void setSkeletonUrl(QString modelUrl); - void headURLChanged(const QString& newValue, const QString& modelName); - void bodyURLChanged(const QString& newValue, const QString& modelName); - void fullAvatarURLChanged(const QString& newValue, const QString& modelName); - void useSeparateBodyAndHead(bool checked); - void useFullAvatar(bool checked); - - -}; - -#endif // hifi_AvatarAppearanceDialog_h diff --git a/interface/src/ui/DialogsManager.cpp b/interface/src/ui/DialogsManager.cpp index ac5e6833fb..d8671f9798 100644 --- a/interface/src/ui/DialogsManager.cpp +++ b/interface/src/ui/DialogsManager.cpp @@ -20,7 +20,6 @@ #include "AddressBarDialog.h" #include "AnimationsDialog.h" #include "AttachmentsDialog.h" -#include "AvatarAppearanceDialog.h" #include "BandwidthDialog.h" #include "CachesSizeDialog.h" #include "DiskCacheEditor.h" @@ -88,15 +87,6 @@ void DialogsManager::editPreferences() { } } -void DialogsManager::changeAvatarAppearance() { - if (!_avatarAppearanceDialog) { - maybeCreateDialog(_avatarAppearanceDialog); - _avatarAppearanceDialog->show(); - } else { - _avatarAppearanceDialog->close(); - } -} - void DialogsManager::editAttachments() { if (!_attachmentsDialog) { maybeCreateDialog(_attachmentsDialog); diff --git a/interface/src/ui/DialogsManager.h b/interface/src/ui/DialogsManager.h index 09e0274d86..2db700e72a 100644 --- a/interface/src/ui/DialogsManager.h +++ b/interface/src/ui/DialogsManager.h @@ -34,7 +34,6 @@ class OctreeStatsDialog; class PreferencesDialog; class ScriptEditorWindow; class QMessageBox; -class AvatarAppearanceDialog; class DomainConnectionDialog; class UpdateDialog; @@ -66,7 +65,6 @@ public slots: void hmdTools(bool showTools); void showScriptEditor(); void showIRCLink(); - void changeAvatarAppearance(); void showDomainConnectionDialog(); // Application Update @@ -110,7 +108,6 @@ private: QPointer _octreeStatsDialog; QPointer _preferencesDialog; QPointer _scriptEditor; - QPointer _avatarAppearanceDialog; QPointer _domainConnectionDialog; QPointer _updateDialog; }; diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 8e9c164563..cec379c596 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -47,23 +47,25 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) : connect(ui.buttonBrowseScriptsLocation, &QPushButton::clicked, this, &PreferencesDialog::openScriptsLocationBrowser); connect(ui.buttonReloadDefaultScripts, &QPushButton::clicked, Application::getInstance(), &Application::loadDefaultScripts); - DialogsManager* dialogsManager = DependencyManager::get().data(); - connect(ui.buttonChangeApperance, &QPushButton::clicked, dialogsManager, &DialogsManager::changeAvatarAppearance); + //FIXME remove DialogsManager* dialogsManager = DependencyManager::get().data(); + //FIXME remove connect(ui.buttonChangeApperance, &QPushButton::clicked, dialogsManager, &DialogsManager::changeAvatarAppearance); + connect(ui.buttonChangeApperance, &QPushButton::clicked, this, &PreferencesDialog::openFullAvatarModelBrowser); + connect(ui.apperanceDescription, &QLineEdit::textChanged, this, [this](const QString& url) { + this->fullAvatarURLChanged(url, ""); + }); - connect(Application::getInstance(), &Application::headURLChanged, this, &PreferencesDialog::headURLChanged); - connect(Application::getInstance(), &Application::bodyURLChanged, this, &PreferencesDialog::bodyURLChanged); + //FIXME remove connect(Application::getInstance(), &Application::headURLChanged, this, &PreferencesDialog::headURLChanged); + //FIXME remove connect(Application::getInstance(), &Application::bodyURLChanged, this, &PreferencesDialog::bodyURLChanged); connect(Application::getInstance(), &Application::fullAvatarURLChanged, this, &PreferencesDialog::fullAvatarURLChanged); // move dialog to left side move(parentWidget()->geometry().topLeft()); setFixedHeight(parentWidget()->size().height() - PREFERENCES_HEIGHT_PADDING); - ui.apperanceDescription->setText(DependencyManager::get()->getMyAvatar()->getModelDescription()); - UIUtil::scaleWidgetFontSizes(this); } -void PreferencesDialog::avatarDescriptionChanged() { +/*FIXME remove void PreferencesDialog::avatarDescriptionChanged() { ui.apperanceDescription->setText(DependencyManager::get()->getMyAvatar()->getModelDescription()); } @@ -74,9 +76,13 @@ void PreferencesDialog::headURLChanged(const QString& newValue, const QString& m void PreferencesDialog::bodyURLChanged(const QString& newValue, const QString& modelName) { ui.apperanceDescription->setText(DependencyManager::get()->getMyAvatar()->getModelDescription()); } - +*/ void PreferencesDialog::fullAvatarURLChanged(const QString& newValue, const QString& modelName) { - ui.apperanceDescription->setText(DependencyManager::get()->getMyAvatar()->getModelDescription()); + //FIXME remove ui.apperanceDescription->setText(DependencyManager::get()->getMyAvatar()->getModelDescription()); + ui.apperanceDescription->setText(newValue); + const QString APPEARANCE_LABEL_TEXT("Appearance: "); + ui.appearanceLabel->setText(APPEARANCE_LABEL_TEXT + modelName); + DependencyManager::get()->getMyAvatar()->useFullAvatarURL(newValue, modelName); } void PreferencesDialog::accept() { @@ -103,6 +109,16 @@ void PreferencesDialog::openScriptsLocationBrowser() { ui.scriptsLocationEdit->setText(dir); } } +void PreferencesDialog::openFullAvatarModelBrowser() { + const auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars"; + const auto WIDTH = 900; + const auto HEIGHT = 700; + if (!_marketplaceWindow) { + _marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false); + } + _marketplaceWindow->setVisible(true); + +} void PreferencesDialog::resizeEvent(QResizeEvent *resizeEvent) { @@ -129,6 +145,9 @@ void PreferencesDialog::loadPreferences() { ui.collisionSoundURLEdit->setText(myAvatar->getCollisionSoundURL()); + fullAvatarURLChanged(myAvatar->getFullAvatarURLFromPreferences().toString(), + myAvatar->getFullAvartarModelName()); + ui.sendDataCheckBox->setChecked(!menuInstance->isOptionChecked(MenuOption::DisableActivityLogger)); ui.snapshotLocationEdit->setText(Snapshot::snapshotsLocation.get()); @@ -210,6 +229,7 @@ void PreferencesDialog::savePreferences() { } myAvatar->setCollisionSoundURL(ui.collisionSoundURLEdit->text()); + // avatar model url is already persisted by fullAvatarURLChanged() if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableActivityLogger) != ui.sendDataCheckBox->isChecked()) { diff --git a/interface/src/ui/PreferencesDialog.h b/interface/src/ui/PreferencesDialog.h index 8e699c80a2..6cdb4deba1 100644 --- a/interface/src/ui/PreferencesDialog.h +++ b/interface/src/ui/PreferencesDialog.h @@ -42,10 +42,11 @@ private: private slots: void accept(); + void openFullAvatarModelBrowser(); void openSnapshotLocationBrowser(); void openScriptsLocationBrowser(); - void headURLChanged(const QString& newValue, const QString& modelName); - void bodyURLChanged(const QString& newValue, const QString& modelName); + /* FIXME remove void headURLChanged(const QString& newValue, const QString& modelName); + void bodyURLChanged(const QString& newValue, const QString& modelName);*/ void fullAvatarURLChanged(const QString& newValue, const QString& modelName); }; diff --git a/interface/ui/avatarAppearance.ui b/interface/ui/avatarAppearance.ui deleted file mode 100644 index 5ebf2c705b..0000000000 --- a/interface/ui/avatarAppearance.ui +++ /dev/null @@ -1,471 +0,0 @@ - - - AvatarAppearanceDialog - - - - 0 - 0 - 500 - 350 - - - - - 0 - 0 - - - - - 500 - 350 - - - - - 500 - 16777215 - - - - - 13 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - QFrame::NoFrame - - - QFrame::Plain - - - 0 - - - true - - - - - 0 - -107 - 485 - 1550 - - - - - 0 - - - 30 - - - 0 - - - 30 - - - 10 - - - - - - - 0 - - - 7 - - - 7 - - - - - - - - - Arial - - - - Use single avatar with Body and Head - - - - - - - - - - 0 - - - 10 - - - 0 - - - 0 - - - - - - - - Arial - - - - Full Avatar - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - fullAvatarURLEdit - - - - - - - - - - - - 0 - 0 - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 5 - 0 - - - - - - - - - - Arial - - - - Browse - - - - 0 - 0 - - - - - - - - - - - - - - - - - - - - - - - - Arial - - - - Use separate Body and Head avatar files - - - - - - - - - 0 - - - 10 - - - 7 - - - 7 - - - - - - - - - Arial - - - - Head - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - - - - - - - - 0 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 5 - 20 - - - - - - - - - Arial - - - - Browse - - - - 0 - 0 - - - - - - - - - - - - - - - 0 - - - 10 - - - 7 - - - 7 - - - - - - - Arial - - - - Body - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - skeletonURLEdit - - - - - - - - 0 - - - - - - 0 - 0 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 5 - 20 - - - - - - - - - Arial - - - - Browse - - - - 0 - 0 - - - - - - - - - - - - - - - - - - - - - - - - QFrame::NoFrame - - - QFrame::Raised - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - Arial - - - - Close - - - true - - - false - - - - - - - - - - - - diff --git a/interface/ui/preferencesDialog.ui b/interface/ui/preferencesDialog.ui index df6d28c07b..71103da654 100644 --- a/interface/ui/preferencesDialog.ui +++ b/interface/ui/preferencesDialog.ui @@ -294,11 +294,6 @@ Arial - - - false - - From 62941c09140feeffcbe3e7ceb72efac1f024305f Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 13 Aug 2015 12:39:30 -0700 Subject: [PATCH 010/102] Remove dead code. --- interface/src/Application.cpp | 27 +---- interface/src/avatar/Avatar.cpp | 13 +-- interface/src/avatar/Avatar.h | 2 - interface/src/avatar/MyAvatar.cpp | 142 +------------------------ interface/src/avatar/MyAvatar.h | 24 +---- interface/src/ui/PreferencesDialog.cpp | 18 ---- interface/src/ui/PreferencesDialog.h | 2 - libraries/avatars/src/AvatarData.cpp | 2 +- libraries/avatars/src/AvatarData.h | 7 +- 9 files changed, 12 insertions(+), 225 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index dba2ed3234..5dac571045 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3896,23 +3896,12 @@ bool Application::askToSetAvatarUrl(const QString& url) { QMessageBox msgBox; msgBox.setIcon(QMessageBox::Question); msgBox.setWindowTitle("Set Avatar"); - QPushButton* headButton = NULL; - QPushButton* bodyButton = NULL; QPushButton* bodyAndHeadButton = NULL; QString modelName = fstMapping["name"].toString(); QString message; QString typeInfo; switch (modelType) { - case FSTReader::HEAD_MODEL: - message = QString("Would you like to use '") + modelName + QString("' for your avatar head?"); - headButton = msgBox.addButton(tr("Yes"), QMessageBox::ActionRole); - break; - - case FSTReader::BODY_ONLY_MODEL: - message = QString("Would you like to use '") + modelName + QString("' for your avatar body?"); - bodyButton = msgBox.addButton(tr("Yes"), QMessageBox::ActionRole); - break; case FSTReader::HEAD_AND_BODY_MODEL: message = QString("Would you like to use '") + modelName + QString("' for your avatar?"); @@ -3920,10 +3909,7 @@ bool Application::askToSetAvatarUrl(const QString& url) { break; default: - message = QString("Would you like to use '") + modelName + QString("' for some part of your avatar head?"); - headButton = msgBox.addButton(tr("Use for Head"), QMessageBox::ActionRole); - bodyButton = msgBox.addButton(tr("Use for Body"), QMessageBox::ActionRole); - bodyAndHeadButton = msgBox.addButton(tr("Use for Body and Head"), QMessageBox::ActionRole); + message = QString(modelName + QString("Does not support a head and body as required.")); break; } @@ -3932,14 +3918,7 @@ bool Application::askToSetAvatarUrl(const QString& url) { msgBox.exec(); - if (msgBox.clickedButton() == headButton) { - _myAvatar->useHeadURL(url, modelName); - emit headURLChanged(url, modelName); - } else if (msgBox.clickedButton() == bodyButton) { - _myAvatar->useBodyURL(url, modelName); - emit bodyURLChanged(url, modelName); - } else if (msgBox.clickedButton() == bodyAndHeadButton) { - _myAvatar->useFullAvatarURL(url, modelName); + if (msgBox.clickedButton() == bodyAndHeadButton) { emit fullAvatarURLChanged(url, modelName); } else { qCDebug(interfaceapp) << "Declined to use the avatar: " << url; @@ -4426,7 +4405,7 @@ void Application::checkSkeleton() { msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); - _myAvatar->useBodyURL(DEFAULT_BODY_MODEL_URL, "Default"); + _myAvatar->useFullAvatarURL(DEFAULT_FULL_AVATAR_MODEL_URL, DEFAULT_FULL_AVATAR_MODEL_NAME); } else { _physicsEngine.setCharacterController(_myAvatar->getCharacterController()); } diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 8ba58217c3..b537d5a5d8 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -953,20 +952,12 @@ void Avatar::scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const { void Avatar::setFaceModelURL(const QUrl& faceModelURL) { AvatarData::setFaceModelURL(faceModelURL); - const QUrl DEFAULT_FACE_MODEL_URL = QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_head.fst"); - getHead()->getFaceModel().setURL(_faceModelURL, DEFAULT_FACE_MODEL_URL, true, !isMyAvatar()); + getHead()->getFaceModel().setURL(_faceModelURL, DEFAULT_FULL_AVATAR_MODEL_URL, true, !isMyAvatar()); } void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { AvatarData::setSkeletonModelURL(skeletonModelURL); - const QUrl DEFAULT_FULL_MODEL_URL = QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_full.fst"); - const QUrl DEFAULT_SKELETON_MODEL_URL = QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_body.fst"); - if (isMyAvatar()) { - _skeletonModel.setURL(_skeletonModelURL, - getUseFullAvatar() ? DEFAULT_FULL_MODEL_URL : DEFAULT_SKELETON_MODEL_URL, true, !isMyAvatar()); - } else { - _skeletonModel.setURL(_skeletonModelURL, DEFAULT_SKELETON_MODEL_URL, true, !isMyAvatar()); - } + _skeletonModel.setURL(_skeletonModelURL, DEFAULT_FULL_AVATAR_MODEL_URL, true, !isMyAvatar()); } void Avatar::setAttachmentData(const QVector& attachmentData) { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index a51da387d0..2adff1ce02 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -149,8 +149,6 @@ public: Q_INVOKABLE glm::vec3 getAcceleration() const { return _acceleration; } Q_INVOKABLE glm::vec3 getAngularVelocity() const { return _angularVelocity; } Q_INVOKABLE glm::vec3 getAngularAcceleration() const { return _angularAcceleration; } - - virtual bool getUseFullAvatar() const { return false; } /// Scales a world space position vector relative to the avatar position and scale /// \param vector position to be scaled. Will store the result diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 2cc1105fdc..05bfac1523 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -651,12 +651,7 @@ void MyAvatar::saveData() { settings.setValue("leanScale", _leanScale); settings.setValue("scale", _targetScale); - settings.setValue("useFullAvatar", _useFullAvatar); settings.setValue("fullAvatarURL", _fullAvatarURLFromPreferences); - settings.setValue("faceModelURL", _headURLFromPreferences); - settings.setValue("skeletonModelURL", _skeletonURLFromPreferences); - settings.setValue("headModelName", _headModelName); - settings.setValue("bodyModelName", _bodyModelName); settings.setValue("fullAvatarModelName", _fullAvatarModelName); settings.beginWriteArray("attachmentData"); @@ -726,61 +721,10 @@ void MyAvatar::loadData() { _targetScale = loadSetting(settings, "scale", 1.0f); setScale(_scale); - // The old preferences only stored the face and skeleton URLs, we didn't track if the user wanted to use 1 or 2 urls - // for their avatar, So we need to attempt to detect this old case and set our new preferences accordingly. If - // the head URL is empty, then we will assume they are using a full url... - bool isOldSettings = !(settings.contains("useFullAvatar") || settings.contains("fullAvatarURL")); - - _useFullAvatar = settings.value("useFullAvatar").toBool(); - _headURLFromPreferences = settings.value("faceModelURL", DEFAULT_HEAD_MODEL_URL).toUrl(); _fullAvatarURLFromPreferences = settings.value("fullAvatarURL", DEFAULT_FULL_AVATAR_MODEL_URL).toUrl(); - _skeletonURLFromPreferences = settings.value("skeletonModelURL", DEFAULT_BODY_MODEL_URL).toUrl(); - _headModelName = settings.value("headModelName", DEFAULT_HEAD_MODEL_NAME).toString(); - _bodyModelName = settings.value("bodyModelName", DEFAULT_BODY_MODEL_NAME).toString(); _fullAvatarModelName = settings.value("fullAvatarModelName", DEFAULT_FULL_AVATAR_MODEL_NAME).toString(); - if (isOldSettings) { - bool assumeFullAvatar = _headURLFromPreferences.isEmpty(); - _useFullAvatar = assumeFullAvatar; - - if (_useFullAvatar) { - _fullAvatarURLFromPreferences = settings.value("skeletonModelURL").toUrl(); - _headURLFromPreferences = DEFAULT_HEAD_MODEL_URL; - _skeletonURLFromPreferences = DEFAULT_BODY_MODEL_URL; - - QVariantHash fullAvatarFST = FSTReader::downloadMapping(_fullAvatarURLFromPreferences.toString()); - - _headModelName = "Default"; - _bodyModelName = "Default"; - _fullAvatarModelName = fullAvatarFST["name"].toString(); - - } else { - _fullAvatarURLFromPreferences = DEFAULT_FULL_AVATAR_MODEL_URL; - _skeletonURLFromPreferences = settings.value("skeletonModelURL", DEFAULT_BODY_MODEL_URL).toUrl(); - - if (_skeletonURLFromPreferences == DEFAULT_BODY_MODEL_URL) { - _bodyModelName = DEFAULT_BODY_MODEL_NAME; - } else { - QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString()); - _bodyModelName = bodyFST["name"].toString(); - } - - if (_headURLFromPreferences == DEFAULT_HEAD_MODEL_URL) { - _headModelName = DEFAULT_HEAD_MODEL_NAME; - } else { - QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString()); - _headModelName = headFST["name"].toString(); - } - - _fullAvatarModelName = "Default"; - } - } - - if (_useFullAvatar) { - useFullAvatarURL(_fullAvatarURLFromPreferences, _fullAvatarModelName); - } else { - useHeadAndBodyURLs(_headURLFromPreferences, _skeletonURLFromPreferences, _headModelName, _bodyModelName); - } + useFullAvatarURL(_fullAvatarURLFromPreferences, _fullAvatarModelName); QVector attachmentData; int attachmentCount = settings.beginReadArray("attachmentData"); @@ -1015,29 +959,6 @@ void MyAvatar::clearJointAnimationPriorities() { } } -QString MyAvatar::getModelDescription() const { - QString result; - if (_useFullAvatar) { - if (!getFullAvartarModelName().isEmpty()) { - result = "Full Avatar \"" + getFullAvartarModelName() + "\""; - } else { - result = "Full Avatar \"" + _fullAvatarURLFromPreferences.fileName() + "\""; - } - } else { - if (!getHeadModelName().isEmpty()) { - result = "Head \"" + getHeadModelName() + "\""; - } else { - result = "Head \"" + _headURLFromPreferences.fileName() + "\""; - } - if (!getBodyModelName().isEmpty()) { - result += " and Body \"" + getBodyModelName() + "\""; - } else { - result += " and Body \"" + _skeletonURLFromPreferences.fileName() + "\""; - } - } - return result; -} - void MyAvatar::setFaceModelURL(const QUrl& faceModelURL) { Avatar::setFaceModelURL(faceModelURL); @@ -1064,8 +985,6 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN return; } - _useFullAvatar = true; - if (_fullAvatarURLFromPreferences != fullAvatarURL) { _fullAvatarURLFromPreferences = fullAvatarURL; if (modelName.isEmpty()) { @@ -1087,59 +1006,6 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN sendIdentityPacket(); } -void MyAvatar::useHeadURL(const QUrl& headURL, const QString& modelName) { - useHeadAndBodyURLs(headURL, _skeletonURLFromPreferences, modelName, _bodyModelName); -} - -void MyAvatar::useBodyURL(const QUrl& bodyURL, const QString& modelName) { - useHeadAndBodyURLs(_headURLFromPreferences, bodyURL, _headModelName, modelName); -} - -void MyAvatar::useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, const QString& headName, const QString& bodyName) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "useFullAvatarURL", Qt::BlockingQueuedConnection, - Q_ARG(const QUrl&, headURL), - Q_ARG(const QUrl&, bodyURL), - Q_ARG(const QString&, headName), - Q_ARG(const QString&, bodyName)); - return; - } - - _useFullAvatar = false; - - if (_headURLFromPreferences != headURL) { - _headURLFromPreferences = headURL; - if (headName.isEmpty()) { - QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString()); - _headModelName = headFST["name"].toString(); - } else { - _headModelName = headName; - } - } - - if (_skeletonURLFromPreferences != bodyURL) { - _skeletonURLFromPreferences = bodyURL; - if (bodyName.isEmpty()) { - QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString()); - _bodyModelName = bodyFST["name"].toString(); - } else { - _bodyModelName = bodyName; - } - } - - if (headURL != getFaceModelURL()) { - setFaceModelURL(headURL); - UserActivityLogger::getInstance().changedModel("head", headURL.toString()); - } - - if (bodyURL != getSkeletonModelURL()) { - setSkeletonModelURL(bodyURL); - UserActivityLogger::getInstance().changedModel("skeleton", bodyURL.toString()); - } - sendIdentityPacket(); -} - - void MyAvatar::setAttachmentData(const QVector& attachmentData) { Avatar::setAttachmentData(attachmentData); if (QThread::currentThread() != thread()) { @@ -1295,11 +1161,7 @@ void MyAvatar::preRender(RenderArgs* renderArgs) { } if (shouldDrawHead != _prevShouldDrawHead) { - if (_useFullAvatar) { - _skeletonModel.setCauterizeBones(!shouldDrawHead); - } else { - getHead()->getFaceModel().setVisibleInScene(shouldDrawHead, scene); - } + _skeletonModel.setCauterizeBones(!shouldDrawHead); } _prevShouldDrawHead = shouldDrawHead; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 88649429f5..0cd56ec99c 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -126,22 +126,9 @@ public: virtual void clearJointsData(); Q_INVOKABLE void useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName = QString()); - Q_INVOKABLE void useHeadURL(const QUrl& headURL, const QString& modelName = QString()); - Q_INVOKABLE void useBodyURL(const QUrl& bodyURL, const QString& modelName = QString()); - Q_INVOKABLE void useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, - const QString& headName = QString(), const QString& bodyName = QString()); - - Q_INVOKABLE virtual bool getUseFullAvatar() const { return _useFullAvatar; } Q_INVOKABLE const QUrl& getFullAvatarURLFromPreferences() const { return _fullAvatarURLFromPreferences; } - Q_INVOKABLE const QUrl& getHeadURLFromPreferences() const { return _headURLFromPreferences; } - Q_INVOKABLE const QUrl& getBodyURLFromPreferences() const { return _skeletonURLFromPreferences; } - - Q_INVOKABLE const QString& getHeadModelName() const { return _headModelName; } - Q_INVOKABLE const QString& getBodyModelName() const { return _bodyModelName; } Q_INVOKABLE const QString& getFullAvartarModelName() const { return _fullAvatarModelName; } - Q_INVOKABLE QString getModelDescription() const; - virtual void setAttachmentData(const QVector& attachmentData); DynamicCharacterController* getCharacterController() { return &_characterController; } @@ -298,18 +285,9 @@ private: void initHeadBones(); // Avatar Preferences - bool _useFullAvatar = false; QUrl _fullAvatarURLFromPreferences; - QUrl _headURLFromPreferences; - QUrl _skeletonURLFromPreferences; - - QString _headModelName; - QString _bodyModelName; QString _fullAvatarModelName; - RigPointer _rig; - bool _prevShouldDrawHead; - // cache of the current HMD sensor position and orientation // in sensor space. glm::mat4 _hmdSensorMatrix; @@ -330,6 +308,8 @@ private: glm::quat _goToOrientation; std::unordered_set _headBoneSet; + RigPointer _rig; + bool _prevShouldDrawHead; }; #endif // hifi_MyAvatar_h diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index cec379c596..59701e5cf3 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -47,15 +47,10 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) : connect(ui.buttonBrowseScriptsLocation, &QPushButton::clicked, this, &PreferencesDialog::openScriptsLocationBrowser); connect(ui.buttonReloadDefaultScripts, &QPushButton::clicked, Application::getInstance(), &Application::loadDefaultScripts); - //FIXME remove DialogsManager* dialogsManager = DependencyManager::get().data(); - //FIXME remove connect(ui.buttonChangeApperance, &QPushButton::clicked, dialogsManager, &DialogsManager::changeAvatarAppearance); connect(ui.buttonChangeApperance, &QPushButton::clicked, this, &PreferencesDialog::openFullAvatarModelBrowser); connect(ui.apperanceDescription, &QLineEdit::textChanged, this, [this](const QString& url) { this->fullAvatarURLChanged(url, ""); }); - - //FIXME remove connect(Application::getInstance(), &Application::headURLChanged, this, &PreferencesDialog::headURLChanged); - //FIXME remove connect(Application::getInstance(), &Application::bodyURLChanged, this, &PreferencesDialog::bodyURLChanged); connect(Application::getInstance(), &Application::fullAvatarURLChanged, this, &PreferencesDialog::fullAvatarURLChanged); // move dialog to left side @@ -65,20 +60,7 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) : UIUtil::scaleWidgetFontSizes(this); } -/*FIXME remove void PreferencesDialog::avatarDescriptionChanged() { - ui.apperanceDescription->setText(DependencyManager::get()->getMyAvatar()->getModelDescription()); -} - -void PreferencesDialog::headURLChanged(const QString& newValue, const QString& modelName) { - ui.apperanceDescription->setText(DependencyManager::get()->getMyAvatar()->getModelDescription()); -} - -void PreferencesDialog::bodyURLChanged(const QString& newValue, const QString& modelName) { - ui.apperanceDescription->setText(DependencyManager::get()->getMyAvatar()->getModelDescription()); -} -*/ void PreferencesDialog::fullAvatarURLChanged(const QString& newValue, const QString& modelName) { - //FIXME remove ui.apperanceDescription->setText(DependencyManager::get()->getMyAvatar()->getModelDescription()); ui.apperanceDescription->setText(newValue); const QString APPEARANCE_LABEL_TEXT("Appearance: "); ui.appearanceLabel->setText(APPEARANCE_LABEL_TEXT + modelName); diff --git a/interface/src/ui/PreferencesDialog.h b/interface/src/ui/PreferencesDialog.h index 6cdb4deba1..47341b8feb 100644 --- a/interface/src/ui/PreferencesDialog.h +++ b/interface/src/ui/PreferencesDialog.h @@ -45,8 +45,6 @@ private slots: void openFullAvatarModelBrowser(); void openSnapshotLocationBrowser(); void openScriptsLocationBrowser(); - /* FIXME remove void headURLChanged(const QString& newValue, const QString& modelName); - void bodyURLChanged(const QString& newValue, const QString& modelName);*/ void fullAvatarURLChanged(const QString& newValue, const QString& modelName); }; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 5b970a95a3..78fa00eed7 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -941,7 +941,7 @@ void AvatarData::setFaceModelURL(const QUrl& faceModelURL) { } void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) { - _skeletonModelURL = skeletonModelURL.isEmpty() ? DEFAULT_BODY_MODEL_URL : skeletonModelURL; + _skeletonModelURL = skeletonModelURL.isEmpty() ? DEFAULT_FULL_AVATAR_MODEL_URL : skeletonModelURL; qCDebug(avatars) << "Changing skeleton model for avatar to" << _skeletonModelURL.toString(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 69783652fc..16003594c9 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -48,6 +48,7 @@ typedef unsigned long long quint64; #include #include +//FIXME #include #include #include @@ -107,12 +108,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/models/heads/defaultAvatar_head.fst"); -const QUrl DEFAULT_BODY_MODEL_URL = QUrl("http://public.highfidelity.io/models/skeletons/defaultAvatar_body.fst"); +//FIXME const QUrl DEFAULT_FULL_AVATAR_MODEL_URL = QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_full.fst"); const QUrl DEFAULT_FULL_AVATAR_MODEL_URL = QUrl("http://public.highfidelity.io/marketplace/contents/029db3d4-da2c-4cb2-9c08-b9612ba576f5/02949063e7c4aed42ad9d1a58461f56d.fst"); - -const QString DEFAULT_HEAD_MODEL_NAME = QString("Robot"); -const QString DEFAULT_BODY_MODEL_NAME = QString("Robot"); const QString DEFAULT_FULL_AVATAR_MODEL_NAME = QString("Default"); From 4dae01a69c7bafbb10639212640340941adc7e3b Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 13 Aug 2015 12:54:16 -0700 Subject: [PATCH 011/102] Provide a consistent avatar default for the empty string. --- interface/src/avatar/MyAvatar.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 05bfac1523..ddc0b0b9d1 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -999,9 +999,10 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN setFaceModelURL(QString()); } - if (fullAvatarURL != getSkeletonModelURL()) { + const QString& urlString = fullAvatarURL.toString(); + if (urlString.isEmpty() || (fullAvatarURL != getSkeletonModelURL())) { setSkeletonModelURL(fullAvatarURL); - UserActivityLogger::getInstance().changedModel("skeleton", fullAvatarURL.toString()); + UserActivityLogger::getInstance().changedModel("skeleton", urlString); } sendIdentityPacket(); } From cda5b29fd3f2c0340f5d891bdd897aad182b4b07 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Thu, 13 Aug 2015 14:19:13 -0600 Subject: [PATCH 012/102] Another take at versioning details exchange - checkpoint --- assignment-client/CMakeLists.txt | 1 + assignment-client/src/AssignmentClient.cpp | 3 +-- assignment-client/src/AssignmentClientApp.cpp | 5 ++--- .../macros/ApplicationVersion.h.in | 10 ++++----- cmake/macros/IncludeApplicationVersion.cmake | 22 +++++++++++++++++++ domain-server/CMakeLists.txt | 1 + domain-server/src/DomainServer.cpp | 8 ++----- interface/CMakeLists.txt | 12 ++-------- interface/src/Application.cpp | 2 +- libraries/networking/CMakeLists.txt | 3 ++- libraries/networking/src/Assignment.cpp | 7 ++++++ libraries/networking/src/Assignment.h | 1 + libraries/networking/src/NodeList.cpp | 10 ++++++--- 13 files changed, 53 insertions(+), 32 deletions(-) rename interface/InterfaceVersion.h.in => cmake/macros/ApplicationVersion.h.in (54%) create mode 100644 cmake/macros/IncludeApplicationVersion.cmake diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index 2561a1502d..edd68e12bf 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -17,4 +17,5 @@ if (UNIX) target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS}) endif (UNIX) +include_application_version() copy_dlls_beside_windows_executable() \ No newline at end of file diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 40aef1c707..ec0e5b9e5a 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -129,6 +129,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri packetReceiver.registerListener(PacketType::CreateAssignment, this, "handleCreateAssignmentPacket"); packetReceiver.registerListener(PacketType::StopNode, this, "handleStopNodePacket"); } + void AssignmentClient::stopAssignmentClient() { qDebug() << "Forced stop of assignment-client."; @@ -172,7 +173,6 @@ void AssignmentClient::aboutToQuit() { qInstallMessageHandler(0); } - void AssignmentClient::setUpStatusToMonitor() { // send a stats packet every 1 seconds connect(&_statsTimerACM, &QTimer::timeout, this, &AssignmentClient::sendStatusPacketToACM); @@ -217,7 +217,6 @@ void AssignmentClient::sendAssignmentRequest() { qDebug() << "Failed to read local assignment server port from shared memory" << "- will send assignment request to previous assignment server socket."; } - } nodeList->sendAssignment(_requestAssignment); diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index 7268f9281b..2edae340c3 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -40,6 +41,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : setOrganizationName("High Fidelity"); setOrganizationDomain("highfidelity.io"); setApplicationName("assignment-client"); + setApplicationName(BUILD_VERSION); // use the verbose message handler in Logging qInstallMessageHandler(LogHandler::verboseMessageHandler); @@ -93,10 +95,8 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : Q_UNREACHABLE(); } - const QVariantMap argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments()); - unsigned int numForks = 0; if (parser.isSet(numChildsOption)) { numForks = parser.value(numChildsOption).toInt(); @@ -139,7 +139,6 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : assignmentPool = parser.value(poolOption); } - QUuid walletUUID; if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) { walletUUID = argumentVariantMap.value(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION).toString(); diff --git a/interface/InterfaceVersion.h.in b/cmake/macros/ApplicationVersion.h.in similarity index 54% rename from interface/InterfaceVersion.h.in rename to cmake/macros/ApplicationVersion.h.in index 2f902de41c..736d00726c 100644 --- a/interface/InterfaceVersion.h.in +++ b/cmake/macros/ApplicationVersion.h.in @@ -1,11 +1,9 @@ // -// InterfaceVersion.h -// interface/src +// ApplicationVersion.h.in +// cmake/macros // -// Created by Leonardo Murillo on 12/16/13. -// Copyright 2013 High Fidelity, Inc. -// -// Declaration of version and build data +// Created by Leonardo Murillo on 8/13/15. +// Copyright 2015 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 diff --git a/cmake/macros/IncludeApplicationVersion.cmake b/cmake/macros/IncludeApplicationVersion.cmake new file mode 100644 index 0000000000..96137294a7 --- /dev/null +++ b/cmake/macros/IncludeApplicationVersion.cmake @@ -0,0 +1,22 @@ +# +# IncludeApplicationVersion.cmake +# cmake/macros +# +# Created by Leonardo Murillo on 07/14/2015. +# Copyright 2015 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 +# + +macro(INCLUDE_APPLICATION_VERSION) + if (DEFINED ENV{JOB_ID}) + set (BUILD_SEQ $ENV{JOB_ID}) + elseif (DEFINED ENV{ghprbPullId}) + set (BUILD_SEQ "PR: $ENV{ghprbPullId} - Commit: $ENV{ghprbActualCommit}") + else () + set(BUILD_SEQ "dev") + endif () + configure_file("${MACRO_DIR}/ApplicationVersion.h.in" "${PROJECT_BINARY_DIR}/includes/ApplicationVersion.h") + include_directories("${PROJECT_BINARY_DIR}/includes") +endmacro(INCLUDE_APPLICATION_VERSION) diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index 41f2d15486..e4fa1d874d 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -31,4 +31,5 @@ include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}") # append OpenSSL to our list of libraries to link target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES}) +include_application_version() copy_dlls_beside_windows_executable() diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 4e5b563fc6..abfd7efe89 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -75,6 +76,7 @@ DomainServer::DomainServer(int argc, char* argv[]) : setOrganizationName("High Fidelity"); setOrganizationDomain("highfidelity.io"); setApplicationName("domain-server"); + setApplicationVersion(BUILD_VERSION); QSettings::setDefaultFormat(QSettings::IniFormat); // make sure we have a fresh AccountManager instance @@ -1478,7 +1480,6 @@ const char JSON_KEY_POOL[] = "pool"; const char JSON_KEY_PENDING_CREDITS[] = "pending_credits"; const char JSON_KEY_WAKE_TIMESTAMP[] = "wake_timestamp"; const char JSON_KEY_USERNAME[] = "username"; - QJsonObject DomainServer::jsonObjectForNode(const SharedNodePointer& node) { QJsonObject nodeJson; @@ -1527,7 +1528,6 @@ QJsonObject DomainServer::jsonObjectForNode(const SharedNodePointer& node) { } const char ASSIGNMENT_SCRIPT_HOST_LOCATION[] = "resources/web/assignment"; - QString pathForAssignmentScript(const QUuid& assignmentUUID) { QString newPath(ASSIGNMENT_SCRIPT_HOST_LOCATION); newPath += "/scripts/"; @@ -1537,7 +1537,6 @@ QString pathForAssignmentScript(const QUuid& assignmentUUID) { } const QString URI_OAUTH = "/oauth"; - bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) { const QString JSON_MIME_TYPE = "application/json"; @@ -2024,8 +2023,6 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl } const QString OAUTH_JSON_ACCESS_TOKEN_KEY = "access_token"; - - QNetworkReply* DomainServer::profileRequestGivenTokenReply(QNetworkReply* tokenReply) { // pull the access token from the returned JSON and store it with the matching session UUID QJsonDocument returnedJSON = QJsonDocument::fromJson(tokenReply->readAll()); @@ -2042,7 +2039,6 @@ QNetworkReply* DomainServer::profileRequestGivenTokenReply(QNetworkReply* tokenR } const QString DS_SETTINGS_SESSIONS_GROUP = "web-sessions"; - Headers DomainServer::setupCookieHeadersFromProfileReply(QNetworkReply* profileReply) { Headers cookieHeaders; diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 9ad250bdcf..acafafa006 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -14,20 +14,12 @@ endforeach() find_package(Qt5LinguistTools REQUIRED) find_package(Qt5LinguistToolsMacros) -if (DEFINED ENV{JOB_ID}) - set(BUILD_SEQ $ENV{JOB_ID}) -elseif (DEFINED ENV{ghprbPullId}) - set(BUILD_SEQ "PR: $ENV{ghprbPullId} - Commit: $ENV{ghprbActualCommit}") -else () - set(BUILD_SEQ "dev") -endif () - if (WIN32) add_definitions(-D_USE_MATH_DEFINES) # apparently needed to get M_PI and other defines from cmath/math.h add_definitions(-DWINDOWS_LEAN_AND_MEAN) # needed to make sure windows doesn't go to crazy with its defines endif() -configure_file(InterfaceVersion.h.in "${PROJECT_BINARY_DIR}/includes/InterfaceVersion.h") +include_application_version() # grab the implementation and header files from src dirs file(GLOB_RECURSE INTERFACE_SRCS "src/*.cpp" "src/*.h") @@ -174,7 +166,7 @@ if (RTMIDI_FOUND AND NOT DISABLE_RTMIDI AND APPLE) endif () # include headers for interface and InterfaceConfig. -include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes") +include_directories("${PROJECT_SOURCE_DIR}/src") target_link_libraries( ${TARGET_NAME} diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d8dad73d82..fe361f8b8f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -52,6 +52,7 @@ #include #include +#include #include #include #include @@ -100,7 +101,6 @@ #include "AudioClient.h" #include "DiscoverabilityManager.h" #include "GLCanvas.h" -#include "InterfaceVersion.h" #include "LODManager.h" #include "Menu.h" #include "ModelPackager.h" diff --git a/libraries/networking/CMakeLists.txt b/libraries/networking/CMakeLists.txt index 6b386ace92..d79e6bde58 100644 --- a/libraries/networking/CMakeLists.txt +++ b/libraries/networking/CMakeLists.txt @@ -28,4 +28,5 @@ include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}") target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES} ${TBB_LIBRARIES}) # append tbb includes to our list of includes to bubble -target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${TBB_INCLUDE_DIRS}) \ No newline at end of file +target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${TBB_INCLUDE_DIRS}) +include_application_version() \ No newline at end of file diff --git a/libraries/networking/src/Assignment.cpp b/libraries/networking/src/Assignment.cpp index 293d86475f..a7a6fe03ea 100644 --- a/libraries/networking/src/Assignment.cpp +++ b/libraries/networking/src/Assignment.cpp @@ -66,7 +66,9 @@ Assignment::Assignment(NLPacket& packet) : _payload(), _walletUUID() { + qDebug() << "LEOTEST: We are building an Assignment from a packet"; if (packet.getType() == PacketType::RequestAssignment) { + qDebug() << "LEOTEST: This is a request assignment packet"; _command = Assignment::RequestCommand; } else if (packet.getType() == PacketType::CreateAssignment) { _command = Assignment::CreateCommand; @@ -151,11 +153,16 @@ QDataStream& operator<<(QDataStream &out, const Assignment& assignment) { QDataStream& operator>>(QDataStream &in, Assignment& assignment) { quint8 packedType; in >> packedType; + if (assignment._command == Assignment::RequestCommand) { + qDebug() << "We are extracting the version"; + in >> assignment._nodeVersion; + } assignment._type = (Assignment::Type) packedType; in >> assignment._uuid >> assignment._pool >> assignment._payload; if (assignment._command == Assignment::RequestCommand) { + qDebug() << "LEOTEST: Operator for >> in case of RequestCommand"; in >> assignment._walletUUID; } diff --git a/libraries/networking/src/Assignment.h b/libraries/networking/src/Assignment.h index 67f861f850..f1b6cc7fba 100644 --- a/libraries/networking/src/Assignment.h +++ b/libraries/networking/src/Assignment.h @@ -98,6 +98,7 @@ protected: QByteArray _payload; /// an optional payload attached to this assignment, a maximum for 1024 bytes will be packed bool _isStatic; /// defines if this assignment needs to be re-queued in the domain-server if it stops being fulfilled QUuid _walletUUID; /// the UUID for the wallet that should be paid for this assignment + QString _nodeVersion; }; #endif // hifi_Assignment_h diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 44b9c0b829..9ecf31edab 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include "AccountManager.h" @@ -367,7 +368,6 @@ void NodeList::sendDSPathQuery(const QString& newPath) { } } - void NodeList::processDomainServerPathResponse(QSharedPointer packet) { // This is a response to a path query we theoretically made. // In the future we may want to check that this was actually from our DS and for a query we actually made. @@ -457,7 +457,6 @@ void NodeList::pingPunchForDomainServer() { } } - void NodeList::processDomainServerConnectionTokenPacket(QSharedPointer packet) { if (_domainHandler.getSockAddr().isNull()) { // refuse to process this packet if we aren't currently connected to the DS @@ -547,9 +546,14 @@ void NodeList::sendAssignment(Assignment& assignment) { ? PacketType::CreateAssignment : PacketType::RequestAssignment; + qDebug() << "LEOTEST: Packet type name " << nameForPacketType(assignmentPacketType); auto assignmentPacket = NLPacket::create(assignmentPacketType); - + QDataStream packetStream(assignmentPacket.get()); + if (assignmentPacketType == PacketType::RequestAssignment) { + qDebug() << "LEOTEST: This is an assignment request, lets send the node version here " << BUILD_VERSION; + packetStream << BUILD_VERSION; + } packetStream << assignment; // TODO: should this be a non sourced packet? From 2756a0063877e2274a94df7a22ebcaaa8f9120d4 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 13 Aug 2015 14:23:34 -0700 Subject: [PATCH 013/102] Get default avatar url from resources. --- interface/src/Application.cpp | 2 +- interface/src/avatar/Avatar.cpp | 4 ++-- interface/src/avatar/MyAvatar.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 12 +++++++++++- libraries/avatars/src/AvatarData.h | 8 +++++--- 5 files changed, 20 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5dac571045..914356fa45 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4405,7 +4405,7 @@ void Application::checkSkeleton() { msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); - _myAvatar->useFullAvatarURL(DEFAULT_FULL_AVATAR_MODEL_URL, DEFAULT_FULL_AVATAR_MODEL_NAME); + _myAvatar->useFullAvatarURL(AvatarData::defaultFullAvatarModelUrl(), DEFAULT_FULL_AVATAR_MODEL_NAME); } else { _physicsEngine.setCharacterController(_myAvatar->getCharacterController()); } diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index b537d5a5d8..893c9a9370 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -952,12 +952,12 @@ void Avatar::scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const { void Avatar::setFaceModelURL(const QUrl& faceModelURL) { AvatarData::setFaceModelURL(faceModelURL); - getHead()->getFaceModel().setURL(_faceModelURL, DEFAULT_FULL_AVATAR_MODEL_URL, true, !isMyAvatar()); + getHead()->getFaceModel().setURL(_faceModelURL, AvatarData::defaultFullAvatarModelUrl(), true, !isMyAvatar()); } void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { AvatarData::setSkeletonModelURL(skeletonModelURL); - _skeletonModel.setURL(_skeletonModelURL, DEFAULT_FULL_AVATAR_MODEL_URL, true, !isMyAvatar()); + _skeletonModel.setURL(_skeletonModelURL, AvatarData::defaultFullAvatarModelUrl(), true, !isMyAvatar()); } void Avatar::setAttachmentData(const QVector& attachmentData) { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index ddc0b0b9d1..6425169e57 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -721,7 +721,7 @@ void MyAvatar::loadData() { _targetScale = loadSetting(settings, "scale", 1.0f); setScale(_scale); - _fullAvatarURLFromPreferences = settings.value("fullAvatarURL", DEFAULT_FULL_AVATAR_MODEL_URL).toUrl(); + _fullAvatarURLFromPreferences = settings.value("fullAvatarURL", AvatarData::defaultFullAvatarModelUrl()).toUrl(); _fullAvatarModelName = settings.value("fullAvatarModelName", DEFAULT_FULL_AVATAR_MODEL_NAME).toString(); useFullAvatarURL(_fullAvatarURLFromPreferences, _fullAvatarModelName); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 78fa00eed7..afcc3a98b2 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -70,6 +70,16 @@ AvatarData::~AvatarData() { delete _referential; } +// We cannot have a file-level variable (const or otherwise) in the header if it uses PathUtils, because that references Application, which will not yet initialized. +// Thus we have a static class getter, referencing a static class var. +QUrl AvatarData::_defaultFullAvatarModelUrl = {}; // In C++, if this initialization were in the header, every file would have it's own copy, even for class vars. +const QUrl AvatarData::defaultFullAvatarModelUrl() { + if (_defaultFullAvatarModelUrl.isEmpty()) { + _defaultFullAvatarModelUrl = QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_full.fst"); + } + return _defaultFullAvatarModelUrl; +} + const glm::vec3& AvatarData::getPosition() const { if (_referential) { _referential->update(); @@ -941,7 +951,7 @@ void AvatarData::setFaceModelURL(const QUrl& faceModelURL) { } void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) { - _skeletonModelURL = skeletonModelURL.isEmpty() ? DEFAULT_FULL_AVATAR_MODEL_URL : skeletonModelURL; + _skeletonModelURL = skeletonModelURL.isEmpty() ? AvatarData::defaultFullAvatarModelUrl() : skeletonModelURL; qCDebug(avatars) << "Changing skeleton model for avatar to" << _skeletonModelURL.toString(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 16003594c9..c4412e1d09 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -48,13 +48,13 @@ typedef unsigned long long quint64; #include #include -//FIXME #include #include #include #include "AABox.h" #include "HandData.h" #include "HeadData.h" +#include "PathUtils.h" #include "Player.h" #include "Recorder.h" #include "Referential.h" @@ -108,8 +108,7 @@ 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; -//FIXME const QUrl DEFAULT_FULL_AVATAR_MODEL_URL = QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_full.fst"); -const QUrl DEFAULT_FULL_AVATAR_MODEL_URL = QUrl("http://public.highfidelity.io/marketplace/contents/029db3d4-da2c-4cb2-9c08-b9612ba576f5/02949063e7c4aed42ad9d1a58461f56d.fst"); +// See also static AvatarData::defaultFullAvatarModelUrl(). const QString DEFAULT_FULL_AVATAR_MODEL_NAME = QString("Default"); @@ -160,6 +159,8 @@ public: AvatarData(); virtual ~AvatarData(); + static const QUrl defaultFullAvatarModelUrl(); + virtual bool isMyAvatar() const { return false; } const QUuid& getSessionUUID() const { return _sessionUUID; } @@ -398,6 +399,7 @@ protected: SimpleMovingAverage _averageBytesReceived; private: + static QUrl _defaultFullAvatarModelUrl; // privatize the copy constructor and assignment operator so they cannot be called AvatarData(const AvatarData&); AvatarData& operator= (const AvatarData&); From a8a064990f64cd17257a0fdaeb6749571bacde23 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 13 Aug 2015 14:42:37 -0700 Subject: [PATCH 014/102] apperance => appearance --- interface/src/ui/PreferencesDialog.cpp | 6 +++--- interface/ui/preferencesDialog.ui | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 59701e5cf3..8479f6778c 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -47,8 +47,8 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) : connect(ui.buttonBrowseScriptsLocation, &QPushButton::clicked, this, &PreferencesDialog::openScriptsLocationBrowser); connect(ui.buttonReloadDefaultScripts, &QPushButton::clicked, Application::getInstance(), &Application::loadDefaultScripts); - connect(ui.buttonChangeApperance, &QPushButton::clicked, this, &PreferencesDialog::openFullAvatarModelBrowser); - connect(ui.apperanceDescription, &QLineEdit::textChanged, this, [this](const QString& url) { + connect(ui.buttonChangeAppearance, &QPushButton::clicked, this, &PreferencesDialog::openFullAvatarModelBrowser); + connect(ui.appearanceDescription, &QLineEdit::textChanged, this, [this](const QString& url) { this->fullAvatarURLChanged(url, ""); }); connect(Application::getInstance(), &Application::fullAvatarURLChanged, this, &PreferencesDialog::fullAvatarURLChanged); @@ -61,7 +61,7 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) : } void PreferencesDialog::fullAvatarURLChanged(const QString& newValue, const QString& modelName) { - ui.apperanceDescription->setText(newValue); + ui.appearanceDescription->setText(newValue); const QString APPEARANCE_LABEL_TEXT("Appearance: "); ui.appearanceLabel->setText(APPEARANCE_LABEL_TEXT + modelName); DependencyManager::get()->getMyAvatar()->useFullAvatarURL(newValue, modelName); diff --git a/interface/ui/preferencesDialog.ui b/interface/ui/preferencesDialog.ui index 71103da654..b91367dcf1 100644 --- a/interface/ui/preferencesDialog.ui +++ b/interface/ui/preferencesDialog.ui @@ -275,7 +275,7 @@ Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - apperanceDescription + appearanceDescription @@ -283,12 +283,12 @@ - + 0 - + Arial @@ -297,7 +297,7 @@ - + Qt::Horizontal @@ -313,7 +313,7 @@ - + Arial From 74dc6a3dc54b53b541b99195a7f752bb422771e9 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 13 Aug 2015 14:43:39 -0700 Subject: [PATCH 015/102] updateMotionBehavior => updateMotionBehaviorFromMenu --- interface/src/Menu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 44f336e996..6d39326195 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -258,7 +258,7 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::BlueSpeechSphere, 0, true); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::EnableCharacterController, 0, true, - avatar, SLOT(updateMotionBehavior())); + avatar, SLOT(updateMotionBehaviorFromMenu())); MenuWrapper* viewMenu = addMenu("View"); addActionToQMenuAndActionHash(viewMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches())); From 7d4c96cc29bd5ab021f969bea213cf7daeaa2b42 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 13 Aug 2015 14:53:12 -0700 Subject: [PATCH 016/102] avartar => avatar --- interface/src/avatar/MyAvatar.h | 2 +- interface/src/ui/PreferencesDialog.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 0cd56ec99c..8ff9211101 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -127,7 +127,7 @@ public: Q_INVOKABLE void useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName = QString()); Q_INVOKABLE const QUrl& getFullAvatarURLFromPreferences() const { return _fullAvatarURLFromPreferences; } - Q_INVOKABLE const QString& getFullAvartarModelName() const { return _fullAvatarModelName; } + Q_INVOKABLE const QString& getFullAvatarModelName() const { return _fullAvatarModelName; } virtual void setAttachmentData(const QVector& attachmentData); diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 8479f6778c..41b91d65c3 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -128,7 +128,7 @@ void PreferencesDialog::loadPreferences() { ui.collisionSoundURLEdit->setText(myAvatar->getCollisionSoundURL()); fullAvatarURLChanged(myAvatar->getFullAvatarURLFromPreferences().toString(), - myAvatar->getFullAvartarModelName()); + myAvatar->getFullAvatarModelName()); ui.sendDataCheckBox->setChecked(!menuInstance->isOptionChecked(MenuOption::DisableActivityLogger)); From 722c024f610aaf9ce558303e6bee1a2e594216e8 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 13 Aug 2015 15:08:26 -0700 Subject: [PATCH 017/102] Remove obsolete code. --- interface/src/avatar/FaceModel.cpp | 56 ------------------------------ interface/src/avatar/FaceModel.h | 4 --- 2 files changed, 60 deletions(-) diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index e31c804185..0e8e5a6a91 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -47,66 +47,10 @@ void FaceModel::simulate(float deltaTime, bool fullUpdate) { if (isActive()) { setOffset(-_geometry->getFBXGeometry().neckPivot); - - for (int i = 0; i < _rig->getJointStateCount(); i++) { - maybeUpdateNeckAndEyeRotation(i); - } - Model::simulateInternal(deltaTime); } } -void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const JointState& state, int index) { - // get the rotation axes in joint space and use them to adjust the rotation - glm::mat3 axes = glm::mat3_cast(glm::quat()); - glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() * - glm::translate(_rig->getJointDefaultTranslationInConstrainedFrame(index)) * - state.getPreTransform() * glm::mat4_cast(state.getPreRotation()))); - glm::vec3 pitchYawRoll = safeEulerAngles(_owningHead->getFinalOrientationInLocalFrame()); - glm::vec3 lean = glm::radians(glm::vec3(_owningHead->getFinalLeanForward(), - _owningHead->getTorsoTwist(), - _owningHead->getFinalLeanSideways())); - pitchYawRoll -= lean; - _rig->setJointRotationInConstrainedFrame(index, - glm::angleAxis(-pitchYawRoll.z, glm::normalize(inverse * axes[2])) - * glm::angleAxis(pitchYawRoll.y, glm::normalize(inverse * axes[1])) - * glm::angleAxis(-pitchYawRoll.x, glm::normalize(inverse * axes[0])) - * state.getDefaultRotation(), DEFAULT_PRIORITY); -} - -void FaceModel::maybeUpdateEyeRotation(Model* model, const JointState& parentState, const JointState& state, int index) { - // likewise with the eye joints - // NOTE: at the moment we do the math in the world-frame, hence the inverse transform is more complex than usual. - glm::mat4 inverse = glm::inverse(glm::mat4_cast(model->getRotation()) * parentState.getTransform() * - glm::translate(_rig->getJointDefaultTranslationInConstrainedFrame(index)) * - state.getPreTransform() * glm::mat4_cast(state.getPreRotation() * state.getDefaultRotation())); - glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getFinalOrientationInWorldFrame() * IDENTITY_FRONT, 0.0f)); - glm::vec3 lookAtDelta = _owningHead->getCorrectedLookAtPosition() - model->getTranslation(); - glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(lookAtDelta + glm::length(lookAtDelta) * _owningHead->getSaccade(), 1.0f)); - glm::quat between = rotationBetween(front, lookAt); - const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE; - _rig->setJointRotationInConstrainedFrame(index, glm::angleAxis(glm::clamp(glm::angle(between), - -MAX_ANGLE, MAX_ANGLE), glm::axis(between)) * - state.getDefaultRotation(), DEFAULT_PRIORITY); -} - -void FaceModel::maybeUpdateNeckAndEyeRotation(int index) { - const JointState& state = _rig->getJointState(index); - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - const int parentIndex = state.getParentIndex(); - - // guard against out-of-bounds access to _jointStates - if (parentIndex != -1 && parentIndex >= 0 && parentIndex < _rig->getJointStateCount()) { - const JointState& parentState = _rig->getJointState(parentIndex); - if (index == geometry.neckJointIndex) { - maybeUpdateNeckRotation(parentState, state, index); - - } else if (index == geometry.leftEyeJointIndex || index == geometry.rightEyeJointIndex) { - maybeUpdateEyeRotation(this, parentState, state, index); - } - } -} - bool FaceModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const { if (!isActive()) { return false; diff --git a/interface/src/avatar/FaceModel.h b/interface/src/avatar/FaceModel.h index ed1ea28508..5a19a8ea29 100644 --- a/interface/src/avatar/FaceModel.h +++ b/interface/src/avatar/FaceModel.h @@ -26,10 +26,6 @@ public: virtual void simulate(float deltaTime, bool fullUpdate = true); - void maybeUpdateNeckRotation(const JointState& parentState, const JointState& state, int index); - void maybeUpdateEyeRotation(Model* model, const JointState& parentState, const JointState& state, int index); - void maybeUpdateNeckAndEyeRotation(int index); - /// Retrieve the positions of up to two eye meshes. /// \return whether or not both eye meshes were found bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; From 7c4813f1cf278a58d4fae85ad6bfbc1b1368b189 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Thu, 13 Aug 2015 16:35:55 -0600 Subject: [PATCH 018/102] Another versioning checkpoint + cleanup --- domain-server/src/DomainServer.cpp | 6 ++++- domain-server/src/DomainServerNodeData.h | 5 ++++ domain-server/src/PendingAssignedNodeData.cpp | 5 ++-- domain-server/src/PendingAssignedNodeData.h | 6 ++++- libraries/networking/src/Assignment.cpp | 26 ++++++++++++------- libraries/networking/src/Assignment.h | 2 ++ libraries/networking/src/NodeList.cpp | 5 ---- 7 files changed, 37 insertions(+), 18 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index abfd7efe89..071626ef1e 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -740,6 +740,7 @@ void DomainServer::processConnectRequestPacket(QSharedPointer packet) if (isAssignment) { nodeData->setAssignmentUUID(matchingQueuedAssignment->getUUID()); nodeData->setWalletUUID(pendingAssigneeData->getWalletUUID()); + nodeData->setNodeVersion(pendingAssigneeData->getNodeVersion()); // always allow assignment clients to create and destroy entities newNode->setCanAdjustLocks(true); @@ -1170,7 +1171,8 @@ void DomainServer::processRequestAssignmentPacket(QSharedPointer packe // add the information for that deployed assignment to the hash of pending assigned nodes PendingAssignedNodeData* pendingNodeData = new PendingAssignedNodeData(assignmentToDeploy->getUUID(), - requestAssignment.getWalletUUID()); + requestAssignment.getWalletUUID(), + requestAssignment.getNodeVersion()); _pendingAssignedNodes.insert(uniqueAssignment.getUUID(), pendingNodeData); } else { if (requestAssignment.getType() != Assignment::AgentType @@ -1480,6 +1482,7 @@ const char JSON_KEY_POOL[] = "pool"; const char JSON_KEY_PENDING_CREDITS[] = "pending_credits"; const char JSON_KEY_WAKE_TIMESTAMP[] = "wake_timestamp"; const char JSON_KEY_USERNAME[] = "username"; +const char JSON_KEY_VERSION[] = "version"; QJsonObject DomainServer::jsonObjectForNode(const SharedNodePointer& node) { QJsonObject nodeJson; @@ -1506,6 +1509,7 @@ QJsonObject DomainServer::jsonObjectForNode(const SharedNodePointer& node) { // add the node username, if it exists nodeJson[JSON_KEY_USERNAME] = nodeData->getUsername(); + nodeJson[JSON_KEY_VERSION] = nodeData->getNodeVersion(); SharedAssignmentPointer matchingAssignment = _allAssignments.value(nodeData->getAssignmentUUID()); if (matchingAssignment) { diff --git a/domain-server/src/DomainServerNodeData.h b/domain-server/src/DomainServerNodeData.h index 57ed96acab..2c57368653 100644 --- a/domain-server/src/DomainServerNodeData.h +++ b/domain-server/src/DomainServerNodeData.h @@ -50,6 +50,10 @@ public: const NodeSet& getNodeInterestSet() const { return _nodeInterestSet; } void setNodeInterestSet(const NodeSet& nodeInterestSet) { _nodeInterestSet = nodeInterestSet; } + + void setNodeVersion(const QString& nodeVersion) { _nodeVersion = nodeVersion; } + const QString& getNodeVersion() { return _nodeVersion; } + private: QJsonObject mergeJSONStatsFromNewObject(const QJsonObject& newObject, QJsonObject destinationObject); @@ -62,6 +66,7 @@ private: HifiSockAddr _sendingSockAddr; bool _isAuthenticated; NodeSet _nodeInterestSet; + QString _nodeVersion; }; #endif // hifi_DomainServerNodeData_h diff --git a/domain-server/src/PendingAssignedNodeData.cpp b/domain-server/src/PendingAssignedNodeData.cpp index 21b3aa4ca4..30310ac01f 100644 --- a/domain-server/src/PendingAssignedNodeData.cpp +++ b/domain-server/src/PendingAssignedNodeData.cpp @@ -11,9 +11,10 @@ #include "PendingAssignedNodeData.h" -PendingAssignedNodeData::PendingAssignedNodeData(const QUuid& assignmentUUID, const QUuid& walletUUID) : +PendingAssignedNodeData::PendingAssignedNodeData(const QUuid& assignmentUUID, const QUuid& walletUUID, const QString& nodeVersion) : _assignmentUUID(assignmentUUID), - _walletUUID(walletUUID) + _walletUUID(walletUUID), + _nodeVersion(nodeVersion) { } \ No newline at end of file diff --git a/domain-server/src/PendingAssignedNodeData.h b/domain-server/src/PendingAssignedNodeData.h index 93d99a6f8f..2d546f573f 100644 --- a/domain-server/src/PendingAssignedNodeData.h +++ b/domain-server/src/PendingAssignedNodeData.h @@ -18,16 +18,20 @@ class PendingAssignedNodeData : public QObject { Q_OBJECT public: - PendingAssignedNodeData(const QUuid& assignmentUUID, const QUuid& walletUUID); + PendingAssignedNodeData(const QUuid& assignmentUUID, const QUuid& walletUUID, const QString& nodeVersion); void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; } const QUuid& getAssignmentUUID() const { return _assignmentUUID; } void setWalletUUID(const QUuid& walletUUID) { _walletUUID = walletUUID; } const QUuid& getWalletUUID() const { return _walletUUID; } + + const QString& getNodeVersion() const { return _nodeVersion; } + private: QUuid _assignmentUUID; QUuid _walletUUID; + QString _nodeVersion; }; #endif // hifi_PendingAssignedNodeData_h \ No newline at end of file diff --git a/libraries/networking/src/Assignment.cpp b/libraries/networking/src/Assignment.cpp index a7a6fe03ea..8a97b7cf8c 100644 --- a/libraries/networking/src/Assignment.cpp +++ b/libraries/networking/src/Assignment.cpp @@ -13,8 +13,10 @@ #include "SharedUtil.h" #include "UUID.h" +#include #include +#include #include "Assignment.h" Assignment::Type Assignment::typeForNodeType(NodeType_t nodeType) { @@ -52,11 +54,14 @@ Assignment::Assignment(Assignment::Command command, Assignment::Type type, const _location(location), _payload(), _isStatic(false), - _walletUUID() + _walletUUID(), + _nodeVersion() { if (_command == Assignment::CreateCommand) { // this is a newly created assignment, generate a random UUID _uuid = QUuid::createUuid(); + } else if (_command == Assignment::RequestCommand) { + _nodeVersion = BUILD_VERSION; } } @@ -64,11 +69,10 @@ Assignment::Assignment(NLPacket& packet) : _pool(), _location(GlobalLocation), _payload(), - _walletUUID() + _walletUUID(), + _nodeVersion() { - qDebug() << "LEOTEST: We are building an Assignment from a packet"; if (packet.getType() == PacketType::RequestAssignment) { - qDebug() << "LEOTEST: This is a request assignment packet"; _command = Assignment::RequestCommand; } else if (packet.getType() == PacketType::CreateAssignment) { _command = Assignment::CreateCommand; @@ -85,15 +89,14 @@ Assignment::Assignment(NLPacket& packet) : Assignment::Assignment(const Assignment& otherAssignment) { - _uuid = otherAssignment._uuid; - _command = otherAssignment._command; _type = otherAssignment._type; _location = otherAssignment._location; _pool = otherAssignment._pool; _payload = otherAssignment._payload; _walletUUID = otherAssignment._walletUUID; + _nodeVersion = otherAssignment._nodeVersion; } Assignment& Assignment::operator=(const Assignment& rhsAssignment) { @@ -112,6 +115,7 @@ void Assignment::swap(Assignment& otherAssignment) { swap(_pool, otherAssignment._pool); swap(_payload, otherAssignment._payload); swap(_walletUUID, otherAssignment._walletUUID); + swap(_nodeVersion, otherAssignment._nodeVersion); } const char* Assignment::getTypeName() const { @@ -141,7 +145,13 @@ QDebug operator<<(QDebug debug, const Assignment &assignment) { } QDataStream& operator<<(QDataStream &out, const Assignment& assignment) { - out << (quint8) assignment._type << assignment._uuid << assignment._pool << assignment._payload; + out << (quint8) assignment._type; + + if (assignment._command == Assignment::RequestCommand) { + out << assignment._nodeVersion; + } + + out << assignment._uuid << assignment._pool << assignment._payload; if (assignment._command == Assignment::RequestCommand) { out << assignment._walletUUID; @@ -154,7 +164,6 @@ QDataStream& operator>>(QDataStream &in, Assignment& assignment) { quint8 packedType; in >> packedType; if (assignment._command == Assignment::RequestCommand) { - qDebug() << "We are extracting the version"; in >> assignment._nodeVersion; } assignment._type = (Assignment::Type) packedType; @@ -162,7 +171,6 @@ QDataStream& operator>>(QDataStream &in, Assignment& assignment) { in >> assignment._uuid >> assignment._pool >> assignment._payload; if (assignment._command == Assignment::RequestCommand) { - qDebug() << "LEOTEST: Operator for >> in case of RequestCommand"; in >> assignment._walletUUID; } diff --git a/libraries/networking/src/Assignment.h b/libraries/networking/src/Assignment.h index f1b6cc7fba..6950223a9d 100644 --- a/libraries/networking/src/Assignment.h +++ b/libraries/networking/src/Assignment.h @@ -83,6 +83,8 @@ public: void setWalletUUID(const QUuid& walletUUID) { _walletUUID = walletUUID; } const QUuid& getWalletUUID() const { return _walletUUID; } + const QString& getNodeVersion() const { return _nodeVersion; } + const char* getTypeName() const; friend QDebug operator<<(QDebug debug, const Assignment& assignment); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 9ecf31edab..563b7d7080 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -546,14 +546,9 @@ void NodeList::sendAssignment(Assignment& assignment) { ? PacketType::CreateAssignment : PacketType::RequestAssignment; - qDebug() << "LEOTEST: Packet type name " << nameForPacketType(assignmentPacketType); auto assignmentPacket = NLPacket::create(assignmentPacketType); QDataStream packetStream(assignmentPacket.get()); - if (assignmentPacketType == PacketType::RequestAssignment) { - qDebug() << "LEOTEST: This is an assignment request, lets send the node version here " << BUILD_VERSION; - packetStream << BUILD_VERSION; - } packetStream << assignment; // TODO: should this be a non sourced packet? From b345d75e4d897f3b20f43de2705f6586aa04d9c4 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Thu, 13 Aug 2015 16:44:28 -0600 Subject: [PATCH 019/102] More cleanup and showing version in ds web gui --- domain-server/resources/web/index.shtml | 4 +++- libraries/networking/src/Assignment.cpp | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/domain-server/resources/web/index.shtml b/domain-server/resources/web/index.shtml index b159d624a4..0f720ebe79 100644 --- a/domain-server/resources/web/index.shtml +++ b/domain-server/resources/web/index.shtml @@ -9,6 +9,7 @@ Type + Version UUID Pool Username @@ -24,6 +25,7 @@ <% _.each(nodes, function(node, node_index){ %> <%- node.type %> + <%- node.version %> <%- node.uuid %> <%- node.pool %> <%- node.username %> @@ -75,4 +77,4 @@ - \ No newline at end of file + diff --git a/libraries/networking/src/Assignment.cpp b/libraries/networking/src/Assignment.cpp index 8a97b7cf8c..b63373858e 100644 --- a/libraries/networking/src/Assignment.cpp +++ b/libraries/networking/src/Assignment.cpp @@ -13,7 +13,6 @@ #include "SharedUtil.h" #include "UUID.h" -#include #include #include From 63608d8012c2c64c98ec8cc4ce4d9020a4675a3a Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 13 Aug 2015 15:55:43 -0700 Subject: [PATCH 020/102] Undo avatar choice if the whole preferences dialog is cancelled. --- interface/src/ui/PreferencesDialog.cpp | 23 ++++++++++++++++++++--- interface/src/ui/PreferencesDialog.h | 4 ++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 41b91d65c3..63170fdd70 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -68,12 +68,24 @@ void PreferencesDialog::fullAvatarURLChanged(const QString& newValue, const QStr } void PreferencesDialog::accept() { + MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); + _lastGoodAvatarURL = myAvatar->getFullAvatarURLFromPreferences(); + _lastGoodAvatarName = myAvatar->getFullAvatarModelName(); savePreferences(); close(); delete _marketplaceWindow; _marketplaceWindow = NULL; } +void PreferencesDialog::restoreLastGoodAvatar() { + fullAvatarURLChanged(_lastGoodAvatarURL.toString(), _lastGoodAvatarName); +} + +void PreferencesDialog::reject() { + restoreLastGoodAvatar(); + QDialog::reject(); +} + void PreferencesDialog::openSnapshotLocationBrowser() { QString dir = QFileDialog::getExistingDirectory(this, tr("Snapshots Location"), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), @@ -127,8 +139,9 @@ void PreferencesDialog::loadPreferences() { ui.collisionSoundURLEdit->setText(myAvatar->getCollisionSoundURL()); - fullAvatarURLChanged(myAvatar->getFullAvatarURLFromPreferences().toString(), - myAvatar->getFullAvatarModelName()); + _lastGoodAvatarURL = myAvatar->getFullAvatarURLFromPreferences(); + _lastGoodAvatarName = myAvatar->getFullAvatarModelName(); + fullAvatarURLChanged(_lastGoodAvatarURL.toString(), _lastGoodAvatarName); ui.sendDataCheckBox->setChecked(!menuInstance->isOptionChecked(MenuOption::DisableActivityLogger)); @@ -211,7 +224,11 @@ void PreferencesDialog::savePreferences() { } myAvatar->setCollisionSoundURL(ui.collisionSoundURLEdit->text()); - // avatar model url is already persisted by fullAvatarURLChanged() + + // MyAvatar persists its own data. If it doesn't agree with what the user has explicitly accepted, set it back to old values. + if (_lastGoodAvatarURL != myAvatar->getFullAvatarURLFromPreferences()) { + restoreLastGoodAvatar(); + } if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableActivityLogger) != ui.sendDataCheckBox->isChecked()) { diff --git a/interface/src/ui/PreferencesDialog.h b/interface/src/ui/PreferencesDialog.h index 47341b8feb..6d7a87b97c 100644 --- a/interface/src/ui/PreferencesDialog.h +++ b/interface/src/ui/PreferencesDialog.h @@ -33,6 +33,9 @@ protected: private: void loadPreferences(); void savePreferences(); + QUrl _lastGoodAvatarURL; + QString _lastGoodAvatarName; + void restoreLastGoodAvatar(); Ui_PreferencesDialog ui; @@ -42,6 +45,7 @@ private: private slots: void accept(); + void reject(); void openFullAvatarModelBrowser(); void openSnapshotLocationBrowser(); void openScriptsLocationBrowser(); From f00d3c037d99584892dcc468cd3b2509ae45205a Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 13 Aug 2015 17:36:03 -0700 Subject: [PATCH 021/102] whitespace --- interface/src/ui/PreferencesDialog.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 63170fdd70..a6340d3955 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -48,9 +48,9 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) : connect(ui.buttonReloadDefaultScripts, &QPushButton::clicked, Application::getInstance(), &Application::loadDefaultScripts); connect(ui.buttonChangeAppearance, &QPushButton::clicked, this, &PreferencesDialog::openFullAvatarModelBrowser); - connect(ui.appearanceDescription, &QLineEdit::textChanged, this, [this](const QString& url) { - this->fullAvatarURLChanged(url, ""); - }); + connect(ui.appearanceDescription, &QLineEdit::textChanged, this, [this](const QString& url) { + this->fullAvatarURLChanged(url, ""); + }); connect(Application::getInstance(), &Application::fullAvatarURLChanged, this, &PreferencesDialog::fullAvatarURLChanged); // move dialog to left side From daeb90c1e0644c30d9f4338972a7e36bb7dd1a86 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 14 Aug 2015 09:35:39 -0700 Subject: [PATCH 022/102] fix clamp in AddEntityOperator --- libraries/entities/src/AddEntityOperator.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/entities/src/AddEntityOperator.cpp b/libraries/entities/src/AddEntityOperator.cpp index db9a18a3e9..51015c1ff4 100644 --- a/libraries/entities/src/AddEntityOperator.cpp +++ b/libraries/entities/src/AddEntityOperator.cpp @@ -26,8 +26,7 @@ AddEntityOperator::AddEntityOperator(EntityTree* tree, // caller must have verified existence of newEntity assert(_newEntity); - // FIXME - how does this change for new origin??? - _newEntityBox = _newEntity->getMaximumAACube().clamp(0.0f, (float)TREE_SCALE); + _newEntityBox = _newEntity->getMaximumAACube().clamp((float)(-HALF_TREE_SCALE), (float)HALF_TREE_SCALE); } bool AddEntityOperator::preRecursion(OctreeElement* element) { From bdc78e9666a6fe95f9b931320f0571cd8d7896d6 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 14 Aug 2015 10:16:48 -0700 Subject: [PATCH 023/102] some CR cleanup --- libraries/entities/src/EntitySimulation.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index c614b62c91..06f5023193 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -113,8 +113,7 @@ void EntitySimulation::sortEntitiesThatMoved() { // External changes to entity position/shape are expected to be sorted outside of the EntitySimulation. PerformanceTimer perfTimer("sortingEntities"); MovingEntitiesOperator moveOperator(_entityTree); - AACube domainBounds(glm::vec3((float)-HALF_TREE_SCALE, (float)-HALF_TREE_SCALE, (float)-HALF_TREE_SCALE), - (float)TREE_SCALE); + AACube domainBounds(glm::vec3((float)-HALF_TREE_SCALE), (float)TREE_SCALE); SetOfEntities::iterator itemItr = _entitiesToSort.begin(); while (itemItr != _entitiesToSort.end()) { EntityItemPointer entity = *itemItr; @@ -196,8 +195,7 @@ void EntitySimulation::changeEntity(EntityItemPointer entity) { bool wasRemoved = false; uint32_t dirtyFlags = entity->getDirtyFlags(); if (dirtyFlags & EntityItem::DIRTY_POSITION) { - AACube domainBounds(glm::vec3((float)-HALF_TREE_SCALE, (float)-HALF_TREE_SCALE, (float)-HALF_TREE_SCALE), - (float)TREE_SCALE); + AACube domainBounds(glm::vec3((float)-HALF_TREE_SCALE), (float)TREE_SCALE); AACube newCube = entity->getMaximumAACube(); if (!domainBounds.touches(newCube)) { qCDebug(entities) << "Entity " << entity->getEntityItemID() << " moved out of domain bounds."; From 7c6a9b131d581644400879658d280435a11cfb22 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 14 Aug 2015 10:17:48 -0700 Subject: [PATCH 024/102] some CR cleanup --- interface/src/Util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index f62a6b8fc5..5a9ecfee67 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -44,7 +44,7 @@ void renderWorldBox(gpu::Batch& batch) { auto transform = Transform{}; batch.setModelTransform(transform); - // FIXME - new origin tweaks need to be done to this + // TODO - consider alternate rendering for negative build-able space in the domain geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(TREE_SCALE, 0.0f, 0.0f), red); geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, TREE_SCALE, 0.0f), green); geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, TREE_SCALE), blue); From 44fcf71f075bfc3136c0e2c99f6beba523555227 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 14 Aug 2015 15:26:49 -0700 Subject: [PATCH 025/102] change domain to be 32k and still have origin centered at 0 --- examples/edit.js | 2 +- libraries/entities/src/EntityItem.cpp | 13 ++----------- libraries/entities/src/EntityItem.h | 1 - libraries/networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 1 - libraries/octree/src/OctreeConstants.h | 2 +- 6 files changed, 5 insertions(+), 16 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 4cc38a0c3d..aea08640aa 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -1020,7 +1020,7 @@ function getPositionToCreateEntity() { var cameraPosition = Camera.position; - var HALF_TREE_SCALE = 16384 / 2; + var HALF_TREE_SCALE = 16384; var cameraOutOfBounds = cameraPosition.x < -HALF_TREE_SCALE || cameraPosition.y < -HALF_TREE_SCALE || cameraPosition.z < -HALF_TREE_SCALE; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 922170707b..0ffcc00ead 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -634,11 +634,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // but since we're using macros below we have to temporarily modify overwriteLocalData. bool oldOverwrite = overwriteLocalData; overwriteLocalData = overwriteLocalData && !weOwnSimulation; - if (args.bitstreamVersion >= VERSION_ENTITIES_CENTER_ORIGIN) { - READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition); - } else { - READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePositionOldOrigin); - } + READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition); READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation); READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocity); READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity); @@ -660,7 +656,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef } else { // legacy order of packing here // TODO: purge this logic in a few months from now (2015.07) - READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePositionOldOrigin); + READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition); READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions); READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation); READ_ENTITY_PROPERTY(PROP_DENSITY, float, updateDensity); @@ -1321,11 +1317,6 @@ void EntityItem::updatePosition(const glm::vec3& value) { } } -void EntityItem::updatePositionOldOrigin(const glm::vec3& value) { - glm::vec3 newValue = value - glm::vec3(HALF_TREE_SCALE); - updatePosition(newValue); -} - void EntityItem::updateDimensions(const glm::vec3& value) { auto delta = glm::distance(getDimensions(), value); if (delta > IGNORE_DIMENSIONS_DELTA) { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 936b2e4d21..e420d08709 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -363,7 +363,6 @@ public: // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags void updatePosition(const glm::vec3& value); - void updatePositionOldOrigin(const glm::vec3& value); void updateDimensions(const glm::vec3& value); void updateRotation(const glm::quat& rotation); void updateDensity(float value); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index a1af3c58c5..5562490344 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -67,7 +67,7 @@ PacketVersion versionForPacketType(PacketType::Value packetType) { case EntityAdd: case EntityEdit: case EntityData: - return VERSION_ENTITIES_CENTER_ORIGIN; + return VERSION_ENTITIES_POLYLINE; case AvatarData: return 12; default: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 613ea4913d..1aeadb1af9 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -142,6 +142,5 @@ const PacketVersion VERSION_ENTITIES_HAVE_SIMULATION_OWNER_AND_ACTIONS_OVER_WIRE const PacketVersion VERSION_ENTITIES_NEW_PROTOCOL_LAYER = 35; const PacketVersion VERSION_POLYVOX_TEXTURES = 36; const PacketVersion VERSION_ENTITIES_POLYLINE = 37; -const PacketVersion VERSION_ENTITIES_CENTER_ORIGIN = 38; #endif // hifi_PacketHeaders_h \ No newline at end of file diff --git a/libraries/octree/src/OctreeConstants.h b/libraries/octree/src/OctreeConstants.h index acfa1d14c6..a98f042006 100644 --- a/libraries/octree/src/OctreeConstants.h +++ b/libraries/octree/src/OctreeConstants.h @@ -17,7 +17,7 @@ const quint64 CHANGE_FUDGE = 1000 * 200; // useconds of fudge in determining if we want to resend changed voxels -const int TREE_SCALE = 16384; // ~10 miles.. This is the number of meters of the 0.0 to 1.0 voxel universe +const int TREE_SCALE = 32768; // ~20 miles.. This is the number of meters of the 0.0 to 1.0 voxel universe const int HALF_TREE_SCALE = TREE_SCALE / 2; // This controls the LOD. Larger number will make smaller voxels visible at greater distance. From 65864b1876e4f1843c853f3e5ae28bbb5ce3bb48 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 14 Aug 2015 15:30:16 -0700 Subject: [PATCH 026/102] only draw axis for HALF_TREE_SCALE --- interface/src/Util.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 5a9ecfee67..8f687a93d6 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -45,11 +45,11 @@ void renderWorldBox(gpu::Batch& batch) { batch.setModelTransform(transform); // TODO - consider alternate rendering for negative build-able space in the domain - geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(TREE_SCALE, 0.0f, 0.0f), red); - geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, TREE_SCALE, 0.0f), green); - geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, TREE_SCALE), blue); - geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, TREE_SCALE), glm::vec3(TREE_SCALE, 0.0f, TREE_SCALE), grey); - geometryCache->renderLine(batch, glm::vec3(TREE_SCALE, 0.0f, TREE_SCALE), glm::vec3(TREE_SCALE, 0.0f, 0.0f), grey); + geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(HALF_TREE_SCALE, 0.0f, 0.0f), red); + geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, HALF_TREE_SCALE, 0.0f), green); + geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, HALF_TREE_SCALE), blue); + geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, HALF_TREE_SCALE), glm::vec3(HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), grey); + geometryCache->renderLine(batch, glm::vec3(HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), glm::vec3(HALF_TREE_SCALE, 0.0f, 0.0f), grey); // Draw meter markers along the 3 axis to help with measuring things const float MARKER_DISTANCE = 1.0f; From d28c555a79c20365ce3cb37f8eea160a67102d4d Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Fri, 14 Aug 2015 16:47:34 -0700 Subject: [PATCH 027/102] Synchronize eye joint and debugging vectors when the other avatar is looking at me. --- interface/src/Application.cpp | 4 ++++ interface/src/avatar/Head.cpp | 16 ++++++++++++++- interface/src/avatar/SkeletonModel.cpp | 27 ++++++++++++++++++-------- libraries/animation/src/Rig.cpp | 9 +++++++-- libraries/animation/src/Rig.h | 2 ++ 5 files changed, 47 insertions(+), 11 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2f6b038e40..1b8ba2d4cd 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2352,6 +2352,10 @@ void Application::updateMouseRay() { } } +// Called during Application::update immediately before AvatarManager::updateMyAvatar, updating my data that is then sent to everyone. +// (Maybe this code should be moved there?) +// The principal result is to call updateLookAtTargetAvatar() and then setLookAtPosition(). +// Note that it is called BEFORE we update position or joints based on sensors, etc. void Application::updateMyAvatarLookAtPosition() { PerformanceTimer perfTimer("lookAt"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index cec9079443..065b655628 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -344,6 +344,20 @@ glm::quat Head::getFinalOrientationInLocalFrame() const { return glm::quat(glm::radians(glm::vec3(getFinalPitch(), getFinalYaw(), getFinalRoll() ))); } +// Everyone else's head keeps track of a lookAtPosition that everybody sees the same, and refers to where that head +// is looking in model space -- e.g., at someone's eyeball, or between their eyes, or mouth, etc. Everyon's Interface +// will have the same value for the lookAtPosition of any given head. +// +// Everyone else's head also keeps track of a correctedLookAtPosition that may be different for the same head within +// different Interfaces. If that head is not looking at me, the correctedLookAtPosition is the same as the lookAtPosition. +// However, if that head is looking at me, then I will attempt to adjust the lookAtPosition by the difference between +// my (singular) eye position and my actual camera position. This adjustment is used on their eyeballs during rendering +// (and also on any lookAt vector display for that head, during rendering). Note that: +// 1. this adjustment can be made directly to the other head's eyeball joints, because we won't be send their joint information to others. +// 2. the corrected position is a separate ivar, so the common/uncorrected value is still available +// +// There is a pun here: The two lookAtPositions will always be the same for my own avatar in my own Interface, because I +// will not be looking at myself. (Even in a mirror, I will be looking at the camera.) glm::vec3 Head::getCorrectedLookAtPosition() { if (isLookingAtMe()) { return _correctedLookAtPosition; @@ -364,7 +378,7 @@ void Head::setCorrectedLookAtPosition(glm::vec3 correctedLookAtPosition) { bool Head::isLookingAtMe() { // Allow for outages such as may be encountered during avatar movement quint64 now = usecTimestampNow(); - const quint64 LOOKING_AT_ME_GAP_ALLOWED = 1000000; // microseconds + const quint64 LOOKING_AT_ME_GAP_ALLOWED = (5 * 1000.0f * 1000.0f) / 60.0f; // n frames, in microseconds return _isLookingAtMe || (now - _wasLastLookingAtMe) < LOOKING_AT_ME_GAP_ALLOWED; } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index e870ba2140..e11e8996ca 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -97,7 +97,7 @@ void SkeletonModel::initJointStates(QVector states) { } const float PALM_PRIORITY = DEFAULT_PRIORITY; - +// Called within Model::simulate call, below. void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { if (_owningAvatar->isMyAvatar()) { _rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation()); @@ -105,26 +105,37 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { Model::updateRig(deltaTime, parentTransform); if (_owningAvatar->isMyAvatar()) { const FBXGeometry& geometry = _geometry->getFBXGeometry(); + Head* head = _owningAvatar->getHead(); Rig::HeadParameters params; params.modelRotation = getRotation(); params.modelTranslation = getTranslation(); - params.leanSideways = _owningAvatar->getHead()->getFinalLeanSideways(); - params.leanForward = _owningAvatar->getHead()->getFinalLeanForward(); - params.torsoTwist = _owningAvatar->getHead()->getTorsoTwist(); - params.localHeadOrientation = _owningAvatar->getHead()->getFinalOrientationInLocalFrame(); - params.worldHeadOrientation = _owningAvatar->getHead()->getFinalOrientationInWorldFrame(); - params.eyeLookAt = _owningAvatar->getHead()->getLookAtPosition(); - params.eyeSaccade = _owningAvatar->getHead()->getSaccade(); + params.leanSideways = head->getFinalLeanSideways(); + params.leanForward = head->getFinalLeanForward(); + params.torsoTwist = head->getTorsoTwist(); + params.localHeadOrientation = head->getFinalOrientationInLocalFrame(); + params.worldHeadOrientation = head->getFinalOrientationInWorldFrame(); + params.eyeLookAt = head->getLookAtPosition(); + params.eyeSaccade = head->getSaccade(); params.leanJointIndex = geometry.leanJointIndex; params.neckJointIndex = geometry.neckJointIndex; params.leftEyeJointIndex = geometry.leftEyeJointIndex; params.rightEyeJointIndex = geometry.rightEyeJointIndex; _rig->updateFromHeadParameters(params); + } else if (true) { //(_owningAvatar->getHead()->isLookingAtMe()) { + // Other avatars joint, including their eyes, will already be set just like any other joints + // from the wire data. But when looking at me, we want the eyes to use the corrected lookAt. + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + Head* head = _owningAvatar->getHead(); + _rig->updateEyeJoints(geometry.leftEyeJointIndex, geometry.rightEyeJointIndex, + getTranslation(), getRotation(), + head->getFinalOrientationInWorldFrame(), head->getCorrectedLookAtPosition()); } } +// Called by Avatar::simulate after it has set the joint states (fullUpdate true if changed), +// but just before head has been simulated. 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)); diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 1a8bd0bbad..2212e06e31 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -786,8 +786,8 @@ glm::quat Rig::getJointDefaultRotationInParentFrame(int jointIndex) { void Rig::updateFromHeadParameters(const HeadParameters& params) { updateLeanJoint(params.leanJointIndex, params.leanSideways, params.leanForward, params.torsoTwist); updateNeckJoint(params.neckJointIndex, params.localHeadOrientation, params.leanSideways, params.leanForward, params.torsoTwist); - updateEyeJoint(params.leftEyeJointIndex, params.modelTranslation, params.modelRotation, params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade); - updateEyeJoint(params.rightEyeJointIndex, params.modelTranslation, params.modelRotation, params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade); + updateEyeJoints(params.leftEyeJointIndex, params.rightEyeJointIndex, params.modelTranslation, params.modelRotation, + params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade); } void Rig::updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist) { @@ -828,6 +828,11 @@ void Rig::updateNeckJoint(int index, const glm::quat& localHeadOrientation, floa } } +void Rig::updateEyeJoints(int leftEyeIndex, int rightEyeIndex, const glm::vec3& modelTranslation, const glm::quat& modelRotation, + const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade) { + updateEyeJoint(leftEyeIndex, modelTranslation, modelRotation, worldHeadOrientation, lookAtSpot, saccade); + updateEyeJoint(rightEyeIndex, modelTranslation, modelRotation, worldHeadOrientation, lookAtSpot, saccade); +} void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade) { if (index >= 0 && _jointStates[index].getParentIndex() >= 0) { auto& state = _jointStates[index]; diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index face79bc15..8da20062cf 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -157,6 +157,8 @@ public: void setEnableRig(bool isEnabled) { _enableRig = isEnabled; } void updateFromHeadParameters(const HeadParameters& params); + void updateEyeJoints(int leftEyeIndex, int rightEyeIndex, const glm::vec3& modelTranslation, const glm::quat& modelRotation, + const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade = glm::vec3(0.0f)); virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation, float scale, float priority) = 0; From eeeaa8050d75f6fd796832e25b3150ddb435da2d Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Fri, 14 Aug 2015 18:58:49 -0700 Subject: [PATCH 028/102] Fix the rush jobs, so gustavo can build build for me... --- interface/src/avatar/Head.cpp | 2 +- interface/src/avatar/SkeletonModel.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 065b655628..9ab2c83a79 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -378,7 +378,7 @@ void Head::setCorrectedLookAtPosition(glm::vec3 correctedLookAtPosition) { bool Head::isLookingAtMe() { // Allow for outages such as may be encountered during avatar movement quint64 now = usecTimestampNow(); - const quint64 LOOKING_AT_ME_GAP_ALLOWED = (5 * 1000.0f * 1000.0f) / 60.0f; // n frames, in microseconds + const quint64 LOOKING_AT_ME_GAP_ALLOWED = (5 * 1000 * 1000) / 60; // n frames, in microseconds return _isLookingAtMe || (now - _wasLastLookingAtMe) < LOOKING_AT_ME_GAP_ALLOWED; } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index e11e8996ca..831fb26abb 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -123,7 +123,7 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { params.rightEyeJointIndex = geometry.rightEyeJointIndex; _rig->updateFromHeadParameters(params); - } else if (true) { //(_owningAvatar->getHead()->isLookingAtMe()) { + } else if (_owningAvatar->getHead()->isLookingAtMe()) { // Other avatars joint, including their eyes, will already be set just like any other joints // from the wire data. But when looking at me, we want the eyes to use the corrected lookAt. const FBXGeometry& geometry = _geometry->getFBXGeometry(); From 27e5322cb4275276efb0828865553188e1491754 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 15 Aug 2015 11:25:27 -0700 Subject: [PATCH 029/102] compute polyvox collision hull differently for marching-cube surfaces --- .../src/RenderablePolyVoxEntityItem.cpp | 132 ++++++++++++------ 1 file changed, 91 insertions(+), 41 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 23093b9f3f..be2d9b8fe6 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -40,7 +40,7 @@ #include "EntityTreeRenderer.h" #include "polyvox_vert.h" #include "polyvox_frag.h" -#include "RenderablePolyVoxEntityItem.h" +#include "RenderablePolyVoxEntityItem.h" gpu::PipelinePointer RenderablePolyVoxEntityItem::_pipeline = nullptr; @@ -553,53 +553,103 @@ void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) { } _points.clear(); - unsigned int i = 0; - - glm::mat4 wToM = voxelToLocalMatrix(); - AABox box; + glm::mat4 vtoM = voxelToLocalMatrix(); - for (int z = 0; z < _voxelVolumeSize.z; z++) { - for (int y = 0; y < _voxelVolumeSize.y; y++) { - for (int x = 0; x < _voxelVolumeSize.x; x++) { - if (getVoxel(x, y, z) > 0) { - QVector pointsInPart; + if (_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_MARCHING_CUBES) { + unsigned int i = 0; + /* pull top-facing triangles into polyhedrons so they can be walked on */ + const model::MeshPointer& mesh = _modelGeometry.getMesh(); + const gpu::BufferView vertexBufferView = mesh->getVertexBuffer(); + const gpu::BufferView& indexBufferView = mesh->getIndexBuffer(); + gpu::BufferView::Iterator it = indexBufferView.cbegin(); + while (it != indexBufferView.cend()) { + uint32_t p0Index = *(it++); + uint32_t p1Index = *(it++); + uint32_t p2Index = *(it++); - float offL = -0.5f; - float offH = 0.5f; + const glm::vec3 p0 = vertexBufferView.get(p0Index); + const glm::vec3 p1 = vertexBufferView.get(p1Index); + const glm::vec3 p2 = vertexBufferView.get(p2Index); - glm::vec3 p000 = glm::vec3(wToM * glm::vec4(x + offL, y + offL, z + offL, 1.0f)); - glm::vec3 p001 = glm::vec3(wToM * glm::vec4(x + offL, y + offL, z + offH, 1.0f)); - glm::vec3 p010 = glm::vec3(wToM * glm::vec4(x + offL, y + offH, z + offL, 1.0f)); - glm::vec3 p011 = glm::vec3(wToM * glm::vec4(x + offL, y + offH, z + offH, 1.0f)); - glm::vec3 p100 = glm::vec3(wToM * glm::vec4(x + offH, y + offL, z + offL, 1.0f)); - glm::vec3 p101 = glm::vec3(wToM * glm::vec4(x + offH, y + offL, z + offH, 1.0f)); - glm::vec3 p110 = glm::vec3(wToM * glm::vec4(x + offH, y + offH, z + offL, 1.0f)); - glm::vec3 p111 = glm::vec3(wToM * glm::vec4(x + offH, y + offH, z + offH, 1.0f)); + qDebug() << p0Index << p1Index << p2Index; + qDebug() << (int)p0.x << (int)p0.y << (int)p0.z; - box += p000; - box += p001; - box += p010; - box += p011; - box += p100; - box += p101; - box += p110; - box += p111; + glm::vec3 av = (p0 + p1 + p2) / 3.0f; // center of the triangular face + glm::vec3 normal = glm::normalize(glm::cross(p1 - p0, p2 - p0)); + float threshold = 1.0f / sqrtf(3.0f); + if (normal.y > -threshold && normal.y < threshold) { + // this triangle is more a wall than a floor, skip it. + } else { + float dropAmount = 2.0f; // XXX magic + glm::vec3 p3 = av - glm::vec3(0.0f, dropAmount, 0.0f); - pointsInPart << p000; - pointsInPart << p001; - pointsInPart << p010; - pointsInPart << p011; - pointsInPart << p100; - pointsInPart << p101; - pointsInPart << p110; - pointsInPart << p111; + glm::vec3 p0Model = glm::vec3(vtoM * glm::vec4(p0, 1.0f)); + glm::vec3 p1Model = glm::vec3(vtoM * glm::vec4(p1, 1.0f)); + glm::vec3 p2Model = glm::vec3(vtoM * glm::vec4(p2, 1.0f)); + glm::vec3 p3Model = glm::vec3(vtoM * glm::vec4(p3, 1.0f)); - // add next convex hull - QVector newMeshPoints; - _points << newMeshPoints; - // add points to the new convex hull - _points[i++] << pointsInPart; + box += p0Model; + box += p1Model; + box += p2Model; + box += p3Model; + + QVector pointsInPart; + pointsInPart << p0Model; + pointsInPart << p1Model; + pointsInPart << p2Model; + pointsInPart << p3Model; + // add next convex hull + QVector newMeshPoints; + _points << newMeshPoints; + // add points to the new convex hull + _points[i++] << pointsInPart; + } + } + } else { + unsigned int i = 0; + for (int z = 0; z < _voxelVolumeSize.z; z++) { + for (int y = 0; y < _voxelVolumeSize.y; y++) { + for (int x = 0; x < _voxelVolumeSize.x; x++) { + if (getVoxel(x, y, z) > 0) { + QVector pointsInPart; + + float offL = -0.5f; + float offH = 0.5f; + + glm::vec3 p000 = glm::vec3(vtoM * glm::vec4(x + offL, y + offL, z + offL, 1.0f)); + glm::vec3 p001 = glm::vec3(vtoM * glm::vec4(x + offL, y + offL, z + offH, 1.0f)); + glm::vec3 p010 = glm::vec3(vtoM * glm::vec4(x + offL, y + offH, z + offL, 1.0f)); + glm::vec3 p011 = glm::vec3(vtoM * glm::vec4(x + offL, y + offH, z + offH, 1.0f)); + glm::vec3 p100 = glm::vec3(vtoM * glm::vec4(x + offH, y + offL, z + offL, 1.0f)); + glm::vec3 p101 = glm::vec3(vtoM * glm::vec4(x + offH, y + offL, z + offH, 1.0f)); + glm::vec3 p110 = glm::vec3(vtoM * glm::vec4(x + offH, y + offH, z + offL, 1.0f)); + glm::vec3 p111 = glm::vec3(vtoM * glm::vec4(x + offH, y + offH, z + offH, 1.0f)); + + box += p000; + box += p001; + box += p010; + box += p011; + box += p100; + box += p101; + box += p110; + box += p111; + + pointsInPart << p000; + pointsInPart << p001; + pointsInPart << p010; + pointsInPart << p011; + pointsInPart << p100; + pointsInPart << p101; + pointsInPart << p110; + pointsInPart << p111; + + // add next convex hull + QVector newMeshPoints; + _points << newMeshPoints; + // add points to the new convex hull + _points[i++] << pointsInPart; + } } } } From 79a7755cdbc762163394195d5de829ba2ba0405f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 15 Aug 2015 12:18:36 -0700 Subject: [PATCH 030/102] add SURFACE_EDGED_MARCHING_CUBES polyvox surface extraction style --- examples/html/entityProperties.html | 1 + .../src/RenderablePolyVoxEntityItem.cpp | 21 +++++++++++-------- libraries/entities/src/PolyVoxEntityItem.h | 3 ++- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index a2358b40d5..ad489afddf 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -1072,6 +1072,7 @@ + diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index be2d9b8fe6..07026f073c 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -78,6 +78,7 @@ bool inUserBounds(const PolyVox::SimpleVolume* vol, PolyVoxEntityItem:: return true; case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: + case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES: if (x < 0 || y < 0 || z < 0 || x >= vol->getWidth() - 2 || y >= vol->getHeight() - 2 || z >= vol->getDepth() - 2) { return false; @@ -112,7 +113,7 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) _onCount = 0; - if (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC) { + if (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC || _voxelSurfaceStyle == SURFACE_EDGED_MARCHING_CUBES) { // with _EDGED_ we maintain an extra box of voxels around those that the user asked for. This // changes how the surface extractor acts -- mainly it becomes impossible to have holes in the // generated mesh. The non _EDGED_ modes will leave holes in the mesh at the edges of the @@ -156,8 +157,7 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) void RenderablePolyVoxEntityItem::updateVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { // if we are switching to or from "edged" we need to force a resize of _volData. - if (voxelSurfaceStyle == SURFACE_EDGED_CUBIC || - _voxelSurfaceStyle == SURFACE_EDGED_CUBIC) { + if (voxelSurfaceStyle == SURFACE_EDGED_CUBIC || _voxelSurfaceStyle == SURFACE_EDGED_MARCHING_CUBES) { if (_volData) { delete _volData; } @@ -182,11 +182,11 @@ glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const { glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units switch (_voxelSurfaceStyle) { case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: - return scale / 2.0f; - case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: - return scale / -2.0f; case PolyVoxEntityItem::SURFACE_CUBIC: return scale / 2.0f; + case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: + case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES: + return scale / -2.0f; } return glm::vec3(0.0f, 0.0f, 0.0f); } @@ -223,7 +223,7 @@ uint8_t RenderablePolyVoxEntityItem::getVoxel(int x, int y, int z) { // voxels all around the requested voxel space. Having the empty voxels around // the edges changes how the surface extractor behaves. - if (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC) { + if (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC || _voxelSurfaceStyle == SURFACE_EDGED_MARCHING_CUBES) { return _volData->getVoxelAt(x + 1, y + 1, z + 1); } return _volData->getVoxelAt(x, y, z); @@ -238,7 +238,7 @@ void RenderablePolyVoxEntityItem::setVoxelInternal(int x, int y, int z, uint8_t updateOnCount(x, y, z, toValue); - if (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC) { + if (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC || _voxelSurfaceStyle == SURFACE_EDGED_MARCHING_CUBES) { _volData->setVoxelAt(x + 1, y + 1, z + 1, toValue); } else { _volData->setVoxelAt(x, y, z, toValue); @@ -399,6 +399,7 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o glm::vec4 result = callback._result; switch (_voxelSurfaceStyle) { case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: + case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES: result -= glm::vec4(1, 1, 1, 0); // compensate for the extra voxel border break; case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: @@ -556,7 +557,8 @@ void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) { AABox box; glm::mat4 vtoM = voxelToLocalMatrix(); - if (_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_MARCHING_CUBES) { + if (_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_MARCHING_CUBES || + _voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES) { unsigned int i = 0; /* pull top-facing triangles into polyhedrons so they can be walked on */ const model::MeshPointer& mesh = _modelGeometry.getMesh(); @@ -683,6 +685,7 @@ void RenderablePolyVoxEntityItem::getModel() { PolyVox::SurfaceMesh polyVoxMesh; switch (_voxelSurfaceStyle) { + case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES: case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: { PolyVox::MarchingCubesSurfaceExtractor> surfaceExtractor (_volData, _volData->getEnclosingRegion(), &polyVoxMesh); diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 0d0ab060f9..29d0b2e595 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -58,7 +58,8 @@ class PolyVoxEntityItem : public EntityItem { enum PolyVoxSurfaceStyle { SURFACE_MARCHING_CUBES, SURFACE_CUBIC, - SURFACE_EDGED_CUBIC + SURFACE_EDGED_CUBIC, + SURFACE_EDGED_MARCHING_CUBES }; void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle); From 09a9deabdbfd3a19038135f145da2746b1a65781 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 15 Aug 2015 12:55:24 -0700 Subject: [PATCH 031/102] compute polyvox collision hull differently for marching-cube surfaces --- .../src/RenderablePolyVoxEntityItem.cpp | 50 ++++++++----------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 07026f073c..b803e32e1e 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -43,6 +43,7 @@ #include "RenderablePolyVoxEntityItem.h" gpu::PipelinePointer RenderablePolyVoxEntityItem::_pipeline = nullptr; +const float MARCHING_CUBE_COLLISION_HULL_OFFSET = 0.5; EntityItemPointer RenderablePolyVoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { return std::make_shared(entityID, properties); @@ -574,39 +575,30 @@ void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) { const glm::vec3 p1 = vertexBufferView.get(p1Index); const glm::vec3 p2 = vertexBufferView.get(p2Index); - qDebug() << p0Index << p1Index << p2Index; - qDebug() << (int)p0.x << (int)p0.y << (int)p0.z; - glm::vec3 av = (p0 + p1 + p2) / 3.0f; // center of the triangular face glm::vec3 normal = glm::normalize(glm::cross(p1 - p0, p2 - p0)); - float threshold = 1.0f / sqrtf(3.0f); - if (normal.y > -threshold && normal.y < threshold) { - // this triangle is more a wall than a floor, skip it. - } else { - float dropAmount = 2.0f; // XXX magic - glm::vec3 p3 = av - glm::vec3(0.0f, dropAmount, 0.0f); + glm::vec3 p3 = av - normal * MARCHING_CUBE_COLLISION_HULL_OFFSET; - glm::vec3 p0Model = glm::vec3(vtoM * glm::vec4(p0, 1.0f)); - glm::vec3 p1Model = glm::vec3(vtoM * glm::vec4(p1, 1.0f)); - glm::vec3 p2Model = glm::vec3(vtoM * glm::vec4(p2, 1.0f)); - glm::vec3 p3Model = glm::vec3(vtoM * glm::vec4(p3, 1.0f)); + glm::vec3 p0Model = glm::vec3(vtoM * glm::vec4(p0, 1.0f)); + glm::vec3 p1Model = glm::vec3(vtoM * glm::vec4(p1, 1.0f)); + glm::vec3 p2Model = glm::vec3(vtoM * glm::vec4(p2, 1.0f)); + glm::vec3 p3Model = glm::vec3(vtoM * glm::vec4(p3, 1.0f)); - box += p0Model; - box += p1Model; - box += p2Model; - box += p3Model; + box += p0Model; + box += p1Model; + box += p2Model; + box += p3Model; - QVector pointsInPart; - pointsInPart << p0Model; - pointsInPart << p1Model; - pointsInPart << p2Model; - pointsInPart << p3Model; - // add next convex hull - QVector newMeshPoints; - _points << newMeshPoints; - // add points to the new convex hull - _points[i++] << pointsInPart; - } + QVector pointsInPart; + pointsInPart << p0Model; + pointsInPart << p1Model; + pointsInPart << p2Model; + pointsInPart << p3Model; + // add next convex hull + QVector newMeshPoints; + _points << newMeshPoints; + // add points to the new convex hull + _points[i++] << pointsInPart; } } else { unsigned int i = 0; @@ -790,8 +782,6 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { _zTexture = DependencyManager::get()->getTexture(_zTextureURL); } - batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - if (_xTexture) { batch.setResourceTexture(0, _xTexture->getGPUTexture()); } else { From 5ecdbaa19d591cbd4f51f6914cfe696c63a58161 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 15 Aug 2015 15:18:25 -0700 Subject: [PATCH 032/102] have functions that change polyvox voxes return true if they changed anything, else false. added voxelCoordsToWorldCoords and worldCoordsToVoxelCoords --- examples/voxels.js | 16 +++- .../src/RenderablePolyVoxEntityItem.cpp | 59 +++++++++------ .../src/RenderablePolyVoxEntityItem.h | 18 ++--- .../entities/src/EntityScriptingInterface.cpp | 75 ++++++++++++++----- .../entities/src/EntityScriptingInterface.h | 5 +- libraries/entities/src/PolyVoxEntityItem.h | 15 ++-- 6 files changed, 128 insertions(+), 60 deletions(-) diff --git a/examples/voxels.js b/examples/voxels.js index 9627b40701..c70111153b 100644 --- a/examples/voxels.js +++ b/examples/voxels.js @@ -7,10 +7,15 @@ function attemptVoxelChange(intersection) { var success = false; for (var i = 0; i < ids.length; i++) { var id = ids[i]; + // var voxelCoords = Entities.worldCoordsToVoxelCoords(id, intersection.intersection); + if (controlHeld) { // hold control to erase a sphere - if (Entities.setVoxelSphere(id, intersection.intersection, 1.0, 0)) { - success = true; + for (var r = 1.0; r < 17.0; r++) { + if (Entities.setVoxelSphere(id, intersection.intersection, r, 0)) { + success = true; + break; + } } } else if (shiftHeld) { // hold shift to set all voxels to 255 @@ -19,8 +24,11 @@ function attemptVoxelChange(intersection) { } } else { // no modifier key means to add a sphere - if (Entities.setVoxelSphere(id, intersection.intersection, 1.0, 255)) { - success = true; + for (var r = 1.0; r < 17.0; r++) { + if (Entities.setVoxelSphere(id, intersection.intersection, r, 255)) { + success = true; + break; + } } } } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index b803e32e1e..5b0c4ee691 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -230,78 +230,88 @@ uint8_t RenderablePolyVoxEntityItem::getVoxel(int x, int y, int z) { return _volData->getVoxelAt(x, y, z); } -void RenderablePolyVoxEntityItem::setVoxelInternal(int x, int y, int z, uint8_t toValue) { +bool RenderablePolyVoxEntityItem::setVoxelInternal(int x, int y, int z, uint8_t toValue) { // set a voxel without recompressing the voxel data assert(_volData); + bool result = false; if (!inUserBounds(_volData, _voxelSurfaceStyle, x, y, z)) { - return; + return false; } - updateOnCount(x, y, z, toValue); + result = updateOnCount(x, y, z, toValue); if (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC || _voxelSurfaceStyle == SURFACE_EDGED_MARCHING_CUBES) { _volData->setVoxelAt(x + 1, y + 1, z + 1, toValue); } else { _volData->setVoxelAt(x, y, z, toValue); } + + return result; } -void RenderablePolyVoxEntityItem::setVoxel(int x, int y, int z, uint8_t toValue) { +bool RenderablePolyVoxEntityItem::setVoxel(int x, int y, int z, uint8_t toValue) { if (_locked) { - return; + return false; } - setVoxelInternal(x, y, z, toValue); + bool result = setVoxelInternal(x, y, z, toValue); compressVolumeData(); + return result; } -void RenderablePolyVoxEntityItem::updateOnCount(int x, int y, int z, uint8_t toValue) { +bool RenderablePolyVoxEntityItem::updateOnCount(int x, int y, int z, uint8_t toValue) { // keep _onCount up to date if (!inUserBounds(_volData, _voxelSurfaceStyle, x, y, z)) { - return; + return false; } uint8_t uVoxelValue = getVoxel(x, y, z); if (toValue != 0) { if (uVoxelValue == 0) { _onCount++; + return true; } } else { // toValue == 0 if (uVoxelValue != 0) { _onCount--; assert(_onCount >= 0); + return true; } } + return false; } -void RenderablePolyVoxEntityItem::setAll(uint8_t toValue) { +bool RenderablePolyVoxEntityItem::setAll(uint8_t toValue) { + bool result = false; if (_locked) { - return; + return false; } for (int z = 0; z < _voxelVolumeSize.z; z++) { for (int y = 0; y < _voxelVolumeSize.y; y++) { for (int x = 0; x < _voxelVolumeSize.x; x++) { - setVoxelInternal(x, y, z, toValue); + result |= setVoxelInternal(x, y, z, toValue); } } } compressVolumeData(); + return result; } -void RenderablePolyVoxEntityItem::setVoxelInVolume(glm::vec3 position, uint8_t toValue) { +bool RenderablePolyVoxEntityItem::setVoxelInVolume(glm::vec3 position, uint8_t toValue) { if (_locked) { - return; + return false; } // same as setVoxel but takes a vector rather than 3 floats. - setVoxel((int)position.x, (int)position.y, (int)position.z, toValue); + return setVoxel((int)position.x, (int)position.y, (int)position.z, toValue); } -void RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue) { +bool RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue) { + bool result = false; if (_locked) { - return; + return false; } // This three-level for loop iterates over every voxel in the volume @@ -314,22 +324,22 @@ void RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radi float fDistToCenter = glm::distance(pos, center); // If the current voxel is less than 'radius' units from the center then we make it solid. if (fDistToCenter <= radius) { - updateOnCount(x, y, z, toValue); - setVoxelInternal(x, y, z, toValue); + result |= setVoxelInternal(x, y, z, toValue); } } } } compressVolumeData(); + return result; } -void RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float radiusWorldCoords, uint8_t toValue) { +bool RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float radiusWorldCoords, uint8_t toValue) { // glm::vec3 centerVoxelCoords = worldToVoxelCoordinates(centerWorldCoords); glm::vec4 centerVoxelCoords = worldToVoxelMatrix() * glm::vec4(centerWorldCoords, 1.0f); glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units float scaleY = scale.y; float radiusVoxelCoords = radiusWorldCoords / scaleY; - setSphereInVolume(glm::vec3(centerVoxelCoords), radiusVoxelCoords, toValue); + return setSphereInVolume(glm::vec3(centerVoxelCoords), radiusVoxelCoords, toValue); } class RaycastFunctor @@ -508,7 +518,6 @@ void RenderablePolyVoxEntityItem::decompressVolumeData() { for (int y = 0; y < voxelYSize; y++) { for (int x = 0; x < voxelXSize; x++) { int uncompressedIndex = (z * voxelYSize * voxelXSize) + (y * voxelZSize) + x; - updateOnCount(x, y, z, uncompressedData[uncompressedIndex]); setVoxelInternal(x, y, z, uncompressedData[uncompressedIndex]); } } @@ -845,3 +854,11 @@ namespace render { } } } + +glm::vec3 RenderablePolyVoxEntityItem::voxelCoordsToWorldCoords(glm::vec3 voxelCoords) { + return glm::vec3(voxelToWorldMatrix() * glm::vec4(voxelCoords, 1.0f)); +} + +glm::vec3 RenderablePolyVoxEntityItem::worldCoordsToVoxelCoords(glm::vec3 worldCoords) { + return glm::vec3(worldToVoxelMatrix() * glm::vec4(worldCoords, 1.0f)); +} diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index d495900ce9..17c8934577 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -54,9 +54,9 @@ public: } virtual uint8_t getVoxel(int x, int y, int z); - virtual void setVoxel(int x, int y, int z, uint8_t toValue); + virtual bool setVoxel(int x, int y, int z, uint8_t toValue); - void updateOnCount(int x, int y, int z, uint8_t new_value); + bool updateOnCount(int x, int y, int z, uint8_t new_value); void render(RenderArgs* args); virtual bool supportsDetailedRayIntersection() const { return true; } @@ -78,16 +78,16 @@ public: virtual bool isReadyToComputeShape(); virtual void computeShapeInfo(ShapeInfo& info); + virtual glm::vec3 voxelCoordsToWorldCoords(glm::vec3 voxelCoords); + virtual glm::vec3 worldCoordsToVoxelCoords(glm::vec3 worldCoords); // coords are in voxel-volume space - virtual void setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue); + virtual bool setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue); + virtual bool setVoxelInVolume(glm::vec3 position, uint8_t toValue); // coords are in world-space - virtual void setSphere(glm::vec3 center, float radius, uint8_t toValue); - - virtual void setAll(uint8_t toValue); - - virtual void setVoxelInVolume(glm::vec3 position, uint8_t toValue); + virtual bool setSphere(glm::vec3 center, float radius, uint8_t toValue); + virtual bool setAll(uint8_t toValue); virtual void setXTextureURL(QString xTextureURL); virtual void setYTextureURL(QString yTextureURL); @@ -107,7 +107,7 @@ private: // The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions // may not match _voxelVolumeSize. - void setVoxelInternal(int x, int y, int z, uint8_t toValue); + bool setVoxelInternal(int x, int y, int z, uint8_t toValue); void compressVolumeData(); void decompressVolumeData(); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 9654de0fc4..c3e71cef82 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -415,7 +415,7 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra } bool EntityScriptingInterface::setVoxels(QUuid entityID, - std::function actor) { + std::function actor) { if (!_entityTree) { return false; } @@ -435,7 +435,7 @@ bool EntityScriptingInterface::setVoxels(QUuid entityID, auto polyVoxEntity = std::dynamic_pointer_cast(entity); _entityTree->lockForWrite(); - actor(*polyVoxEntity); + bool result = actor(*polyVoxEntity); entity->setLastEdited(now); entity->setLastBroadcast(now); _entityTree->unlock(); @@ -448,42 +448,41 @@ bool EntityScriptingInterface::setVoxels(QUuid entityID, properties.setLastEdited(now); queueEntityMessage(PacketType::EntityEdit, entityID, properties); - return true; + return result; } bool EntityScriptingInterface::setPoints(QUuid entityID, std::function actor) { if (!_entityTree) { return false; } - + EntityItemPointer entity = static_cast(_entityTree->findEntityByEntityItemID(entityID)); if (!entity) { qCDebug(entities) << "EntityScriptingInterface::setPoints no entity with ID" << entityID; } - + EntityTypes::EntityType entityType = entity->getType(); - + if (entityType != EntityTypes::Line) { return false; } - + auto now = usecTimestampNow(); - + auto lineEntity = std::static_pointer_cast(entity); _entityTree->lockForWrite(); bool success = actor(*lineEntity); entity->setLastEdited(now); entity->setLastBroadcast(now); _entityTree->unlock(); - + _entityTree->lockForRead(); EntityItemProperties properties = entity->getProperties(); _entityTree->unlock(); - + properties.setLinePointsDirty(); properties.setLastEdited(now); - - + queueEntityMessage(PacketType::EntityEdit, entityID, properties); return success; } @@ -491,19 +490,19 @@ bool EntityScriptingInterface::setPoints(QUuid entityID, std::functiongetType(); - + if (entityType == EntityTypes::Line) { return setPoints(entityID, [points](LineEntityItem& lineEntity) -> bool { return (LineEntityItem*)lineEntity.setLinePoints(points); }); } - + return false; } @@ -658,3 +657,43 @@ QVariantMap EntityScriptingInterface::getActionArguments(const QUuid& entityID, }); return result; } + +glm::vec3 EntityScriptingInterface::voxelCoordsToWorldCoords(const QUuid& entityID, glm::vec3 voxelCoords) { + if (!_entityTree) { + return glm::vec3(0.0f); + } + + EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); + if (!entity) { + qCDebug(entities) << "EntityScriptingInterface::voxelCoordsToWorldCoords no entity with ID" << entityID; + return glm::vec3(0.0f); + } + + EntityTypes::EntityType entityType = entity->getType(); + if (entityType != EntityTypes::PolyVox) { + return glm::vec3(0.0f); + } + + auto polyVoxEntity = std::dynamic_pointer_cast(entity); + return polyVoxEntity->voxelCoordsToWorldCoords(voxelCoords); +} + +glm::vec3 EntityScriptingInterface::worldCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 worldCoords) { + if (!_entityTree) { + return glm::vec3(0.0f); + } + + EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); + if (!entity) { + qCDebug(entities) << "EntityScriptingInterface::worldCoordsToVoxelCoords no entity with ID" << entityID; + return glm::vec3(0.0f); + } + + EntityTypes::EntityType entityType = entity->getType(); + if (entityType != EntityTypes::PolyVox) { + return glm::vec3(0.0f); + } + + auto polyVoxEntity = std::dynamic_pointer_cast(entity); + return polyVoxEntity->worldCoordsToVoxelCoords(worldCoords); +} diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 434134d2cd..e5bff8e80a 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -134,6 +134,9 @@ public slots: Q_INVOKABLE QVector getActionIDs(const QUuid& entityID); Q_INVOKABLE QVariantMap getActionArguments(const QUuid& entityID, const QUuid& actionID); + Q_INVOKABLE glm::vec3 voxelCoordsToWorldCoords(const QUuid& entityID, glm::vec3 voxelCoords); + Q_INVOKABLE glm::vec3 worldCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 worldCoords); + signals: void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); @@ -162,7 +165,7 @@ signals: private: bool actionWorker(const QUuid& entityID, std::function actor); - bool setVoxels(QUuid entityID, std::function actor); + bool setVoxels(QUuid entityID, std::function actor); bool setPoints(QUuid entityID, std::function actor); void queueEntityMessage(PacketType::Value packetType, EntityItemID entityID, const EntityItemProperties& properties); diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 29d0b2e595..563624a1c7 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -74,17 +74,18 @@ class PolyVoxEntityItem : public EntityItem { static const PolyVoxSurfaceStyle DEFAULT_VOXEL_SURFACE_STYLE; // coords are in voxel-volume space - virtual void setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue) {} + virtual bool setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue) { return false; } + virtual bool setVoxelInVolume(glm::vec3 position, uint8_t toValue) { return false; } + + virtual glm::vec3 voxelCoordsToWorldCoords(glm::vec3 voxelCoords) { return glm::vec3(0.0f); } + virtual glm::vec3 worldCoordsToVoxelCoords(glm::vec3 worldCoords) { return glm::vec3(0.0f); } // coords are in world-space - virtual void setSphere(glm::vec3 center, float radius, uint8_t toValue) {} - - virtual void setAll(uint8_t toValue) {} - - virtual void setVoxelInVolume(glm::vec3 position, uint8_t toValue) {} + virtual bool setSphere(glm::vec3 center, float radius, uint8_t toValue) { return false; } + virtual bool setAll(uint8_t toValue) { return false; } virtual uint8_t getVoxel(int x, int y, int z) { return 0; } - virtual void setVoxel(int x, int y, int z, uint8_t toValue) {} + virtual bool setVoxel(int x, int y, int z, uint8_t toValue) { return false; } static QByteArray makeEmptyVoxelData(quint16 voxelXSize = 16, quint16 voxelYSize = 16, quint16 voxelZSize = 16); From c6530c4cecbc5e9f552570869af6a942e3149396 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 15 Aug 2015 16:16:27 -0700 Subject: [PATCH 033/102] fix newly created polyvox collision-hull bug --- .../src/RenderablePolyVoxEntityItem.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 5b0c4ee691..9f97585fab 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -158,7 +158,10 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) void RenderablePolyVoxEntityItem::updateVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { // if we are switching to or from "edged" we need to force a resize of _volData. - if (voxelSurfaceStyle == SURFACE_EDGED_CUBIC || _voxelSurfaceStyle == SURFACE_EDGED_MARCHING_CUBES) { + bool wasEdged = (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC || _voxelSurfaceStyle == SURFACE_EDGED_MARCHING_CUBES); + bool willBeEdged = (voxelSurfaceStyle == SURFACE_EDGED_CUBIC || voxelSurfaceStyle == SURFACE_EDGED_MARCHING_CUBES); + + if (wasEdged != willBeEdged) { if (_volData) { delete _volData; } @@ -611,6 +614,7 @@ void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) { } } else { unsigned int i = 0; + for (int z = 0; z < _voxelVolumeSize.z; z++) { for (int y = 0; y < _voxelVolumeSize.y; y++) { for (int x = 0; x < _voxelVolumeSize.x; x++) { @@ -619,6 +623,11 @@ void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) { float offL = -0.5f; float offH = 0.5f; + if (_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_CUBIC) { + offL += 1.0f; + offH += 1.0f; + } + glm::vec3 p000 = glm::vec3(vtoM * glm::vec4(x + offL, y + offL, z + offL, 1.0f)); glm::vec3 p001 = glm::vec3(vtoM * glm::vec4(x + offL, y + offL, z + offH, 1.0f)); From 558f68c150af1ba21ebad03937dbdb5d894d9b91 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 15 Aug 2015 16:53:47 -0700 Subject: [PATCH 034/102] increase max polyvox dimension from 32 to 128. don't recompress compressed data unless something changed../../libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp --- libraries/entities/src/PolyVoxEntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp index c9f3705712..30dded3714 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp @@ -22,7 +22,7 @@ const glm::vec3 PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE = glm::vec3(32, 32, 32); -const float PolyVoxEntityItem::MAX_VOXEL_DIMENSION = 32.0f; +const float PolyVoxEntityItem::MAX_VOXEL_DIMENSION = 128.0f; const QByteArray PolyVoxEntityItem::DEFAULT_VOXEL_DATA(PolyVoxEntityItem::makeEmptyVoxelData()); const PolyVoxEntityItem::PolyVoxSurfaceStyle PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE = PolyVoxEntityItem::SURFACE_MARCHING_CUBES; From f6cbeb37f866d46a5cd44735b27e42c50fd5eabb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 16 Aug 2015 09:35:50 -0700 Subject: [PATCH 035/102] put a green sphere at the point being pointed to --- examples/pointer.js | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/examples/pointer.js b/examples/pointer.js index 2791e06466..99c2bcb23b 100644 --- a/examples/pointer.js +++ b/examples/pointer.js @@ -12,6 +12,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html var lineEntityID = null; +var sphereEntityID = null; var lineIsRezzed = false; var BUTTON_SIZE = 32; @@ -56,16 +57,24 @@ function nearLinePoint(targetPosition) { function removeLine() { - if (lineIsRezzed) { - Entities.deleteEntity(lineEntityID); - lineEntityID = null; - lineIsRezzed = false; - } + if (lineIsRezzed) { + Entities.deleteEntity(lineEntityID); + if (sphereEntityID) { + Entities.deleteEntity(sphereEntityID); + } + lineEntityID = null; + sphereEntityID = null; + lineIsRezzed = false; + } } function createOrUpdateLine(event) { var pickRay = Camera.computePickRay(event.x, event.y); + if (sphereEntityID) { + Entities.deleteEntity(sphereEntityID); + sphereEntityID = null; + } var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking var props = Entities.getEntityProperties(intersection.entityID); @@ -78,7 +87,6 @@ function createOrUpdateLine(event) { position: MyAvatar.position, lifetime: 15 + props.lifespan // renew lifetime }); - // Entities.setAllPoints(lineEntityID, points); } else { lineIsRezzed = true; lineEntityID = Entities.addEntity({ @@ -90,6 +98,15 @@ function createOrUpdateLine(event) { lifetime: 15 // if someone crashes while pointing, don't leave the line there forever. }); } + + sphereEntityID = Entities.addEntity({ + type: "Sphere", + position: intersection.intersection, + ignoreForCollisions: 1, + dimensions: { x: 0.6, y: 0.6, z: 0.6 }, + color: { red: 0, green: 255, blue: 0 }, + lifetime: 15 // if someone crashes while pointing, don't leave the line there forever. + }); } else { removeLine(); } From 6db115bed59f5b1f0577ec39ba09461bcc7bd887 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 16 Aug 2015 09:36:13 -0700 Subject: [PATCH 036/102] try to make adding and removing voxels work more like expected --- examples/voxels.js | 120 ++++++++++++++++++++++++++++++++------------- 1 file changed, 85 insertions(+), 35 deletions(-) diff --git a/examples/voxels.js b/examples/voxels.js index c70111153b..0ef9fe9fab 100644 --- a/examples/voxels.js +++ b/examples/voxels.js @@ -1,38 +1,81 @@ var controlHeld = false; var shiftHeld = false; +function floorVector(v) { + return {x: Math.floor(v.x), y: Math.floor(v.y), z: Math.floor(v.z)}; +} -function attemptVoxelChange(intersection) { - var ids = Entities.findEntities(intersection.intersection, 10); - var success = false; - for (var i = 0; i < ids.length; i++) { - var id = ids[i]; - // var voxelCoords = Entities.worldCoordsToVoxelCoords(id, intersection.intersection); - - if (controlHeld) { - // hold control to erase a sphere - for (var r = 1.0; r < 17.0; r++) { - if (Entities.setVoxelSphere(id, intersection.intersection, r, 0)) { - success = true; - break; - } - } - } else if (shiftHeld) { - // hold shift to set all voxels to 255 - if (Entities.setAllVoxels(id, 255)) { - success = true; - } - } else { - // no modifier key means to add a sphere - for (var r = 1.0; r < 17.0; r++) { - if (Entities.setVoxelSphere(id, intersection.intersection, r, 255)) { - success = true; - break; - } - } - } +function backUpByOneVoxel(pickRayDirInVoxelSpace, originalVoxelPosition, low, high) { + // try to back up along pickRay an amount that changes only one coordinate. this does + // a binary search for a pickRay multiplier that only causes one of the 3 coordinates to change. + var originalVoxelCoords = floorVector(originalVoxelPosition) + if (high - low < 0.001) { + print("voxel backup-by-1 failed"); + // give up. + return oCoords; } - return success; + var middle = (low + high) / 2.0; + + var backupVector = Vec3.multiply(pickRayDirInVoxelSpace, -middle); + print("backupVector = " + "{" + backupVector.x + ", " + backupVector.y + ", " + backupVector.z + "}"); + var nPosition = Vec3.sum(originalVoxelPosition, backupVector); // possible neighbor coordinates + var nCoords = floorVector(nPosition); + + print("middle = " + middle + + " -- {" + originalVoxelCoords.x + ", " + originalVoxelCoords.y + ", " + originalVoxelCoords.z + "}" + + " -- {" + nCoords.x + ", " + nCoords.y + ", " + nCoords.z + "}"); + + + if (nCoords.x == originalVoxelCoords.x && + nCoords.y == originalVoxelCoords.y && + nCoords.z == originalVoxelCoords.z) { + // still in the original voxel. back up more... + return backUpByOneVoxel(pickRayDirInVoxelSpace, originalVoxelPosition, middle, high); + } + + if (nCoords.x != originalVoxelCoords.x && + nCoords.y == originalVoxelCoords.y && + nCoords.z == originalVoxelCoords.z) { + return nCoords; + } + if (nCoords.x == originalVoxelCoords.x && + nCoords.y != originalVoxelCoords.y && + nCoords.z == originalVoxelCoords.z) { + return nCoords; + } + if (nCoords.x == originalVoxelCoords.x && + nCoords.y == originalVoxelCoords.y && + nCoords.z != originalVoxelCoords.z) { + return nCoords; + } + + // more than one coordinate changed, but no less... + return backUpByOneVoxel(pickRayDirInVoxelSpace, originalVoxelPosition, low, middle); +} + + +function attemptVoxelChange(pickRayDir, intersection) { + var voxelPosition = Entities.worldCoordsToVoxelCoords(intersection.entityID, intersection.intersection); + var pickRayDirInVoxelSpace = Entities.localCoordsToVoxelCoords(intersection.entityID, pickRayDir); + + print("voxelPosition = " + voxelPosition.x + ", " + voxelPosition.y + ", " + voxelPosition.z); + print("pickRay = " + pickRayDir.x + ", " + pickRayDir.y + ", " + pickRayDir.z); + print("pickRayInVoxelSpace = " + + pickRayDirInVoxelSpace.x + ", " + pickRayDirInVoxelSpace.y + ", " + pickRayDirInVoxelSpace.z); + + if (controlHeld) { + // hold control to erase a voxel + return Entities.setVoxel(intersection.entityID, floorVector(voxelPosition), 0); + } else if (shiftHeld) { + // hold shift to set all voxels to 255 + return Entities.setAllVoxels(intersection.entityID, 255); + } else { + // no modifier key to add a voxel + var backOneVoxel = backUpByOneVoxel(pickRayDirInVoxelSpace, voxelPosition, 0.0, 1.0); + return Entities.setVoxel(intersection.entityID, backOneVoxel, 255); + } + + // Entities.setVoxelSphere(id, intersection.intersection, radius, 0) } @@ -43,20 +86,27 @@ function mousePressEvent(event) { var pickRay = Camera.computePickRay(event.x, event.y); var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking + var properties; - // we've used a picking ray to decide where to add the new sphere of voxels. If we pick nothing - // or if we pick a non-PolyVox entity, we fall through to the next picking attempt. if (intersection.intersects) { - if (attemptVoxelChange(intersection)) { - return; + properties = Entities.getEntityProperties(intersection.entityID); + print("got accurate pick"); + if (properties.type == "PolyVox") { + if (attemptVoxelChange(pickRay.direction, intersection)) { + return; + } + } else { + print("not a polyvox: " + properties.type); } } + print("trying bounding-box pick"); + // if the PolyVox entity is empty, we can't pick against its "on" voxels. try picking against its // bounding box, instead. intersection = Entities.findRayIntersection(pickRay, false); // bounding box picking if (intersection.intersects) { - attemptVoxelChange(intersection); + attemptVoxelChange(pickRay.direction, intersection); } } From b129c2a93342c0c86363ad1c6959406affe81c54 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 16 Aug 2015 09:36:54 -0700 Subject: [PATCH 037/102] in edged mode, make sure border voxels are zeroed out. expose some more voxel matrix math to javascript --- .../src/RenderablePolyVoxEntityItem.cpp | 84 +++++++++++++++---- .../src/RenderablePolyVoxEntityItem.h | 7 +- .../entities/src/EntityScriptingInterface.cpp | 40 +++++++++ .../entities/src/EntityScriptingInterface.h | 2 + libraries/entities/src/PolyVoxEntityItem.h | 2 + 5 files changed, 117 insertions(+), 18 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 9f97585fab..108660f386 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include #if defined(__GNUC__) && !defined(__clang__) @@ -67,7 +68,7 @@ RenderablePolyVoxEntityItem::~RenderablePolyVoxEntityItem() { } bool inUserBounds(const PolyVox::SimpleVolume* vol, PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle, - int x, int y, int z) { + int x, int y, int z) { // x, y, z are in user voxel-coords, not adjusted-for-edge voxel-coords. switch (surfaceStyle) { case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: @@ -206,6 +207,11 @@ glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const { return scaled; } +glm::mat4 RenderablePolyVoxEntityItem::localToVoxelMatrix() const { + glm::mat4 localToModelMatrix = glm::inverse(voxelToLocalMatrix()); + return localToModelMatrix; +} + glm::mat4 RenderablePolyVoxEntityItem::voxelToWorldMatrix() const { glm::mat4 rotation = glm::mat4_cast(getRotation()); glm::mat4 translation = glm::translate(getPosition()); @@ -252,13 +258,32 @@ bool RenderablePolyVoxEntityItem::setVoxelInternal(int x, int y, int z, uint8_t return result; } +void RenderablePolyVoxEntityItem::clearEdges() { + // if we are in an edged mode, make sure the outside surfaces are zeroed out. + if (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC || _voxelSurfaceStyle == SURFACE_EDGED_MARCHING_CUBES) { + for (int z = 0; z < _volData->getDepth(); z++) { + for (int y = 0; y < _volData->getHeight(); y++) { + for (int x = 0; x < _volData->getWidth(); x++) { + if (x == 0 || y == 0 || z == 0 || + x == _volData->getWidth() - 1 || + y == _volData->getHeight() - 1 || + z == _volData->getDepth() - 1) { + _volData->setVoxelAt(x, y, z, 0); + } + } + } + } + } +} bool RenderablePolyVoxEntityItem::setVoxel(int x, int y, int z, uint8_t toValue) { if (_locked) { return false; } bool result = setVoxelInternal(x, y, z, toValue); - compressVolumeData(); + if (result) { + compressVolumeData(); + } return result; } @@ -298,7 +323,9 @@ bool RenderablePolyVoxEntityItem::setAll(uint8_t toValue) { } } } - compressVolumeData(); + if (result) { + compressVolumeData(); + } return result; } @@ -308,7 +335,7 @@ bool RenderablePolyVoxEntityItem::setVoxelInVolume(glm::vec3 position, uint8_t t } // same as setVoxel but takes a vector rather than 3 floats. - return setVoxel((int)position.x, (int)position.y, (int)position.z, toValue); + return setVoxel(roundf(position.x), roundf(position.y), roundf(position.z), toValue); } bool RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue) { @@ -332,7 +359,9 @@ bool RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radi } } } - compressVolumeData(); + if (result) { + compressVolumeData(); + } return result; } @@ -354,9 +383,10 @@ public: } bool operator()(PolyVox::SimpleVolume::Sampler& sampler) { - int x = sampler.getPosition().getX(); - int y = sampler.getPosition().getY(); - int z = sampler.getPosition().getZ(); + PolyVox::Vector3DInt32 positionIndex = sampler.getPosition(); + int x = positionIndex.getX(); + int y = positionIndex.getY(); + int z = positionIndex.getZ(); if (!inBounds(_vol, x, y, z)) { return true; @@ -365,8 +395,9 @@ public: if (sampler.getVoxel() == 0) { return true; // keep raycasting } - PolyVox::Vector3DInt32 positionIndex = sampler.getPosition(); - _result = glm::vec4(positionIndex.getX(), positionIndex.getY(), positionIndex.getZ(), 1.0f); + // qDebug() << "RaycastFunctor hit" << x << y << z; + // add {0.5, 0.5, 0.5} to result so it's centered on the voxel + _result = glm::vec4((float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f, 1.0f); return false; } glm::vec4 _result; @@ -386,7 +417,6 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o return true; } - // the PolyVox ray intersection code requires a near and far point. glm::mat4 wtvMatrix = worldToVoxelMatrix(); glm::vec3 normDirection = glm::normalize(direction); @@ -411,23 +441,29 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o } glm::vec4 result = callback._result; + switch (_voxelSurfaceStyle) { case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES: - result -= glm::vec4(1, 1, 1, 0); // compensate for the extra voxel border + result -= glm::vec4(1.0f, 1.0f, 1.0f, 0.0f); // compensate for the extra voxel border break; case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: case PolyVoxEntityItem::SURFACE_CUBIC: break; } - result -= glm::vec4(0.5f, 0.5f, 0.5f, 0.0f); + // result -= glm::vec4(0.5f, 0.5f, 0.5f, 0.0f); glm::vec4 intersectedWorldPosition = voxelToWorldMatrix() * result; - distance = glm::distance(glm::vec3(intersectedWorldPosition), origin); + // TODO: use this to find the actual point of intersection rather than using the center of the voxel + // GeometryUtil.h + // bool findRayRectangleIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::quat& rotation, + // const glm::vec3& position, const glm::vec2& dimensions, float& distance);; - face = BoxFace::MIN_X_FACE; // XXX + face = BoxFace::MIN_X_FACE; + + distance = glm::distance(glm::vec3(intersectedWorldPosition), origin); return true; } @@ -436,6 +472,8 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o // compress the data in _volData and save the results. The compressed form is used during // saves to disk and for transmission over the wire void RenderablePolyVoxEntityItem::compressVolumeData() { + auto startTime = usecTimestampNow(); + quint16 voxelXSize = _voxelVolumeSize.x; quint16 voxelYSize = _voxelVolumeSize.y; quint16 voxelZSize = _voxelVolumeSize.z; @@ -486,6 +524,8 @@ void RenderablePolyVoxEntityItem::compressVolumeData() { _dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS; _needsModelReload = true; + + qDebug() << "RenderablePolyVoxEntityItem::compressVolumeData" << (usecTimestampNow() - startTime) << getName(); } @@ -525,6 +565,7 @@ void RenderablePolyVoxEntityItem::decompressVolumeData() { } } } + clearEdges(); #ifdef WANT_DEBUG qDebug() << "--------------- voxel decompress ---------------"; @@ -628,7 +669,6 @@ void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) { offH += 1.0f; } - glm::vec3 p000 = glm::vec3(vtoM * glm::vec4(x + offL, y + offL, z + offL, 1.0f)); glm::vec3 p001 = glm::vec3(vtoM * glm::vec4(x + offL, y + offL, z + offH, 1.0f)); glm::vec3 p010 = glm::vec3(vtoM * glm::vec4(x + offL, y + offH, z + offL, 1.0f)); @@ -691,6 +731,8 @@ void RenderablePolyVoxEntityItem::setZTextureURL(QString zTextureURL) { } void RenderablePolyVoxEntityItem::getModel() { + auto startTime = usecTimestampNow(); + // A mesh object to hold the result of surface extraction PolyVox::SurfaceMesh polyVoxMesh; @@ -745,6 +787,8 @@ void RenderablePolyVoxEntityItem::getModel() { #endif _needsModelReload = false; + + qDebug() << "RenderablePolyVoxEntityItem::getModel" << (usecTimestampNow() - startTime) << getName(); } void RenderablePolyVoxEntityItem::render(RenderArgs* args) { @@ -871,3 +915,11 @@ glm::vec3 RenderablePolyVoxEntityItem::voxelCoordsToWorldCoords(glm::vec3 voxelC glm::vec3 RenderablePolyVoxEntityItem::worldCoordsToVoxelCoords(glm::vec3 worldCoords) { return glm::vec3(worldToVoxelMatrix() * glm::vec4(worldCoords, 1.0f)); } + +glm::vec3 RenderablePolyVoxEntityItem::voxelCoordsToLocalCoords(glm::vec3 voxelCoords) { + return glm::vec3(voxelToLocalMatrix() * glm::vec4(voxelCoords, 1.0f)); +} + +glm::vec3 RenderablePolyVoxEntityItem::localCoordsToVoxelCoords(glm::vec3 localCoords) { + return glm::vec3(localToVoxelMatrix() * glm::vec4(localCoords, 1.0f)); +} diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index 17c8934577..ffc45beb22 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -71,8 +71,9 @@ public: virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize); glm::vec3 getSurfacePositionAdjustment() const; glm::mat4 voxelToWorldMatrix() const; - glm::mat4 voxelToLocalMatrix() const; glm::mat4 worldToVoxelMatrix() const; + glm::mat4 voxelToLocalMatrix() const; + glm::mat4 localToVoxelMatrix() const; virtual ShapeType getShapeType() const; virtual bool isReadyToComputeShape(); @@ -80,6 +81,8 @@ public: virtual glm::vec3 voxelCoordsToWorldCoords(glm::vec3 voxelCoords); virtual glm::vec3 worldCoordsToVoxelCoords(glm::vec3 worldCoords); + virtual glm::vec3 voxelCoordsToLocalCoords(glm::vec3 voxelCoords); + virtual glm::vec3 localCoordsToVoxelCoords(glm::vec3 localCoords); // coords are in voxel-volume space virtual bool setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue); @@ -110,7 +113,7 @@ private: bool setVoxelInternal(int x, int y, int z, uint8_t toValue); void compressVolumeData(); void decompressVolumeData(); - + void clearEdges(); PolyVox::SimpleVolume* _volData = nullptr; model::Geometry _modelGeometry; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index c3e71cef82..41ca6a91ac 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -697,3 +697,43 @@ glm::vec3 EntityScriptingInterface::worldCoordsToVoxelCoords(const QUuid& entity auto polyVoxEntity = std::dynamic_pointer_cast(entity); return polyVoxEntity->worldCoordsToVoxelCoords(worldCoords); } + +glm::vec3 EntityScriptingInterface::voxelCoordsToLocalCoords(const QUuid& entityID, glm::vec3 voxelCoords) { + if (!_entityTree) { + return glm::vec3(0.0f); + } + + EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); + if (!entity) { + qCDebug(entities) << "EntityScriptingInterface::voxelCoordsToLocalCoords no entity with ID" << entityID; + return glm::vec3(0.0f); + } + + EntityTypes::EntityType entityType = entity->getType(); + if (entityType != EntityTypes::PolyVox) { + return glm::vec3(0.0f); + } + + auto polyVoxEntity = std::dynamic_pointer_cast(entity); + return polyVoxEntity->voxelCoordsToLocalCoords(voxelCoords); +} + +glm::vec3 EntityScriptingInterface::localCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 localCoords) { + if (!_entityTree) { + return glm::vec3(0.0f); + } + + EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); + if (!entity) { + qCDebug(entities) << "EntityScriptingInterface::localCoordsToVoxelCoords no entity with ID" << entityID; + return glm::vec3(0.0f); + } + + EntityTypes::EntityType entityType = entity->getType(); + if (entityType != EntityTypes::PolyVox) { + return glm::vec3(0.0f); + } + + auto polyVoxEntity = std::dynamic_pointer_cast(entity); + return polyVoxEntity->localCoordsToVoxelCoords(localCoords); +} diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index e5bff8e80a..a51ebfb61c 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -136,6 +136,8 @@ public slots: Q_INVOKABLE glm::vec3 voxelCoordsToWorldCoords(const QUuid& entityID, glm::vec3 voxelCoords); Q_INVOKABLE glm::vec3 worldCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 worldCoords); + Q_INVOKABLE glm::vec3 voxelCoordsToLocalCoords(const QUuid& entityID, glm::vec3 voxelCoords); + Q_INVOKABLE glm::vec3 localCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 localCoords); signals: void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 563624a1c7..2ba57f85de 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -79,6 +79,8 @@ class PolyVoxEntityItem : public EntityItem { virtual glm::vec3 voxelCoordsToWorldCoords(glm::vec3 voxelCoords) { return glm::vec3(0.0f); } virtual glm::vec3 worldCoordsToVoxelCoords(glm::vec3 worldCoords) { return glm::vec3(0.0f); } + virtual glm::vec3 voxelCoordsToLocalCoords(glm::vec3 voxelCoords) { return glm::vec3(0.0f); } + virtual glm::vec3 localCoordsToVoxelCoords(glm::vec3 localCoords) { return glm::vec3(0.0f); } // coords are in world-space virtual bool setSphere(glm::vec3 center, float radius, uint8_t toValue) { return false; } From 0230d9397cb04cf09803cc582cd94a0c9083aa09 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 16 Aug 2015 11:04:52 -0700 Subject: [PATCH 038/102] attempt to find exact ray intersection with cubic polyvox -- not working right, yet. --- .../src/RenderablePolyVoxEntityItem.cpp | 56 ++++++++++++++++--- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 108660f386..760fe5ad16 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -418,6 +418,8 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o } glm::mat4 wtvMatrix = worldToVoxelMatrix(); + glm::mat4 vtwMatrix = voxelToWorldMatrix(); + glm::mat4 vtlMatrix = voxelToLocalMatrix(); glm::vec3 normDirection = glm::normalize(direction); // the PolyVox ray intersection code requires a near and far point. @@ -440,6 +442,7 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o return false; } + // result is in voxel-space coordinates. glm::vec4 result = callback._result; switch (_voxelSurfaceStyle) { @@ -452,18 +455,55 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o break; } - // result -= glm::vec4(0.5f, 0.5f, 0.5f, 0.0f); - glm::vec4 intersectedWorldPosition = voxelToWorldMatrix() * result; + // close-ish, but not right + // glm::vec4 intersectedWorldPosition = vtwMatrix * result; + // distance = glm::distance(glm::vec3(intersectedWorldPosition), origin); - // TODO: use this to find the actual point of intersection rather than using the center of the voxel - // GeometryUtil.h - // bool findRayRectangleIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::quat& rotation, - // const glm::vec3& position, const glm::vec2& dimensions, float& distance);; + glm::vec3 minXPosition = glm::vec3(vtwMatrix * (result + glm::vec4(0.0f, 0.5f, 0.5f, 0.0f))); + glm::vec3 maxXPosition = glm::vec3(vtwMatrix * (result + glm::vec4(1.0f, 0.5f, 0.5f, 0.0f))); + glm::vec3 minYPosition = glm::vec3(vtwMatrix * (result + glm::vec4(0.5f, 0.0f, 0.5f, 0.0f))); + glm::vec3 maxYPosition = glm::vec3(vtwMatrix * (result + glm::vec4(0.5f, 1.0f, 0.5f, 0.0f))); + glm::vec3 minZPosition = glm::vec3(vtwMatrix * (result + glm::vec4(0.5f, 0.5f, 0.0f, 0.0f))); + glm::vec3 maxZPosition = glm::vec3(vtwMatrix * (result + glm::vec4(0.5f, 0.5f, 1.0f, 0.0f))); - face = BoxFace::MIN_X_FACE; + glm::vec4 baseDimensions = glm::vec4(1.0, 1.0, 1.0, 0.0); + glm::vec3 worldDimensions = glm::vec3(vtlMatrix * baseDimensions); + glm::vec2 xDimensions = glm::vec2(worldDimensions.y, worldDimensions.z); + glm::vec2 yDimensions = glm::vec2(worldDimensions.x, worldDimensions.z); + glm::vec2 zDimensions = glm::vec2(worldDimensions.x, worldDimensions.y); - distance = glm::distance(glm::vec3(intersectedWorldPosition), origin); + glm::quat minXRotation = extractRotation(vtwMatrix) * glm::quat(0.0f, 1.0f, 0.0f, PI_OVER_TWO); + glm::quat maxXRotation = extractRotation(vtwMatrix) * glm::quat(0.0f, 1.0f, 0.0f, PI_OVER_TWO); + glm::quat minYRotation = extractRotation(vtwMatrix) * glm::quat(1.0f, 0.0f, 0.0f, PI_OVER_TWO); + glm::quat maxYRotation = extractRotation(vtwMatrix) * glm::quat(1.0f, 0.0f, 0.0f, PI_OVER_TWO); + glm::quat minZRotation = extractRotation(vtwMatrix) * glm::quat(0.0f, 0.0f, 1.0f, 0.0f); + glm::quat maxZRotation = extractRotation(vtwMatrix) * glm::quat(0.0f, 0.0f, 1.0f, 0.0f); + + float bestDx = FLT_MAX; + bool hit[ 6 ]; + float dx[ 6 ] = {FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX}; + + hit[0] = findRayRectangleIntersection(origin, direction, minXRotation, minXPosition, xDimensions, dx[0]); + hit[1] = findRayRectangleIntersection(origin, direction, maxXRotation, maxXPosition, xDimensions, dx[1]); + hit[2] = findRayRectangleIntersection(origin, direction, minYRotation, minYPosition, yDimensions, dx[2]); + hit[3] = findRayRectangleIntersection(origin, direction, maxYRotation, maxYPosition, yDimensions, dx[3]); + hit[4] = findRayRectangleIntersection(origin, direction, minZRotation, minZPosition, zDimensions, dx[4]); + hit[5] = findRayRectangleIntersection(origin, direction, maxZRotation, maxZPosition, zDimensions, dx[5]); + + bool ok = false; + for (int i = 0; i < 6; i ++) { + if (hit[ i ] && dx[ i ] < bestDx) { + face = (BoxFace)i; + distance = dx[ i ]; + ok = true; + } + } + + if (!ok) { + qWarning() << "RenderablePolyVoxEntityItem::findDetailedRayIntersection -- failed to determine face"; + return false; + } return true; } From a57278ba3c063b6ee576714766d9f395517c4f0c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 16 Aug 2015 11:51:04 -0700 Subject: [PATCH 039/102] ray-picks against cubic-voxels seem right, now --- examples/voxels.js | 2 +- .../src/RenderablePolyVoxEntityItem.cpp | 46 ++++++++----------- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/examples/voxels.js b/examples/voxels.js index 0ef9fe9fab..b198ac3948 100644 --- a/examples/voxels.js +++ b/examples/voxels.js @@ -12,7 +12,7 @@ function backUpByOneVoxel(pickRayDirInVoxelSpace, originalVoxelPosition, low, hi if (high - low < 0.001) { print("voxel backup-by-1 failed"); // give up. - return oCoords; + return originalVoxelPosition; } var middle = (low + high) / 2.0; diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 760fe5ad16..4819d46e39 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -397,7 +397,9 @@ public: } // qDebug() << "RaycastFunctor hit" << x << y << z; // add {0.5, 0.5, 0.5} to result so it's centered on the voxel - _result = glm::vec4((float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f, 1.0f); + // _result = glm::vec4((float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f, 1.0f); + + _result = glm::vec4((float)x, (float)y, (float)z, 1.0f); return false; } glm::vec4 _result; @@ -412,6 +414,8 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o void** intersectedObject, bool precisionPicking) const { + // TODO -- correctly pick against marching-cube generated meshes + if (_needsModelReload || !precisionPicking) { // just intersect with bounding box return true; @@ -443,23 +447,9 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o } // result is in voxel-space coordinates. - glm::vec4 result = callback._result; - - switch (_voxelSurfaceStyle) { - case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: - case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES: - result -= glm::vec4(1.0f, 1.0f, 1.0f, 0.0f); // compensate for the extra voxel border - break; - case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: - case PolyVoxEntityItem::SURFACE_CUBIC: - break; - } - - - // close-ish, but not right - // glm::vec4 intersectedWorldPosition = vtwMatrix * result; - // distance = glm::distance(glm::vec3(intersectedWorldPosition), origin); + glm::vec4 result = callback._result - glm::vec4(0.5f, 0.5f, 0.5f, 0.0f); + // set up ray tests against each face of the voxel. glm::vec3 minXPosition = glm::vec3(vtwMatrix * (result + glm::vec4(0.0f, 0.5f, 0.5f, 0.0f))); glm::vec3 maxXPosition = glm::vec3(vtwMatrix * (result + glm::vec4(1.0f, 0.5f, 0.5f, 0.0f))); glm::vec3 minYPosition = glm::vec3(vtwMatrix * (result + glm::vec4(0.5f, 0.0f, 0.5f, 0.0f))); @@ -469,16 +459,17 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o glm::vec4 baseDimensions = glm::vec4(1.0, 1.0, 1.0, 0.0); glm::vec3 worldDimensions = glm::vec3(vtlMatrix * baseDimensions); - glm::vec2 xDimensions = glm::vec2(worldDimensions.y, worldDimensions.z); + glm::vec2 xDimensions = glm::vec2(worldDimensions.z, worldDimensions.y); glm::vec2 yDimensions = glm::vec2(worldDimensions.x, worldDimensions.z); glm::vec2 zDimensions = glm::vec2(worldDimensions.x, worldDimensions.y); - glm::quat minXRotation = extractRotation(vtwMatrix) * glm::quat(0.0f, 1.0f, 0.0f, PI_OVER_TWO); - glm::quat maxXRotation = extractRotation(vtwMatrix) * glm::quat(0.0f, 1.0f, 0.0f, PI_OVER_TWO); - glm::quat minYRotation = extractRotation(vtwMatrix) * glm::quat(1.0f, 0.0f, 0.0f, PI_OVER_TWO); - glm::quat maxYRotation = extractRotation(vtwMatrix) * glm::quat(1.0f, 0.0f, 0.0f, PI_OVER_TWO); - glm::quat minZRotation = extractRotation(vtwMatrix) * glm::quat(0.0f, 0.0f, 1.0f, 0.0f); - glm::quat maxZRotation = extractRotation(vtwMatrix) * glm::quat(0.0f, 0.0f, 1.0f, 0.0f); + glm::quat vtwRotation = extractRotation(vtwMatrix); + glm::quat minXRotation = vtwRotation * glm::quat(glm::vec3(0.0f, PI_OVER_TWO, 0.0f)); + glm::quat maxXRotation = vtwRotation * glm::quat(glm::vec3(0.0f, PI_OVER_TWO, 0.0f)); + glm::quat minYRotation = vtwRotation * glm::quat(glm::vec3(PI_OVER_TWO, 0.0f, 0.0f)); + glm::quat maxYRotation = vtwRotation * glm::quat(glm::vec3(PI_OVER_TWO, 0.0f, 0.0f)); + glm::quat minZRotation = vtwRotation * glm::quat(glm::vec3(0.0f, 0.0f, 0.0f)); + glm::quat maxZRotation = vtwRotation * glm::quat(glm::vec3(0.0f, 0.0f, 0.0f)); float bestDx = FLT_MAX; bool hit[ 6 ]; @@ -497,12 +488,15 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o face = (BoxFace)i; distance = dx[ i ]; ok = true; + bestDx = dx[ i ]; } } if (!ok) { - qWarning() << "RenderablePolyVoxEntityItem::findDetailedRayIntersection -- failed to determine face"; - return false; + // if the attempt to put the ray against one of the voxel-faces fails, just return the center + glm::vec4 intersectedWorldPosition = vtwMatrix * (result + vec4(0.5f, 0.5f, 0.5f, 0.0f)); + distance = glm::distance(glm::vec3(intersectedWorldPosition), origin); + face = BoxFace::MIN_X_FACE; } return true; From c60a8e7dfcbe610d7d51790dd7d1642964c74885 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 16 Aug 2015 12:52:55 -0700 Subject: [PATCH 040/102] minecraft style voxel editing largely works --- examples/voxels.js | 85 ++++--------------- .../src/RenderablePolyVoxEntityItem.cpp | 15 ++-- 2 files changed, 25 insertions(+), 75 deletions(-) diff --git a/examples/voxels.js b/examples/voxels.js index b198ac3948..cc3453202a 100644 --- a/examples/voxels.js +++ b/examples/voxels.js @@ -5,80 +5,34 @@ function floorVector(v) { return {x: Math.floor(v.x), y: Math.floor(v.y), z: Math.floor(v.z)}; } -function backUpByOneVoxel(pickRayDirInVoxelSpace, originalVoxelPosition, low, high) { - // try to back up along pickRay an amount that changes only one coordinate. this does - // a binary search for a pickRay multiplier that only causes one of the 3 coordinates to change. - var originalVoxelCoords = floorVector(originalVoxelPosition) - if (high - low < 0.001) { - print("voxel backup-by-1 failed"); - // give up. - return originalVoxelPosition; - } - var middle = (low + high) / 2.0; - - var backupVector = Vec3.multiply(pickRayDirInVoxelSpace, -middle); - print("backupVector = " + "{" + backupVector.x + ", " + backupVector.y + ", " + backupVector.z + "}"); - var nPosition = Vec3.sum(originalVoxelPosition, backupVector); // possible neighbor coordinates - var nCoords = floorVector(nPosition); - - print("middle = " + middle + - " -- {" + originalVoxelCoords.x + ", " + originalVoxelCoords.y + ", " + originalVoxelCoords.z + "}" + - " -- {" + nCoords.x + ", " + nCoords.y + ", " + nCoords.z + "}"); - - - if (nCoords.x == originalVoxelCoords.x && - nCoords.y == originalVoxelCoords.y && - nCoords.z == originalVoxelCoords.z) { - // still in the original voxel. back up more... - return backUpByOneVoxel(pickRayDirInVoxelSpace, originalVoxelPosition, middle, high); - } - - if (nCoords.x != originalVoxelCoords.x && - nCoords.y == originalVoxelCoords.y && - nCoords.z == originalVoxelCoords.z) { - return nCoords; - } - if (nCoords.x == originalVoxelCoords.x && - nCoords.y != originalVoxelCoords.y && - nCoords.z == originalVoxelCoords.z) { - return nCoords; - } - if (nCoords.x == originalVoxelCoords.x && - nCoords.y == originalVoxelCoords.y && - nCoords.z != originalVoxelCoords.z) { - return nCoords; - } - - // more than one coordinate changed, but no less... - return backUpByOneVoxel(pickRayDirInVoxelSpace, originalVoxelPosition, low, middle); -} - - function attemptVoxelChange(pickRayDir, intersection) { - var voxelPosition = Entities.worldCoordsToVoxelCoords(intersection.entityID, intersection.intersection); - var pickRayDirInVoxelSpace = Entities.localCoordsToVoxelCoords(intersection.entityID, pickRayDir); - print("voxelPosition = " + voxelPosition.x + ", " + voxelPosition.y + ", " + voxelPosition.z); - print("pickRay = " + pickRayDir.x + ", " + pickRayDir.y + ", " + pickRayDir.z); - print("pickRayInVoxelSpace = " + - pickRayDirInVoxelSpace.x + ", " + pickRayDirInVoxelSpace.y + ", " + pickRayDirInVoxelSpace.z); + var properties = Entities.getEntityProperties(intersection.entityID); + if (properties.type != "PolyVox") { + return false; + } + + var voxelPosition = Entities.worldCoordsToVoxelCoords(intersection.entityID, intersection.intersection); + voxelPosition = Vec3.subtract(voxelPosition, {x: 0.5, y: 0.5, z: 0.5}); + var pickRayDirInVoxelSpace = Entities.localCoordsToVoxelCoords(intersection.entityID, pickRayDir); + pickRayDirInVoxelSpace = Vec3.normalize(pickRayDirInVoxelSpace); if (controlHeld) { // hold control to erase a voxel - return Entities.setVoxel(intersection.entityID, floorVector(voxelPosition), 0); + var toErasePosition = Vec3.sum(voxelPosition, Vec3.multiply(pickRayDirInVoxelSpace, 0.1)); + return Entities.setVoxel(intersection.entityID, floorVector(toErasePosition), 0); } else if (shiftHeld) { // hold shift to set all voxels to 255 return Entities.setAllVoxels(intersection.entityID, 255); } else { // no modifier key to add a voxel - var backOneVoxel = backUpByOneVoxel(pickRayDirInVoxelSpace, voxelPosition, 0.0, 1.0); - return Entities.setVoxel(intersection.entityID, backOneVoxel, 255); + var toDrawPosition = Vec3.subtract(voxelPosition, Vec3.multiply(pickRayDirInVoxelSpace, 0.1)); + return Entities.setVoxel(intersection.entityID, floorVector(toDrawPosition), 255); } // Entities.setVoxelSphere(id, intersection.intersection, radius, 0) } - function mousePressEvent(event) { if (!event.isLeftButton) { return; @@ -86,22 +40,13 @@ function mousePressEvent(event) { var pickRay = Camera.computePickRay(event.x, event.y); var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking - var properties; if (intersection.intersects) { - properties = Entities.getEntityProperties(intersection.entityID); - print("got accurate pick"); - if (properties.type == "PolyVox") { - if (attemptVoxelChange(pickRay.direction, intersection)) { - return; - } - } else { - print("not a polyvox: " + properties.type); + if (attemptVoxelChange(pickRay.direction, intersection)) { + return; } } - print("trying bounding-box pick"); - // if the PolyVox entity is empty, we can't pick against its "on" voxels. try picking against its // bounding box, instead. intersection = Entities.findRayIntersection(pickRay, false); // bounding box picking diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 4819d46e39..7044eb0b3c 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -395,9 +395,6 @@ public: if (sampler.getVoxel() == 0) { return true; // keep raycasting } - // qDebug() << "RaycastFunctor hit" << x << y << z; - // add {0.5, 0.5, 0.5} to result so it's centered on the voxel - // _result = glm::vec4((float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f, 1.0f); _result = glm::vec4((float)x, (float)y, (float)z, 1.0f); return false; @@ -506,7 +503,9 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o // compress the data in _volData and save the results. The compressed form is used during // saves to disk and for transmission over the wire void RenderablePolyVoxEntityItem::compressVolumeData() { + #ifdef WANT_DEBUG auto startTime = usecTimestampNow(); + #endif quint16 voxelXSize = _voxelVolumeSize.x; quint16 voxelYSize = _voxelVolumeSize.y; @@ -559,7 +558,9 @@ void RenderablePolyVoxEntityItem::compressVolumeData() { _dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS; _needsModelReload = true; + #ifdef WANT_DEBUG qDebug() << "RenderablePolyVoxEntityItem::compressVolumeData" << (usecTimestampNow() - startTime) << getName(); + #endif } @@ -765,7 +766,9 @@ void RenderablePolyVoxEntityItem::setZTextureURL(QString zTextureURL) { } void RenderablePolyVoxEntityItem::getModel() { + #ifdef WANT_DEBUG auto startTime = usecTimestampNow(); + #endif // A mesh object to hold the result of surface extraction PolyVox::SurfaceMesh polyVoxMesh; @@ -822,7 +825,9 @@ void RenderablePolyVoxEntityItem::getModel() { _needsModelReload = false; + #ifdef WANT_DEBUG qDebug() << "RenderablePolyVoxEntityItem::getModel" << (usecTimestampNow() - startTime) << getName(); + #endif } void RenderablePolyVoxEntityItem::render(RenderArgs* args) { @@ -951,9 +956,9 @@ glm::vec3 RenderablePolyVoxEntityItem::worldCoordsToVoxelCoords(glm::vec3 worldC } glm::vec3 RenderablePolyVoxEntityItem::voxelCoordsToLocalCoords(glm::vec3 voxelCoords) { - return glm::vec3(voxelToLocalMatrix() * glm::vec4(voxelCoords, 1.0f)); + return glm::vec3(voxelToLocalMatrix() * glm::vec4(voxelCoords, 0.0f)); } glm::vec3 RenderablePolyVoxEntityItem::localCoordsToVoxelCoords(glm::vec3 localCoords) { - return glm::vec3(localToVoxelMatrix() * glm::vec4(localCoords, 1.0f)); + return glm::vec3(localToVoxelMatrix() * glm::vec4(localCoords, 0.0f)); } From 1ee773a5322ff08fbf0204b995e6be06fad25066 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 16 Aug 2015 14:11:37 -0700 Subject: [PATCH 041/102] don't include interrior voxels in cubic collision hull --- .../src/RenderablePolyVoxEntityItem.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 7044eb0b3c..edccffd397 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -695,6 +695,18 @@ void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) { for (int y = 0; y < _voxelVolumeSize.y; y++) { for (int x = 0; x < _voxelVolumeSize.x; x++) { if (getVoxel(x, y, z) > 0) { + + if ((x > 0 && getVoxel(x - 1, y, z) == 0) && + (y > 0 && getVoxel(x, y - 1, z) == 0) && + (z > 0 && getVoxel(x, y, z - 1) == 0) && + (x < _voxelVolumeSize.x - 1 && getVoxel(x + 1, y, z) == 0) && + (y < _voxelVolumeSize.y - 1 && getVoxel(x, y + 1, z) == 0) && + (z < _voxelVolumeSize.z - 1 && getVoxel(x, y, z + 1) == 0)) { + // this voxel has neighbors in every cardinal direction, so there's no need + // to include it in the collision hull. + continue; + } + QVector pointsInPart; float offL = -0.5f; From db4d98ccb5167503c5ecf0bb30a0975d04330ea5 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sun, 16 Aug 2015 23:21:45 -0700 Subject: [PATCH 042/102] Polyvox shader fix --- libraries/entities-renderer/src/polyvox.slf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/entities-renderer/src/polyvox.slf b/libraries/entities-renderer/src/polyvox.slf index e5c8a49133..5772a93f7d 100644 --- a/libraries/entities-renderer/src/polyvox.slf +++ b/libraries/entities-renderer/src/polyvox.slf @@ -36,9 +36,9 @@ void main(void) { float inPositionY = (_inPosition.y - 0.5) / voxelVolumeSize.y; float inPositionZ = (_inPosition.z - 0.5) / voxelVolumeSize.z; - vec4 xyDiffuse = texture2D(xMap, vec2(-inPositionX, -inPositionY)); - vec4 xzDiffuse = texture2D(yMap, vec2(-inPositionX, inPositionZ)); - vec4 yzDiffuse = texture2D(zMap, vec2(inPositionZ, -inPositionY)); + vec4 xyDiffuse = texture(xMap, vec2(-inPositionX, -inPositionY)); + vec4 xzDiffuse = texture(yMap, vec2(-inPositionX, inPositionZ)); + vec4 yzDiffuse = texture(zMap, vec2(inPositionZ, -inPositionY)); vec3 xyDiffuseScaled = xyDiffuse.rgb * abs(worldNormal.z); vec3 xzDiffuseScaled = xzDiffuse.rgb * abs(worldNormal.y); From a61d9501c86a328a0e146c20eda0a899a121d4ab Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 17 Aug 2015 02:04:23 -0700 Subject: [PATCH 043/102] Add polyvox to shader tests and clean up test code --- tests/shaders/src/main.cpp | 111 ++++--------------------------------- 1 file changed, 10 insertions(+), 101 deletions(-) diff --git a/tests/shaders/src/main.cpp b/tests/shaders/src/main.cpp index dde7419264..8d12663935 100644 --- a/tests/shaders/src/main.cpp +++ b/tests/shaders/src/main.cpp @@ -20,6 +20,8 @@ #include #include +#include + #include "../model/Skybox_vert.h" #include "../model/Skybox_frag.h" @@ -112,85 +114,22 @@ #include "paintStroke_vert.h" #include "paintStroke_frag.h" -class RateCounter { - std::vector times; - QElapsedTimer timer; -public: - RateCounter() { - timer.start(); - } - - void reset() { - times.clear(); - } - - unsigned int count() const { - return times.size() - 1; - } - - float elapsed() const { - if (times.size() < 1) { - return 0.0f; - } - float elapsed = *times.rbegin() - *times.begin(); - return elapsed; - } - - void increment() { - times.push_back(timer.elapsed() / 1000.0f); - } - - float rate() const { - if (elapsed() == 0.0f) { - return 0.0f; - } - return (float) count() / elapsed(); - } -}; - - -const QString& getQmlDir() { - static QString dir; - if (dir.isEmpty()) { - QDir path(__FILE__); - path.cdUp(); - dir = path.cleanPath(path.absoluteFilePath("../../../interface/resources/qml/")) + "/"; - qDebug() << "Qml Path: " << dir; - } - return dir; -} +#include "polyvox_vert.h" +#include "polyvox_frag.h" // Create a simple OpenGL window that renders text in various ways class QTestWindow : public QWindow { Q_OBJECT - QOpenGLContext* _context{ nullptr }; - QSize _size; - //TextRenderer* _textRenderer[4]; - RateCounter fps; protected: void renderText(); -private: - void resizeWindow(const QSize& size) { - _size = size; - } - public: QTestWindow() { setSurfaceType(QSurface::OpenGLSurface); - - QSurfaceFormat format; - // Qt Quick may need a depth and stencil buffer. Always make sure these are available. - format.setDepthBufferSize(16); - format.setStencilBufferSize(8); - format.setVersion(4, 1); - format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); - format.setOption(QSurfaceFormat::DebugContext); - + QSurfaceFormat format = getDefaultOpenGlSurfaceFormat(); setFormat(format); - _context = new QOpenGLContext; _context->setFormat(format); _context->create(); @@ -199,8 +138,6 @@ public: makeCurrent(); gpu::Context::init(); - - { QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(this); logger->initialize(); // initializes in the current context, i.e. ctx @@ -208,25 +145,8 @@ public: connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) { qDebug() << debugMessage; }); - // logger->startLogging(QOpenGLDebugLogger::SynchronousLogging); } - qDebug() << (const char*)glGetString(GL_VERSION); - - //_textRenderer[0] = TextRenderer::getInstance(SANS_FONT_FAMILY, 12, false); - //_textRenderer[1] = TextRenderer::getInstance(SERIF_FONT_FAMILY, 12, false, - // TextRenderer::SHADOW_EFFECT); - //_textRenderer[2] = TextRenderer::getInstance(MONO_FONT_FAMILY, 48, -1, - // false, TextRenderer::OUTLINE_EFFECT); - //_textRenderer[3] = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, 24); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glClearColor(0.2f, 0.2f, 0.2f, 1); - glDisable(GL_DEPTH_TEST); - makeCurrent(); - -// setFramePosition(QPoint(-1000, 0)); resize(QSize(800, 600)); } @@ -237,18 +157,15 @@ public: void makeCurrent() { _context->makeCurrent(this); } - -protected: - void resizeEvent(QResizeEvent* ev) override { - resizeWindow(ev->size()); - } }; void testShaderBuild(const char* vs_src, const char * fs_src) { auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(vs_src))); auto fs = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(fs_src))); auto pr = gpu::ShaderPointer(gpu::Shader::createProgram(vs, fs)); - gpu::Shader::makeProgram(*pr); + if (!gpu::Shader::makeProgram(*pr)) { + throw std::runtime_error("Failed to compile shader"); + } } void QTestWindow::draw() { @@ -257,8 +174,8 @@ void QTestWindow::draw() { } makeCurrent(); + glClearColor(0.2f, 0.2f, 0.2f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glViewport(0, 0, _size.width() * devicePixelRatio(), _size.height() * devicePixelRatio()); static std::once_flag once; std::call_once(once, [&]{ @@ -328,17 +245,10 @@ void QTestWindow::draw() { testShaderBuild(Skybox_vert, Skybox_frag); testShaderBuild(paintStroke_vert,paintStroke_frag); + testShaderBuild(polyvox_vert, polyvox_frag); }); - _context->swapBuffers(this); - glFinish(); - - fps.increment(); - if (fps.elapsed() >= 2.0f) { - qDebug() << "FPS: " << fps.rate(); - fps.reset(); - } } void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { @@ -352,7 +262,6 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt } } - const char * LOG_FILTER_RULES = R"V0G0N( hifi.gpu=true )V0G0N"; From af11e97daad8d8aa4a5c06e8d8cf7f59c683debb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 17 Aug 2015 08:49:00 -0700 Subject: [PATCH 044/102] fix broken optimisation for skipping internal voxels when making collision hull --- .../src/RenderablePolyVoxEntityItem.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index edccffd397..5c0a7888e5 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -696,12 +696,12 @@ void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) { for (int x = 0; x < _voxelVolumeSize.x; x++) { if (getVoxel(x, y, z) > 0) { - if ((x > 0 && getVoxel(x - 1, y, z) == 0) && - (y > 0 && getVoxel(x, y - 1, z) == 0) && - (z > 0 && getVoxel(x, y, z - 1) == 0) && - (x < _voxelVolumeSize.x - 1 && getVoxel(x + 1, y, z) == 0) && - (y < _voxelVolumeSize.y - 1 && getVoxel(x, y + 1, z) == 0) && - (z < _voxelVolumeSize.z - 1 && getVoxel(x, y, z + 1) == 0)) { + if ((x > 0 && getVoxel(x - 1, y, z) > 0) && + (y > 0 && getVoxel(x, y - 1, z) > 0) && + (z > 0 && getVoxel(x, y, z - 1) > 0) && + (x < _voxelVolumeSize.x - 1 && getVoxel(x + 1, y, z) > 0) && + (y < _voxelVolumeSize.y - 1 && getVoxel(x, y + 1, z) > 0) && + (z < _voxelVolumeSize.z - 1 && getVoxel(x, y, z + 1) > 0)) { // this voxel has neighbors in every cardinal direction, so there's no need // to include it in the collision hull. continue; From 014bf661fa92de5c1c9126783a8d3cb84ed654fd Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Aug 2015 11:18:25 -0700 Subject: [PATCH 045/102] bump packet version --- libraries/networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 5562490344..db2a426696 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -67,7 +67,7 @@ PacketVersion versionForPacketType(PacketType::Value packetType) { case EntityAdd: case EntityEdit: case EntityData: - return VERSION_ENTITIES_POLYLINE; + return VERSION_OCTREE_CENTERED_ORIGIN; case AvatarData: return 12; default: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 1aeadb1af9..75d8105dca 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -142,5 +142,6 @@ const PacketVersion VERSION_ENTITIES_HAVE_SIMULATION_OWNER_AND_ACTIONS_OVER_WIRE const PacketVersion VERSION_ENTITIES_NEW_PROTOCOL_LAYER = 35; const PacketVersion VERSION_POLYVOX_TEXTURES = 36; const PacketVersion VERSION_ENTITIES_POLYLINE = 37; +const PacketVersion VERSION_OCTREE_CENTERED_ORIGIN = 38; #endif // hifi_PacketHeaders_h \ No newline at end of file From 8cf450cb674d1ea0a7b44fb9417b552f108be9a6 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Aug 2015 11:41:54 -0700 Subject: [PATCH 046/102] first cut at making focus click based --- interface/src/Application.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 979dc99453..a8c66c4689 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -674,9 +674,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : packetReceiver.registerListener(PacketType::DomainConnectionDenied, this, "handleDomainConnectionDeniedPacket"); auto entityScriptingInterface = DependencyManager::get(); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity, [this, entityScriptingInterface](const EntityItemID& entityItemID, const MouseEvent& event) { + connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity, + [this, entityScriptingInterface](const EntityItemID& entityItemID, const MouseEvent& event) { if (_keyboardFocusedItem != entityItemID) { _keyboardFocusedItem = UNKNOWN_ENTITY_ID; + qDebug() << "_keyboardFocusedItem:" << UNKNOWN_ENTITY_ID; auto properties = entityScriptingInterface->getEntityProperties(entityItemID); if (EntityTypes::Web == properties.getType() && !properties.getLocked()) { auto entity = entityScriptingInterface->getEntityTree()->findEntityByID(entityItemID); @@ -684,16 +686,21 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : if (webEntity) { webEntity->setProxyWindow(_window->windowHandle()); _keyboardFocusedItem = entityItemID; + qDebug() << "_keyboardFocusedItem:" << entityItemID; } } } }); + /* + // FIXME - need a solution for unfocusing on delayed time connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, [=](const EntityItemID& entityItemID, const MouseEvent& event) { if (_keyboardFocusedItem == entityItemID) { _keyboardFocusedItem = UNKNOWN_ENTITY_ID; + qDebug() << "_keyboardFocusedItem:" << UNKNOWN_ENTITY_ID; } }); + */ } void Application::aboutToQuit() { From 941b966dc745fa1c0175feb2a25c4ab4387aa18b Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Mon, 17 Aug 2015 11:57:08 -0700 Subject: [PATCH 047/102] Force eyeball update even when not looking at me. --- interface/src/avatar/SkeletonModel.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 831fb26abb..d58cd8d7c4 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -123,9 +123,15 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { params.rightEyeJointIndex = geometry.rightEyeJointIndex; _rig->updateFromHeadParameters(params); - } else if (_owningAvatar->getHead()->isLookingAtMe()) { - // Other avatars joint, including their eyes, will already be set just like any other joints + } else { + // This is a little more work than we really want. + // + // Other avatars joint, including their eyes, should already be set just like any other joints // from the wire data. But when looking at me, we want the eyes to use the corrected lookAt. + // + // Thus this should really only be ... else if (_owningAvatar->getHead()->isLookingAtMe()) {... + // However, in the !isLookingAtMe case, the eyes aren't rotating the way they should right now. + // (They latch their looking at me position.) We will revisit that as priorities allow. const FBXGeometry& geometry = _geometry->getFBXGeometry(); Head* head = _owningAvatar->getHead(); _rig->updateEyeJoints(geometry.leftEyeJointIndex, geometry.rightEyeJointIndex, From 296a6b1cb831f9a2559dc4ea8000999f6288c3e5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 17 Aug 2015 12:20:46 -0700 Subject: [PATCH 048/102] re-enabled ctrlaltdavid's eye calibration code --- interface/src/devices/EyeTracker.cpp | 47 +++++++++++++--------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/interface/src/devices/EyeTracker.cpp b/interface/src/devices/EyeTracker.cpp index 532c1d41f3..b7a0a8c299 100644 --- a/interface/src/devices/EyeTracker.cpp +++ b/interface/src/devices/EyeTracker.cpp @@ -153,21 +153,20 @@ void EyeTracker::onStreamStarted() { qCDebug(interfaceapp) << "Eye Tracker: Started streaming"; } - // TODO: Re-enable once saving / loading calibrations is working - //if (_isStreaming) { - // // Automatically load calibration if one has been saved. - // QString availableCalibrations = QString(smi_getAvailableCalibrations()); - // if (availableCalibrations.contains(HIGH_FIDELITY_EYE_TRACKER_CALIBRATION)) { - // result = smi_loadCalibration(HIGH_FIDELITY_EYE_TRACKER_CALIBRATION); - // if (result != SMI_RET_SUCCESS) { - // qCWarning(interfaceapp) << "Eye Tracker: Error loading calibration:" << smiReturnValueToString(result); - // QMessageBox::warning(nullptr, "Eye Tracker Error", "Error loading calibration" - // + smiReturnValueToString(result)); - // } else { - // qCDebug(interfaceapp) << "Eye Tracker: Loaded calibration"; - // } - // } - //} + if (_isStreaming) { + // Automatically load calibration if one has been saved. + QString availableCalibrations = QString(smi_getAvailableCalibrations()); + if (availableCalibrations.contains(HIGH_FIDELITY_EYE_TRACKER_CALIBRATION)) { + result = smi_loadCalibration(HIGH_FIDELITY_EYE_TRACKER_CALIBRATION); + if (result != SMI_RET_SUCCESS) { + qCWarning(interfaceapp) << "Eye Tracker: Error loading calibration:" << smiReturnValueToString(result); + QMessageBox::warning(nullptr, "Eye Tracker Error", "Error loading calibration" + + smiReturnValueToString(result)); + } else { + qCDebug(interfaceapp) << "Eye Tracker: Loaded calibration"; + } + } + } } #endif @@ -260,11 +259,10 @@ void EyeTracker::calibrate(int points) { if (result != SMI_RET_SUCCESS) { qCWarning(interfaceapp) << "Eye Tracker: Error performing calibration:" << smiReturnValueToString(result); } else { - // TODO: Re - enable once saving / loading calibrations is working - //result = smi_saveCalibration(HIGH_FIDELITY_EYE_TRACKER_CALIBRATION); - //if (result != SMI_RET_SUCCESS) { - // qCWarning(interfaceapp) << "Eye Tracker: Error saving calibration:" << smiReturnValueToString(result); - //} + result = smi_saveCalibration(HIGH_FIDELITY_EYE_TRACKER_CALIBRATION); + if (result != SMI_RET_SUCCESS) { + qCWarning(interfaceapp) << "Eye Tracker: Error saving calibration:" << smiReturnValueToString(result); + } } } @@ -292,11 +290,10 @@ QString EyeTracker::smiReturnValueToString(int value) { return "Eye cameras not available"; case smi_ErrorReturnValue::SMI_ERROR_OCULUS_RUNTIME_NOT_SUPPORTED: return "Oculus runtime not supported"; - // TODO: Re-enable once saving / loading calibrations is working - //case smi_ErrorReturnValue::SMI_ERROR_FILE_NOT_FOUND: - // return "File not found"; - //case smi_ErrorReturnValue::SMI_ERROR_FILE_EMPTY: - // return "File empty"; + case smi_ErrorReturnValue::SMI_ERROR_FILE_NOT_FOUND: + return "File not found"; + case smi_ErrorReturnValue::SMI_ERROR_FILE_EMPTY: + return "File empty"; case smi_ErrorReturnValue::SMI_ERROR_UNKNOWN: return "Unknown error"; default: From 1c8030472ae6a06f85ec0d9f71aa61278fd78d1b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 17 Aug 2015 12:40:56 -0700 Subject: [PATCH 049/102] back out the more controversial changes --- libraries/fbx/src/FBXReader.cpp | 20 ++++++++++++-------- libraries/render-utils/src/Model.cpp | 11 +++++++++++ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index ebffa4410a..2db5f5fa51 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -976,7 +976,7 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) { data.extracted.mesh.meshIndex = meshIndex++; QVector materials; QVector textures; - // bool isMaterialPerPolygon = false; + bool isMaterialPerPolygon = false; foreach (const FBXNode& child, object.children) { if (child.name == "Vertices") { @@ -1107,13 +1107,12 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) { foreach (const FBXNode& subdata, child.children) { if (subdata.name == "Materials") { materials = getIntVector(subdata); - } // else if (subdata.name == "MappingInformationType") { - // if (subdata.properties.at(0) == "ByPolygon") - // isMaterialPerPolygon = true; - // } else { - // isMaterialPerPolygon = false; - // } - // } + } else if (subdata.name == "MappingInformationType") { + if (subdata.properties.at(0) == "ByPolygon") + isMaterialPerPolygon = true; + } else { + isMaterialPerPolygon = false; + } } @@ -1126,6 +1125,11 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) { } } + bool isMultiMaterial = false; + if (isMaterialPerPolygon) { + isMultiMaterial = true; + } + // convert the polygons to quads and triangles int polygonIndex = 0; QHash, int> materialTextureParts; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 8a9a3f68dc..7452c32ed2 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1808,6 +1808,17 @@ void Model::segregateMeshGroups() { const FBXMesh& mesh = geometry.meshes.at(i); const MeshState& state = _meshStates.at(i); + bool translucentMesh = networkMesh.getTranslucentPartCount(mesh) == networkMesh.parts.size(); + bool hasTangents = !mesh.tangents.isEmpty(); + bool hasSpecular = mesh.hasSpecularTexture(); + bool hasLightmap = mesh.hasEmissiveTexture(); + bool isSkinned = state.clusterMatrices.size() > 1; + bool wireframe = isWireframe(); + + if (wireframe) { + translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false; + } + // Create the render payloads int totalParts = mesh.parts.size(); for (int partIndex = 0; partIndex < totalParts; partIndex++) { From b7d9dc444bdf90aaf2e21b2002b5f2a8d7749b7c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Aug 2015 13:06:32 -0700 Subject: [PATCH 050/102] more work on clicking focus --- interface/src/Application.cpp | 30 ++++++++++++------- interface/src/Application.h | 1 + .../src/EntityTreeRenderer.cpp | 2 ++ .../src/EntityTreeRenderer.h | 1 + .../src/RenderableWebEntityItem.cpp | 9 ++++++ 5 files changed, 33 insertions(+), 10 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a8c66c4689..5ae0872761 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -673,12 +673,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : auto& packetReceiver = nodeList->getPacketReceiver(); packetReceiver.registerListener(PacketType::DomainConnectionDenied, this, "handleDomainConnectionDeniedPacket"); + // If the user clicks an an entity, we will check that it's an unlocked web entity, and if so, set the focus to it auto entityScriptingInterface = DependencyManager::get(); connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity, [this, entityScriptingInterface](const EntityItemID& entityItemID, const MouseEvent& event) { if (_keyboardFocusedItem != entityItemID) { _keyboardFocusedItem = UNKNOWN_ENTITY_ID; - qDebug() << "_keyboardFocusedItem:" << UNKNOWN_ENTITY_ID; + qDebug() << "clickDownOnEntity.... _keyboardFocusedItem:" << UNKNOWN_ENTITY_ID; auto properties = entityScriptingInterface->getEntityProperties(entityItemID); if (EntityTypes::Web == properties.getType() && !properties.getLocked()) { auto entity = entityScriptingInterface->getEntityTree()->findEntityByID(entityItemID); @@ -686,21 +687,19 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : if (webEntity) { webEntity->setProxyWindow(_window->windowHandle()); _keyboardFocusedItem = entityItemID; - qDebug() << "_keyboardFocusedItem:" << entityItemID; + _lastAcceptedKeyPress = usecTimestampNow(); + qDebug() << "clickDownOnEntity.... _keyboardFocusedItem:" << entityItemID; } } } }); - /* - // FIXME - need a solution for unfocusing on delayed time - connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, [=](const EntityItemID& entityItemID, const MouseEvent& event) { - if (_keyboardFocusedItem == entityItemID) { - _keyboardFocusedItem = UNKNOWN_ENTITY_ID; - qDebug() << "_keyboardFocusedItem:" << UNKNOWN_ENTITY_ID; - } + // If the user clicks somewhere where there is NO entity at all, we will release focus + connect(getEntities(), &EntityTreeRenderer::mousePressOffEntity, + [=](const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId) { + _keyboardFocusedItem = UNKNOWN_ENTITY_ID; + qDebug() << "mousePressOffEntity... _keyboardFocusedItem:" << UNKNOWN_ENTITY_ID; }); - */ } void Application::aboutToQuit() { @@ -1277,6 +1276,7 @@ bool Application::event(QEvent* event) { event->setAccepted(false); QCoreApplication::sendEvent(webEntity->getEventHandler(), event); if (event->isAccepted()) { + _lastAcceptedKeyPress = usecTimestampNow(); return true; } } @@ -1286,6 +1286,16 @@ bool Application::event(QEvent* event) { default: break; } + + const quint64 LOSE_FOCUS_AFTER_ELAPSED_TIME = 30 * USECS_PER_SECOND; // if idle for 30 seconds, drop focus + quint64 elapsedSinceAcceptedKeyPress = usecTimestampNow() - _lastAcceptedKeyPress; + if (elapsedSinceAcceptedKeyPress > LOSE_FOCUS_AFTER_ELAPSED_TIME) { + _keyboardFocusedItem = UNKNOWN_ENTITY_ID; + qDebug() << "idle for 30 seconds.... _keyboardFocusedItem:" << UNKNOWN_ENTITY_ID; + } else { + qDebug() << "elapsedSinceAcceptedKeyPress:" << elapsedSinceAcceptedKeyPress; + } + } switch (event->type()) { diff --git a/interface/src/Application.h b/interface/src/Application.h index cec1325baf..e0d4fa559d 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -680,6 +680,7 @@ private: DialogsManagerScriptingInterface* _dialogsManagerScriptingInterface = new DialogsManagerScriptingInterface(); EntityItemID _keyboardFocusedItem; + quint64 _lastAcceptedKeyPress = 0; }; #endif // hifi_Application_h diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 50f79e2ff3..72400dcefb 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -861,6 +861,8 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event, unsigned int device if (entityScript.property("clickDownOnEntity").isValid()) { entityScript.property("clickDownOnEntity").call(entityScript, entityScriptArgs); } + } else { + emit mousePressOffEntity(rayPickResult, event, deviceID); } _lastMouseEvent = MouseEvent(*event, deviceID); _lastMouseEventValid = true; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 39f088f06d..25eb87b422 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -95,6 +95,7 @@ public: signals: void mousePressOnEntity(const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId); + void mousePressOffEntity(const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId); void mouseMoveOnEntity(const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId); void mouseReleaseOnEntity(const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId); diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 73aa6f2718..c8c5b10a61 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -56,6 +56,15 @@ RenderableWebEntityItem::~RenderableWebEntityItem() { } void RenderableWebEntityItem::render(RenderArgs* args) { + + // debug bounds on mac. + { + gpu::Batch& batch = *args->_batch; + batch.setModelTransform(getTransformToCenter()); // we want to include the scale as well + glm::vec4 cubeColor{ 1.0f, 0.0f, 0.0f, 1.0f}; + DependencyManager::get()->renderWireCube(batch, 1.0f, cubeColor); + } + QOpenGLContext * currentContext = QOpenGLContext::currentContext(); QSurface * currentSurface = currentContext->surface(); if (!_webSurface) { From 4a456488a1dede351aaf1c43312f025134ad076a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 17 Aug 2015 14:01:25 -0700 Subject: [PATCH 051/102] remove the option to persist entities as anything other than json.gz files --- assignment-client/src/octree/OctreeServer.cpp | 7 +---- .../resources/describe-settings.json | 26 ++----------------- 2 files changed, 3 insertions(+), 30 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 76d701f0e3..062fe39dbd 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -971,12 +971,7 @@ void OctreeServer::readConfiguration() { strcpy(_persistFilename, qPrintable(persistFilename)); qDebug("persistFilename=%s", _persistFilename); - QString persistAsFileType; - if (!readOptionString(QString("persistAsFileType"), settingsSectionObject, persistAsFileType)) { - persistAsFileType = "svo"; - } - _persistAsFileType = persistAsFileType; - qDebug() << "persistAsFileType=" << _persistAsFileType; + _persistAsFileType = "json.gz"; _persistInterval = OctreePersistThread::DEFAULT_PERSIST_INTERVAL; readOptionInt(QString("persistInterval"), settingsSectionObject, _persistInterval); diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 696a87d2b8..b04ea95a23 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -371,30 +371,8 @@ "name": "persistFilename", "label": "Entities Filename", "help": "the path to the file entities are stored in. Make sure the path exists.", - "placeholder": "resources/models.svo", - "default": "resources/models.svo", - "advanced": true - }, - { - "name": "persistAsFileType", - "label": "File format for entity server's persistent data", - "help": "This defines how the entity server will save entities to disk.", - "default": "svo", - "type": "select", - "options": [ - { - "value": "svo", - "label": "Entity server persists data as SVO" - }, - { - "value": "json", - "label": "Entity server persists data as JSON" - }, - { - "value": "json.gz", - "label": "Entity server persists data as gzipped JSON" - } - ], + "placeholder": "resources/models.json.gz", + "default": "resources/models.json.gz", "advanced": true }, { From 47b0e2fda6cb06f030972aa5e741544c93a07e7e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Aug 2015 14:02:24 -0700 Subject: [PATCH 052/102] more hacking on click to focus --- interface/src/Application.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5ae0872761..874ffdb1b5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1277,6 +1277,7 @@ bool Application::event(QEvent* event) { QCoreApplication::sendEvent(webEntity->getEventHandler(), event); if (event->isAccepted()) { _lastAcceptedKeyPress = usecTimestampNow(); + qDebug() << "Application::event() key event... _lastAcceptedKeyPress:" << _lastAcceptedKeyPress; return true; } } @@ -1287,6 +1288,7 @@ bool Application::event(QEvent* event) { break; } + /* const quint64 LOSE_FOCUS_AFTER_ELAPSED_TIME = 30 * USECS_PER_SECOND; // if idle for 30 seconds, drop focus quint64 elapsedSinceAcceptedKeyPress = usecTimestampNow() - _lastAcceptedKeyPress; if (elapsedSinceAcceptedKeyPress > LOSE_FOCUS_AFTER_ELAPSED_TIME) { @@ -1295,6 +1297,7 @@ bool Application::event(QEvent* event) { } else { qDebug() << "elapsedSinceAcceptedKeyPress:" << elapsedSinceAcceptedKeyPress; } + */ } @@ -2003,6 +2006,19 @@ void Application::idle() { return; // bail early, nothing to do here. } + if (!_keyboardFocusedItem.isInvalidID()) { + const quint64 LOSE_FOCUS_AFTER_ELAPSED_TIME = 30 * USECS_PER_SECOND; // if idle for 30 seconds, drop focus + quint64 elapsedSinceAcceptedKeyPress = usecTimestampNow() - _lastAcceptedKeyPress; + if (elapsedSinceAcceptedKeyPress > LOSE_FOCUS_AFTER_ELAPSED_TIME) { + _keyboardFocusedItem = UNKNOWN_ENTITY_ID; + qDebug() << "Application::idle() no key messages for 30 seconds.... _keyboardFocusedItem: UNKNOWN_ENTITY_ID:" << UNKNOWN_ENTITY_ID; + } else { + qDebug() << "Application::idle() _keyboardFocusedItem:" << _keyboardFocusedItem << "elapsedSinceAcceptedKeyPress:" << elapsedSinceAcceptedKeyPress; + } + } else { + qDebug() << "Application::idle() no focused item, who cares..."; + } + // Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing // details if we're in ExtraDebugging mode. However, the ::update() and its subcomponents will show their timing // details normally. From 49cf29ce8f19df962fc8e0369cccdb680b0be12e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Aug 2015 15:57:20 -0700 Subject: [PATCH 053/102] cleanup debugging and dead code --- interface/src/Application.cpp | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 874ffdb1b5..70b9157a21 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -679,7 +679,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : [this, entityScriptingInterface](const EntityItemID& entityItemID, const MouseEvent& event) { if (_keyboardFocusedItem != entityItemID) { _keyboardFocusedItem = UNKNOWN_ENTITY_ID; - qDebug() << "clickDownOnEntity.... _keyboardFocusedItem:" << UNKNOWN_ENTITY_ID; auto properties = entityScriptingInterface->getEntityProperties(entityItemID); if (EntityTypes::Web == properties.getType() && !properties.getLocked()) { auto entity = entityScriptingInterface->getEntityTree()->findEntityByID(entityItemID); @@ -688,7 +687,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : webEntity->setProxyWindow(_window->windowHandle()); _keyboardFocusedItem = entityItemID; _lastAcceptedKeyPress = usecTimestampNow(); - qDebug() << "clickDownOnEntity.... _keyboardFocusedItem:" << entityItemID; } } } @@ -698,7 +696,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : connect(getEntities(), &EntityTreeRenderer::mousePressOffEntity, [=](const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId) { _keyboardFocusedItem = UNKNOWN_ENTITY_ID; - qDebug() << "mousePressOffEntity... _keyboardFocusedItem:" << UNKNOWN_ENTITY_ID; }); } @@ -1277,7 +1274,6 @@ bool Application::event(QEvent* event) { QCoreApplication::sendEvent(webEntity->getEventHandler(), event); if (event->isAccepted()) { _lastAcceptedKeyPress = usecTimestampNow(); - qDebug() << "Application::event() key event... _lastAcceptedKeyPress:" << _lastAcceptedKeyPress; return true; } } @@ -1287,18 +1283,6 @@ bool Application::event(QEvent* event) { default: break; } - - /* - const quint64 LOSE_FOCUS_AFTER_ELAPSED_TIME = 30 * USECS_PER_SECOND; // if idle for 30 seconds, drop focus - quint64 elapsedSinceAcceptedKeyPress = usecTimestampNow() - _lastAcceptedKeyPress; - if (elapsedSinceAcceptedKeyPress > LOSE_FOCUS_AFTER_ELAPSED_TIME) { - _keyboardFocusedItem = UNKNOWN_ENTITY_ID; - qDebug() << "idle for 30 seconds.... _keyboardFocusedItem:" << UNKNOWN_ENTITY_ID; - } else { - qDebug() << "elapsedSinceAcceptedKeyPress:" << elapsedSinceAcceptedKeyPress; - } - */ - } switch (event->type()) { @@ -2006,17 +1990,13 @@ void Application::idle() { return; // bail early, nothing to do here. } + // Drop focus from _keyboardFocusedItem if no keyboard messages for 30 seconds if (!_keyboardFocusedItem.isInvalidID()) { const quint64 LOSE_FOCUS_AFTER_ELAPSED_TIME = 30 * USECS_PER_SECOND; // if idle for 30 seconds, drop focus quint64 elapsedSinceAcceptedKeyPress = usecTimestampNow() - _lastAcceptedKeyPress; if (elapsedSinceAcceptedKeyPress > LOSE_FOCUS_AFTER_ELAPSED_TIME) { _keyboardFocusedItem = UNKNOWN_ENTITY_ID; - qDebug() << "Application::idle() no key messages for 30 seconds.... _keyboardFocusedItem: UNKNOWN_ENTITY_ID:" << UNKNOWN_ENTITY_ID; - } else { - qDebug() << "Application::idle() _keyboardFocusedItem:" << _keyboardFocusedItem << "elapsedSinceAcceptedKeyPress:" << elapsedSinceAcceptedKeyPress; } - } else { - qDebug() << "Application::idle() no focused item, who cares..."; } // Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing From ae9ccb79ed699a884456dd9be81200f32967eaaa Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Aug 2015 15:58:51 -0700 Subject: [PATCH 054/102] cleanup debugging and dead code --- libraries/entities-renderer/src/RenderableWebEntityItem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index c8c5b10a61..84707aca3b 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -57,13 +57,14 @@ RenderableWebEntityItem::~RenderableWebEntityItem() { void RenderableWebEntityItem::render(RenderArgs* args) { - // debug bounds on mac. + #ifdef WANT_EXTRA_DEBUGGING { gpu::Batch& batch = *args->_batch; batch.setModelTransform(getTransformToCenter()); // we want to include the scale as well glm::vec4 cubeColor{ 1.0f, 0.0f, 0.0f, 1.0f}; DependencyManager::get()->renderWireCube(batch, 1.0f, cubeColor); } + #endif QOpenGLContext * currentContext = QOpenGLContext::currentContext(); QSurface * currentSurface = currentContext->surface(); From cb5f80bf789667ab2134008bceb93c7a91263371 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 17 Aug 2015 15:56:56 -0700 Subject: [PATCH 055/102] Add highlighting of keyboard focused items --- interface/src/Application.cpp | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 621210cc4e..449afae5d1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -112,9 +112,7 @@ #include "InterfaceActionFactory.h" #include "avatar/AvatarManager.h" - #include "audio/AudioScope.h" - #include "devices/DdeFaceTracker.h" #include "devices/EyeTracker.h" #include "devices/Faceshift.h" @@ -148,6 +146,8 @@ #include "ui/AddressBarDialog.h" #include "ui/UpdateDialog.h" +#include "ui/overlays/Cube3DOverlay.h" + // ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. #if defined(Q_OS_WIN) @@ -172,7 +172,6 @@ public: void call() { _fun(); } }; - using namespace std; // Starfield information @@ -299,6 +298,13 @@ bool setupEssentials(int& argc, char** argv) { return true; } +// FIXME move to header, or better yet, design some kind of UI manager +// to take care of highlighting keyboard focused items, rather than +// continuing to overburden Application.cpp +Cube3DOverlay* _keyboardFocusHighlight{ nullptr }; +int _keyboardFocusHighlightID{ -1 }; + + Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : QApplication(argc, argv), _dependencyManagerIsSetup(setupEssentials(argc, argv)), @@ -687,6 +693,23 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : webEntity->setProxyWindow(_window->windowHandle()); _keyboardFocusedItem = entityItemID; _lastAcceptedKeyPress = usecTimestampNow(); + if (_keyboardFocusHighlightID < 0 || !getOverlays().isAddedOverlay(_keyboardFocusHighlightID)) { + _keyboardFocusHighlight = new Cube3DOverlay(); + _keyboardFocusHighlight->setAlpha(1.0f); + _keyboardFocusHighlight->setBorderSize(1.0f); + _keyboardFocusHighlight->setColor({ 0xFF, 0xEF, 0x00 }); + _keyboardFocusHighlight->setIsSolid(false); + _keyboardFocusHighlight->setPulseMin(0.5); + _keyboardFocusHighlight->setPulseMax(1.0); + _keyboardFocusHighlight->setColorPulse(1.0); + _keyboardFocusHighlight->setIgnoreRayIntersection(true); + _keyboardFocusHighlight->setDrawInFront(true); + } + _keyboardFocusHighlight->setRotation(webEntity->getRotation()); + _keyboardFocusHighlight->setPosition(webEntity->getPosition()); + _keyboardFocusHighlight->setDimensions(webEntity->getDimensions() * 1.05f); + _keyboardFocusHighlight->setVisible(true); + _keyboardFocusHighlightID = getOverlays().addOverlay(_keyboardFocusHighlight); } } } @@ -696,6 +719,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : connect(getEntities(), &EntityTreeRenderer::mousePressOffEntity, [=](const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId) { _keyboardFocusedItem = UNKNOWN_ENTITY_ID; + _keyboardFocusHighlight->setVisible(false); }); } @@ -707,6 +731,11 @@ void Application::aboutToQuit() { } void Application::cleanupBeforeQuit() { + if (_keyboardFocusHighlightID > 0) { + getOverlays().deleteOverlay(_keyboardFocusHighlightID); + _keyboardFocusHighlightID = -1; + } + _keyboardFocusHighlight = nullptr; _entities.clear(); // this will allow entity scripts to properly shutdown From 3cbbb5fb7975f369d0e2d4d90bbbad34721c965b Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 18 Aug 2015 00:05:02 -0700 Subject: [PATCH 056/102] Fix crash on mouse click --- interface/src/Application.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 449afae5d1..4e790bfa88 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -712,6 +712,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _keyboardFocusHighlightID = getOverlays().addOverlay(_keyboardFocusHighlight); } } + if (_keyboardFocusedItem == UNKNOWN_ENTITY_ID && _keyboardFocusHighlight) { + _keyboardFocusHighlight->setVisible(false); + } + } }); @@ -719,7 +723,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : connect(getEntities(), &EntityTreeRenderer::mousePressOffEntity, [=](const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId) { _keyboardFocusedItem = UNKNOWN_ENTITY_ID; - _keyboardFocusHighlight->setVisible(false); + if (_keyboardFocusHighlight) { + _keyboardFocusHighlight->setVisible(false); + } }); } From 551f0aaba3b0514eea1c616f55210f6e867a96e5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 18 Aug 2015 01:37:11 -0700 Subject: [PATCH 057/102] show how many times per second Application::idle is called --- interface/resources/qml/Stats.qml | 5 +++++ interface/src/Application.cpp | 19 +++++++++++++------ interface/src/Application.h | 8 ++++++++ interface/src/ui/Stats.cpp | 1 + interface/src/ui/Stats.h | 2 ++ 5 files changed, 29 insertions(+), 6 deletions(-) diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index 996f9f02ef..b7081afadf 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -47,6 +47,11 @@ Item { font.pixelSize: root.fontSize text: "Framerate: " + root.framerate } + Text { + color: root.fontColor; + font.pixelSize: root.fontSize + text: "Simrate: " + root.simrate + } Text { color: root.fontColor; font.pixelSize: root.fontSize diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4e790bfa88..58ef83efff 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -89,7 +89,6 @@ #include #include #include -#include #include #include #include @@ -2003,19 +2002,27 @@ void Application::checkFPS() { void Application::idle() { PROFILE_RANGE(__FUNCTION__); - static SimpleAverage interIdleDurations; + + static uint64_t lastIdleStart{ 0 }; static uint64_t lastIdleEnd{ 0 }; + uint64_t now = usecTimestampNow(); + uint64_t idleStartToStartDuration = now - lastIdleStart; + + if (lastIdleStart > 0 && idleStartToStartDuration > 0) { + _simsPerSecond.updateAverage((float)USECS_PER_SECOND / (float)idleStartToStartDuration); + } + + lastIdleStart = now; if (lastIdleEnd != 0) { - uint64_t now = usecTimestampNow(); - interIdleDurations.update(now - lastIdleEnd); + _interIdleDurations.update(now - lastIdleEnd); static uint64_t lastReportTime = now; if ((now - lastReportTime) >= (USECS_PER_SECOND)) { static QString LOGLINE("Average inter-idle time: %1 us for %2 samples"); if (Menu::getInstance()->isOptionChecked(MenuOption::LogExtraTimings)) { - qCDebug(interfaceapp_timing) << LOGLINE.arg((int)interIdleDurations.getAverage()).arg(interIdleDurations.getCount()); + qCDebug(interfaceapp_timing) << LOGLINE.arg((int)_interIdleDurations.getAverage()).arg(_interIdleDurations.getCount()); } - interIdleDurations.reset(); + _interIdleDurations.reset(); lastReportTime = now; } } diff --git a/interface/src/Application.h b/interface/src/Application.h index e0d4fa559d..fd57406249 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -38,6 +38,8 @@ #include #include #include +#include +#include #include "AudioClient.h" #include "Bookmarks.h" @@ -350,6 +352,9 @@ public: const QRect& getMirrorViewRect() const { return _mirrorViewRect; } + float getAverageInterIdleDuration() { return _interIdleDurations.getAverage(); } + float getAverageSimsPerSecond() { return _simsPerSecond.getAverage(); } + signals: /// Fired when we're simulating; allows external parties to hook in. @@ -681,6 +686,9 @@ private: EntityItemID _keyboardFocusedItem; quint64 _lastAcceptedKeyPress = 0; + + SimpleAverage _interIdleDurations; + SimpleMovingAverage _simsPerSecond; }; #endif // hifi_Application_h diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index d7c4bb5ed7..74e3a8f44f 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -114,6 +114,7 @@ void Stats::updateStats() { STAT_UPDATE(avatarCount, avatarManager->size() - 1); STAT_UPDATE(serverCount, nodeList->size()); STAT_UPDATE(framerate, (int)qApp->getFps()); + STAT_UPDATE(simrate, (int)Application::getInstance()->getAverageSimsPerSecond()); auto bandwidthRecorder = DependencyManager::get(); STAT_UPDATE(packetInCount, bandwidthRecorder->getCachedTotalAverageInputPacketsPerSecond()); diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index af6824d1a3..4f0619d9c8 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -30,6 +30,7 @@ class Stats : public QQuickItem { STATS_PROPERTY(int, serverCount, 0) STATS_PROPERTY(int, framerate, 0) + STATS_PROPERTY(int, simrate, 0) STATS_PROPERTY(int, avatarCount, 0) STATS_PROPERTY(int, packetInCount, 0) STATS_PROPERTY(int, packetOutCount, 0) @@ -95,6 +96,7 @@ signals: void timingExpandedChanged(); void serverCountChanged(); void framerateChanged(); + void simrateChanged(); void avatarCountChanged(); void packetInCountChanged(); void packetOutCountChanged(); From 8435550fe9a20fd9f15926bd217733d4ff7fc021 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 18 Aug 2015 02:05:50 -0700 Subject: [PATCH 058/102] only update simRate once per second --- interface/src/Application.cpp | 17 ++++++++++++++--- interface/src/Application.h | 8 ++++---- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 58ef83efff..de77b95e23 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2014,15 +2014,16 @@ void Application::idle() { lastIdleStart = now; + static SimpleAverage interIdleDurations; if (lastIdleEnd != 0) { - _interIdleDurations.update(now - lastIdleEnd); + interIdleDurations.update(now - lastIdleEnd); static uint64_t lastReportTime = now; if ((now - lastReportTime) >= (USECS_PER_SECOND)) { static QString LOGLINE("Average inter-idle time: %1 us for %2 samples"); if (Menu::getInstance()->isOptionChecked(MenuOption::LogExtraTimings)) { - qCDebug(interfaceapp_timing) << LOGLINE.arg((int)_interIdleDurations.getAverage()).arg(_interIdleDurations.getCount()); + qCDebug(interfaceapp_timing) << LOGLINE.arg((int)interIdleDurations.getAverage()).arg(interIdleDurations.getCount()); } - _interIdleDurations.reset(); + interIdleDurations.reset(); lastReportTime = now; } } @@ -2109,6 +2110,16 @@ void Application::idle() { lastIdleEnd = usecTimestampNow(); } +float Application::getAverageSimsPerSecond() { + uint64_t now = usecTimestampNow(); + + if (now - _lastSimsPerSecondUpdate > USECS_PER_SECOND) { + _simsPerSecondReport = _simsPerSecond.getAverage(); + _lastSimsPerSecondUpdate = now; + } + return _simsPerSecondReport; +} + void Application::setLowVelocityFilter(bool lowVelocityFilter) { InputDevice::setLowVelocityFilter(lowVelocityFilter); } diff --git a/interface/src/Application.h b/interface/src/Application.h index fd57406249..f49fb38e57 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -352,8 +352,7 @@ public: const QRect& getMirrorViewRect() const { return _mirrorViewRect; } - float getAverageInterIdleDuration() { return _interIdleDurations.getAverage(); } - float getAverageSimsPerSecond() { return _simsPerSecond.getAverage(); } + float getAverageSimsPerSecond(); signals: @@ -687,8 +686,9 @@ private: EntityItemID _keyboardFocusedItem; quint64 _lastAcceptedKeyPress = 0; - SimpleAverage _interIdleDurations; - SimpleMovingAverage _simsPerSecond; + SimpleMovingAverage _simsPerSecond{10}; + int _simsPerSecondReport = 0; + quint64 _lastSimsPerSecondUpdate = 0; }; #endif // hifi_Application_h From e29bb9183b230bce810617c2f75a1aa911072ba1 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 18 Aug 2015 02:08:21 -0700 Subject: [PATCH 059/102] minimize diff --- interface/src/Application.cpp | 3 ++- interface/src/Application.h | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index de77b95e23..c9c3b94e03 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -89,6 +89,7 @@ #include #include #include +#include #include #include #include @@ -2002,6 +2003,7 @@ void Application::checkFPS() { void Application::idle() { PROFILE_RANGE(__FUNCTION__); + static SimpleAverage interIdleDurations; static uint64_t lastIdleStart{ 0 }; static uint64_t lastIdleEnd{ 0 }; @@ -2014,7 +2016,6 @@ void Application::idle() { lastIdleStart = now; - static SimpleAverage interIdleDurations; if (lastIdleEnd != 0) { interIdleDurations.update(now - lastIdleEnd); static uint64_t lastReportTime = now; diff --git a/interface/src/Application.h b/interface/src/Application.h index f49fb38e57..4819bd08a4 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -38,7 +38,6 @@ #include #include #include -#include #include #include "AudioClient.h" From 44399da41cc6e315341916f3ee74b4f59a671730 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 18 Aug 2015 14:54:21 +0200 Subject: [PATCH 060/102] Removed the minimize button from the tool window. Close it to hide it. Fixes bug where ToolWindow hides forever. --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4e790bfa88..35206c64de 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -560,7 +560,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _toolWindow = new ToolWindow(); - _toolWindow->setWindowFlags(_toolWindow->windowFlags() | Qt::WindowStaysOnTopHint); + _toolWindow->setWindowFlags((_toolWindow->windowFlags() | Qt::WindowStaysOnTopHint) & ~Qt::WindowMinimizeButtonHint); _toolWindow->setWindowTitle("Tools"); _offscreenContext->makeCurrent(); From 00aa336a2bda14ee9eb8279640f13c6ba53331f2 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 18 Aug 2015 10:01:00 -0700 Subject: [PATCH 061/102] Add further temporary debug for tracking down invalid scale value assert --- interface/src/avatar/Avatar.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 55809646c0..0adf2589cd 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -688,6 +688,23 @@ glm::vec3 Avatar::getDisplayNamePosition() const { const float HEAD_PROPORTION = 0.75f; namePosition = _position + getBodyUpDirection() * (getBillboardSize() * HEAD_PROPORTION); } +#ifdef DEBUG + // TODO: Temporary logging to track cause of invalid scale value; remove once cause has been fixed. + // See other TODO below. + if (glm::isnan(namePosition.x) || glm::isnan(namePosition.y) || glm::isnan(namePosition.z) + || glm::isinf(namePosition.x) || glm::isinf(namePosition.y) || glm::isinf(namePosition.z)) { + qDebug() << "namePosition =" << namePosition; + glm::vec3 tempPosition(0.0f); + if (getSkeletonModel().getNeckPosition(tempPosition)) { + qDebug() << "getBodyUpDirection() =" << getBodyUpDirection(); + qDebug() << "getHeadHeight() =" << getHeadHeight(); + } else { + qDebug() << "_position =" << _position; + qDebug() << "getBodyUpDirection() =" << getBodyUpDirection(); + qDebug() << "getBillboardSize() =" << getBillboardSize(); + } + } +#endif return namePosition; } @@ -722,7 +739,8 @@ Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& frustum, floa // Compute correct scale to apply float scale = DESIRED_HIGHT_ON_SCREEN / (fontSize * pixelHeight) * devicePixelRatio; #ifdef DEBUG - // TODO: Temporary logging to track cause of invalid scale vale; remove once cause has been fixed. + // TODO: Temporary logging to track cause of invalid scale value; remove once cause has been fixed. + // Problem is probably due to an invalid getDisplayNamePosition(). See extra logging above. if (scale == 0.0f || glm::isnan(scale) || glm::isinf(scale)) { if (scale == 0.0f) { qDebug() << "ASSERT because scale == 0.0f"; @@ -733,6 +751,7 @@ Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& frustum, floa if (glm::isinf(scale)) { qDebug() << "ASSERT because isinf(scale)"; } + qDebug() << "textPosition =" << textPosition; qDebug() << "windowSizeY =" << windowSizeY; qDebug() << "p1.y =" << p1.y; qDebug() << "p1.w =" << p1.w; From f6815c215a5b4afa79747b87e3b942177d1eb665 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 18 Aug 2015 10:59:49 -0700 Subject: [PATCH 062/102] Fix edit toolbar moving to top left of screen --- examples/libraries/toolBars.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/libraries/toolBars.js b/examples/libraries/toolBars.js index 16c68a73fb..abe8de8cc3 100644 --- a/examples/libraries/toolBars.js +++ b/examples/libraries/toolBars.js @@ -362,8 +362,11 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit this.fractionKey = optionalPersistenceKey + '.fraction'; this.save = function () { var screenSize = Controller.getViewportDimensions(); - var fraction = {x: that.x / screenSize.x, y: that.y / screenSize.y}; - Settings.setValue(this.fractionKey, JSON.stringify(fraction)); + if (screenSize.x > 0 && screenSize.y > 0) { + // Guard against invalid screen size that can occur at shut-down. + var fraction = {x: that.x / screenSize.x, y: that.y / screenSize.y}; + Settings.setValue(this.fractionKey, JSON.stringify(fraction)); + } } } else { this.save = function () { }; // Called on move. Can be overriden or extended by clients. From 2dc2757ecabf501ed5c92f4c1d069b028d172b50 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 18 Aug 2015 13:03:54 -0700 Subject: [PATCH 063/102] code review --- .../src/RenderablePolyVoxEntityItem.cpp | 14 +++++++------- .../src/RenderablePolyVoxEntityItem.h | 8 ++++---- libraries/entities/src/PolyVoxEntityItem.h | 8 ++++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 5c0a7888e5..5d139a719a 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -659,9 +659,9 @@ void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) { uint32_t p1Index = *(it++); uint32_t p2Index = *(it++); - const glm::vec3 p0 = vertexBufferView.get(p0Index); - const glm::vec3 p1 = vertexBufferView.get(p1Index); - const glm::vec3 p2 = vertexBufferView.get(p2Index); + const glm::vec3& p0 = vertexBufferView.get(p0Index); + const glm::vec3& p1 = vertexBufferView.get(p1Index); + const glm::vec3& p2 = vertexBufferView.get(p2Index); glm::vec3 av = (p0 + p1 + p2) / 3.0f; // center of the triangular face glm::vec3 normal = glm::normalize(glm::cross(p1 - p0, p2 - p0)); @@ -959,18 +959,18 @@ namespace render { } } -glm::vec3 RenderablePolyVoxEntityItem::voxelCoordsToWorldCoords(glm::vec3 voxelCoords) { +glm::vec3 RenderablePolyVoxEntityItem::voxelCoordsToWorldCoords(glm::vec3& voxelCoords) const { return glm::vec3(voxelToWorldMatrix() * glm::vec4(voxelCoords, 1.0f)); } -glm::vec3 RenderablePolyVoxEntityItem::worldCoordsToVoxelCoords(glm::vec3 worldCoords) { +glm::vec3 RenderablePolyVoxEntityItem::worldCoordsToVoxelCoords(glm::vec3& worldCoords) const { return glm::vec3(worldToVoxelMatrix() * glm::vec4(worldCoords, 1.0f)); } -glm::vec3 RenderablePolyVoxEntityItem::voxelCoordsToLocalCoords(glm::vec3 voxelCoords) { +glm::vec3 RenderablePolyVoxEntityItem::voxelCoordsToLocalCoords(glm::vec3& voxelCoords) const { return glm::vec3(voxelToLocalMatrix() * glm::vec4(voxelCoords, 0.0f)); } -glm::vec3 RenderablePolyVoxEntityItem::localCoordsToVoxelCoords(glm::vec3 localCoords) { +glm::vec3 RenderablePolyVoxEntityItem::localCoordsToVoxelCoords(glm::vec3& localCoords) const { return glm::vec3(localToVoxelMatrix() * glm::vec4(localCoords, 0.0f)); } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index ffc45beb22..e2fcdedc31 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -79,10 +79,10 @@ public: virtual bool isReadyToComputeShape(); virtual void computeShapeInfo(ShapeInfo& info); - virtual glm::vec3 voxelCoordsToWorldCoords(glm::vec3 voxelCoords); - virtual glm::vec3 worldCoordsToVoxelCoords(glm::vec3 worldCoords); - virtual glm::vec3 voxelCoordsToLocalCoords(glm::vec3 voxelCoords); - virtual glm::vec3 localCoordsToVoxelCoords(glm::vec3 localCoords); + virtual glm::vec3 voxelCoordsToWorldCoords(glm::vec3& voxelCoords) const; + virtual glm::vec3 worldCoordsToVoxelCoords(glm::vec3& worldCoords) const; + virtual glm::vec3 voxelCoordsToLocalCoords(glm::vec3& voxelCoords) const; + virtual glm::vec3 localCoordsToVoxelCoords(glm::vec3& localCoords) const; // coords are in voxel-volume space virtual bool setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue); diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 2ba57f85de..9fbaade407 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -77,10 +77,10 @@ class PolyVoxEntityItem : public EntityItem { virtual bool setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue) { return false; } virtual bool setVoxelInVolume(glm::vec3 position, uint8_t toValue) { return false; } - virtual glm::vec3 voxelCoordsToWorldCoords(glm::vec3 voxelCoords) { return glm::vec3(0.0f); } - virtual glm::vec3 worldCoordsToVoxelCoords(glm::vec3 worldCoords) { return glm::vec3(0.0f); } - virtual glm::vec3 voxelCoordsToLocalCoords(glm::vec3 voxelCoords) { return glm::vec3(0.0f); } - virtual glm::vec3 localCoordsToVoxelCoords(glm::vec3 localCoords) { return glm::vec3(0.0f); } + virtual glm::vec3 voxelCoordsToWorldCoords(glm::vec3& voxelCoords) const { return glm::vec3(0.0f); } + virtual glm::vec3 worldCoordsToVoxelCoords(glm::vec3& worldCoords) const { return glm::vec3(0.0f); } + virtual glm::vec3 voxelCoordsToLocalCoords(glm::vec3& voxelCoords) const { return glm::vec3(0.0f); } + virtual glm::vec3 localCoordsToVoxelCoords(glm::vec3& localCoords) const { return glm::vec3(0.0f); } // coords are in world-space virtual bool setSphere(glm::vec3 center, float radius, uint8_t toValue) { return false; } From 944734fed2d38ad47ed25a9d0f33d90b21b0eddb Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 18 Aug 2015 13:59:39 -0700 Subject: [PATCH 064/102] Remove focus highlight on delete entity --- interface/src/Application.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c9c3b94e03..a9997c7426 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -719,6 +719,16 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : } }); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::deletingEntity, + [=](const EntityItemID& entityItemID) { + if (entityItemID == _keyboardFocusedItem) { + _keyboardFocusedItem = UNKNOWN_ENTITY_ID; + if (_keyboardFocusHighlight) { + _keyboardFocusHighlight->setVisible(false); + } + } + }); + // If the user clicks somewhere where there is NO entity at all, we will release focus connect(getEntities(), &EntityTreeRenderer::mousePressOffEntity, [=](const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId) { From 5fcbd37e439c95c8c0d983430a27cc165b3457aa Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 18 Aug 2015 15:45:17 -0700 Subject: [PATCH 065/102] possible fix for invisible other's-avatar bug --- interface/src/avatar/Avatar.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 0adf2589cd..4d8e3d99dd 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -563,6 +563,9 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { } void Avatar::fixupModelsInScene() { + if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { + return; + } // check to see if when we added our models to the scene they were ready, if they were not ready, then // fix them up in the scene From eba446e7f66010436b70a331394f5a507f0b8103 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 17 Aug 2015 10:52:05 -0700 Subject: [PATCH 066/102] Updating to the new version of the sixense library --- CMakeLists.txt | 1 + cmake/externals/sixense/CMakeLists.txt | 61 +++++++++++++------------- cmake/modules/FindSixense.cmake | 2 +- libraries/input-plugins/CMakeLists.txt | 8 ++-- 4 files changed, 37 insertions(+), 35 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 38bcb42e26..41b88e4cea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -187,6 +187,7 @@ option(GET_OPENVR "Get OpenVR library automatically as external project" 1) option(GET_BOOSTCONFIG "Get Boost-config library automatically as external project" 1) option(GET_OGLPLUS "Get OGLplus library automatically as external project" 1) option(GET_GLEW "Get GLEW library automatically as external project" 1) +option(GET_SIXENSE "Get Sixense library automatically as external project" 1) option(USE_NSIGHT "Attempt to find the nSight libraries" 1) diff --git a/cmake/externals/sixense/CMakeLists.txt b/cmake/externals/sixense/CMakeLists.txt index c80b492509..d0778774cb 100644 --- a/cmake/externals/sixense/CMakeLists.txt +++ b/cmake/externals/sixense/CMakeLists.txt @@ -7,54 +7,55 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) ExternalProject_Add( ${EXTERNAL_NAME} - URL ./SixenseSDK_062612.zip - URL_MD5 10cc8dc470d2ac1244a88cf04bc549cc + URL http://hifi-public.s3.amazonaws.com/dependencies/SixenseSDK_071615.zip + URL_MD5 752a3901f334124e9cffc2ba4136ef7d CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" LOG_DOWNLOAD 1 ) -if (APPLE) - find_library(SIXENSE_LIBRARY_RELEASE lib/osx_x64/release_dll/libsixense_x64.dylib HINTS ${SIXENSE_SEARCH_DIRS}) - find_library(SIXENSE_LIBRARY_DEBUG lib/osx_x64/debug_dll/libsixensed_x64.dylib HINTS ${SIXENSE_SEARCH_DIRS}) -elseif (UNIX) - find_library(SIXENSE_LIBRARY_RELEASE lib/linux_x64/release/libsixense_x64.so HINTS ${SIXENSE_SEARCH_DIRS}) - # find_library(SIXENSE_LIBRARY_DEBUG lib/linux_x64/debug/libsixensed_x64.so HINTS ${SIXENSE_SEARCH_DIRS}) -elseif (WIN32) -endif () - - - ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE INTERNAL) if (WIN32) - - if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") - set(ARCH_DIR "x64") - set(ARCH_SUFFIX "_x64") - else() - set(ARCH_DIR "Win32") - set(ARCH_SUFFIX "") - endif() + if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + set(ARCH_DIR "x64/VS2013") + set(ARCH_SUFFIX "_x64") + else() + set(ARCH_DIR "Win32/VS2013") + set(ARCH_SUFFIX "") + endif() + + set(LIB_DIR "${SOURCE_DIR}/lib/${ARCH_DIR}") + set(BIN_DIR "${SOURCE_DIR}/bin/${ARCH_DIR}") + set(SIXENSE_LIBRARY_RELEASE "${LIB_DIR}/release_dll/sixense${ARCH_SUFFIX}.lib" CACHE FILEPATH "Sixense release lib") + set(SIXENSE_LIBRARY_DEBUG "${LIB_DIR}/debug_dll/sixensed${ARCH_SUFFIX}.lib" CACHE FILEPATH "Sixense debug lib") + set(SIXENSE_RELEASE_DLL_PATH "${BIN_DIR}/release_dll" CACHE FILEPATH "Sixense release DLL path") + set(SIXENSE_DEBUG_DLL_PATH "${BIN_DIR}/debug_dll" CACHE FILEPATH "Sixense debug DLL path") # FIXME need to account for different architectures - set(${EXTERNAL_NAME_UPPER}_LIBRARIES "${SOURCE_DIR}/lib/${ARCH_DIR}/release_dll/sixense${ARCH_SUFFIX}.lib" CACHE TYPE INTERNAL) - add_paths_to_fixup_libs(${SOURCE_DIR}/bin/win32) + add_paths_to_fixup_libs(${SIXENSE_DEBUG_DLL_PATH}) + add_paths_to_fixup_libs(${SIXENSE_RELEASE_DLL_PATH}) elseif(APPLE) - # FIXME need to account for different architectures - set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/osx32/libopenvr_api.dylib CACHE TYPE INTERNAL) - add_paths_to_fixup_libs(${SOURCE_DIR}/bin/osx32) + set(ARCH_DIR "osx_x64") + set(ARCH_SUFFIX "_x64") + set(LIB_DIR "${SOURCE_DIR}/lib/${ARCH_DIR}") + + set(SIXENSE_LIBRARY_RELEASE "${LIB_DIR}/release_dll/libsixense${ARCH_SUFFIX}.dylib" CACHE FILEPATH "Sixense release lib") + set(SIXENSE_LIBRARY_DEBUG "${LIB_DIR}/debug_dll/libsixensed${ARCH_SUFFIX}.dylib" CACHE FILEPATH "Sixense debug lib") elseif(NOT ANDROID) - # FIXME need to account for different architectures - set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/linux32/libopenvr_api.so CACHE TYPE INTERNAL) - add_paths_to_fixup_libs(${SOURCE_DIR}/bin/linux32) - + set(ARCH_DIR "linux_x64") + set(ARCH_SUFFIX "_x64") + set(LIB_DIR "${SOURCE_DIR}/lib/${ARCH_DIR}") + + set(SIXENSE_LIBRARY_RELEASE "${LIB_DIR}/release/libsixense${ARCH_SUFFIX}.so" CACHE FILEPATH "Sixense release lib") + set(SIXENSE_LIBRARY_DEBUG "${LIB_DIR}/debug/libsixensed${ARCH_SUFFIX}.so" CACHE FILEPATH "Sixense debug lib") + endif() diff --git a/cmake/modules/FindSixense.cmake b/cmake/modules/FindSixense.cmake index 98b37d5410..64cc1e0ffb 100644 --- a/cmake/modules/FindSixense.cmake +++ b/cmake/modules/FindSixense.cmake @@ -51,7 +51,7 @@ select_library_configurations(SIXENSE) set(SIXENSE_REQUIREMENTS SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES) if (WIN32) - list(APPEND SIXENSE_REQUIREMENTS SIXENSE_DEBUG_DLL_PATH SIXENSE_RELEASE_DLL_PATH SIXENSE_DEVICE_DLL_PATH) + list(APPEND SIXENSE_REQUIREMENTS SIXENSE_DEBUG_DLL_PATH SIXENSE_RELEASE_DLL_PATH) endif () set(SIXENSE_LIBRARIES "${SIXENSE_LIBRARY}") diff --git a/libraries/input-plugins/CMakeLists.txt b/libraries/input-plugins/CMakeLists.txt index c3ded6c587..41cee2f666 100644 --- a/libraries/input-plugins/CMakeLists.txt +++ b/libraries/input-plugins/CMakeLists.txt @@ -28,10 +28,10 @@ if (WIN32) target_link_libraries(${TARGET_NAME} ${OPENVR_LIBRARIES}) endif() -#add_dependency_external_projects(Sixense) -#find_package(Sixense REQUIRED) -#target_include_directories(${TARGET_NAME} PRIVATE ${SIXENSE_INCLUDE_DIRS}) -#target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES}) +add_dependency_external_projects(Sixense) +find_package(Sixense REQUIRED) +target_include_directories(${TARGET_NAME} PRIVATE ${SIXENSE_INCLUDE_DIRS}) +target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES}) # perform standard include and linking for found externals foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) From 86e21c91ba3fa3e5057786aee1beec3ce296f6a0 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 18 Aug 2015 15:08:48 -0700 Subject: [PATCH 067/102] Case issues again --- cmake/externals/{sixense => Sixense}/CMakeLists.txt | 8 +++----- libraries/input-plugins/CMakeLists.txt | 3 ++- 2 files changed, 5 insertions(+), 6 deletions(-) rename cmake/externals/{sixense => Sixense}/CMakeLists.txt (96%) diff --git a/cmake/externals/sixense/CMakeLists.txt b/cmake/externals/Sixense/CMakeLists.txt similarity index 96% rename from cmake/externals/sixense/CMakeLists.txt rename to cmake/externals/Sixense/CMakeLists.txt index d0778774cb..7991ccea1b 100644 --- a/cmake/externals/sixense/CMakeLists.txt +++ b/cmake/externals/Sixense/CMakeLists.txt @@ -1,10 +1,5 @@ -include(ExternalProject) -include(SelectLibraryConfigurations) - set(EXTERNAL_NAME Sixense) -string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) - ExternalProject_Add( ${EXTERNAL_NAME} URL http://hifi-public.s3.amazonaws.com/dependencies/SixenseSDK_071615.zip @@ -15,8 +10,11 @@ ExternalProject_Add( LOG_DOWNLOAD 1 ) +set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") + ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) +string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE INTERNAL) if (WIN32) diff --git a/libraries/input-plugins/CMakeLists.txt b/libraries/input-plugins/CMakeLists.txt index 41cee2f666..28af865c7a 100644 --- a/libraries/input-plugins/CMakeLists.txt +++ b/libraries/input-plugins/CMakeLists.txt @@ -32,6 +32,7 @@ add_dependency_external_projects(Sixense) find_package(Sixense REQUIRED) target_include_directories(${TARGET_NAME} PRIVATE ${SIXENSE_INCLUDE_DIRS}) target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES}) +message( ${SIXENSE_INCLUDE_DIRS}) # perform standard include and linking for found externals foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) @@ -69,4 +70,4 @@ foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) add_definitions(-DSIXENSE_LIB_FILENAME=\"${${${EXTERNAL}_UPPERCASE}_LIBRARY_RELEASE}\") endif () endif () -endforeach() \ No newline at end of file +endforeach() From 7f09df1d0ba4877a6a9c7b032dab6bc25e8f389c Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 18 Aug 2015 16:17:27 -0700 Subject: [PATCH 068/102] Fixing external --- cmake/externals/Sixense/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmake/externals/Sixense/CMakeLists.txt b/cmake/externals/Sixense/CMakeLists.txt index 7991ccea1b..46341bd37b 100644 --- a/cmake/externals/Sixense/CMakeLists.txt +++ b/cmake/externals/Sixense/CMakeLists.txt @@ -1,3 +1,6 @@ +include(ExternalProject) +include(SelectLibraryConfigurations) + set(EXTERNAL_NAME Sixense) ExternalProject_Add( From 940390ee46b1fa9663ba19282d271b076f401539 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 18 Aug 2015 19:31:05 -0700 Subject: [PATCH 069/102] make enable-avatar-collisions menu item work again --- interface/src/Menu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 939d733a13..f074dc5ac7 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -258,7 +258,7 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::BlueSpeechSphere, 0, true); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::EnableCharacterController, 0, true, - avatar, SLOT(updateMotionBehavior())); + avatar, SLOT(updateMotionBehaviorFromMenu())); MenuWrapper* viewMenu = addMenu("View"); addActionToQMenuAndActionHash(viewMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches())); From aba7bebf6e5623be7c352ab79336703e51dd6f48 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 19 Aug 2015 09:44:51 -0700 Subject: [PATCH 070/102] Revert "Updating to the new version of the sixense library" --- CMakeLists.txt | 1 - cmake/externals/Sixense/CMakeLists.txt | 62 -------------------------- cmake/externals/sixense/CMakeLists.txt | 60 +++++++++++++++++++++++++ cmake/modules/FindSixense.cmake | 2 +- libraries/input-plugins/CMakeLists.txt | 11 +++-- 5 files changed, 66 insertions(+), 70 deletions(-) delete mode 100644 cmake/externals/Sixense/CMakeLists.txt create mode 100644 cmake/externals/sixense/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 41b88e4cea..38bcb42e26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -187,7 +187,6 @@ option(GET_OPENVR "Get OpenVR library automatically as external project" 1) option(GET_BOOSTCONFIG "Get Boost-config library automatically as external project" 1) option(GET_OGLPLUS "Get OGLplus library automatically as external project" 1) option(GET_GLEW "Get GLEW library automatically as external project" 1) -option(GET_SIXENSE "Get Sixense library automatically as external project" 1) option(USE_NSIGHT "Attempt to find the nSight libraries" 1) diff --git a/cmake/externals/Sixense/CMakeLists.txt b/cmake/externals/Sixense/CMakeLists.txt deleted file mode 100644 index 46341bd37b..0000000000 --- a/cmake/externals/Sixense/CMakeLists.txt +++ /dev/null @@ -1,62 +0,0 @@ -include(ExternalProject) -include(SelectLibraryConfigurations) - -set(EXTERNAL_NAME Sixense) - -ExternalProject_Add( - ${EXTERNAL_NAME} - URL http://hifi-public.s3.amazonaws.com/dependencies/SixenseSDK_071615.zip - URL_MD5 752a3901f334124e9cffc2ba4136ef7d - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - LOG_DOWNLOAD 1 -) - -set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") - -ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) - -string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) -set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE INTERNAL) - -if (WIN32) - if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") - set(ARCH_DIR "x64/VS2013") - set(ARCH_SUFFIX "_x64") - else() - set(ARCH_DIR "Win32/VS2013") - set(ARCH_SUFFIX "") - endif() - - set(LIB_DIR "${SOURCE_DIR}/lib/${ARCH_DIR}") - set(BIN_DIR "${SOURCE_DIR}/bin/${ARCH_DIR}") - set(SIXENSE_LIBRARY_RELEASE "${LIB_DIR}/release_dll/sixense${ARCH_SUFFIX}.lib" CACHE FILEPATH "Sixense release lib") - set(SIXENSE_LIBRARY_DEBUG "${LIB_DIR}/debug_dll/sixensed${ARCH_SUFFIX}.lib" CACHE FILEPATH "Sixense debug lib") - set(SIXENSE_RELEASE_DLL_PATH "${BIN_DIR}/release_dll" CACHE FILEPATH "Sixense release DLL path") - set(SIXENSE_DEBUG_DLL_PATH "${BIN_DIR}/debug_dll" CACHE FILEPATH "Sixense debug DLL path") - - # FIXME need to account for different architectures - add_paths_to_fixup_libs(${SIXENSE_DEBUG_DLL_PATH}) - add_paths_to_fixup_libs(${SIXENSE_RELEASE_DLL_PATH}) - -elseif(APPLE) - - set(ARCH_DIR "osx_x64") - set(ARCH_SUFFIX "_x64") - set(LIB_DIR "${SOURCE_DIR}/lib/${ARCH_DIR}") - - set(SIXENSE_LIBRARY_RELEASE "${LIB_DIR}/release_dll/libsixense${ARCH_SUFFIX}.dylib" CACHE FILEPATH "Sixense release lib") - set(SIXENSE_LIBRARY_DEBUG "${LIB_DIR}/debug_dll/libsixensed${ARCH_SUFFIX}.dylib" CACHE FILEPATH "Sixense debug lib") - -elseif(NOT ANDROID) - - set(ARCH_DIR "linux_x64") - set(ARCH_SUFFIX "_x64") - set(LIB_DIR "${SOURCE_DIR}/lib/${ARCH_DIR}") - - set(SIXENSE_LIBRARY_RELEASE "${LIB_DIR}/release/libsixense${ARCH_SUFFIX}.so" CACHE FILEPATH "Sixense release lib") - set(SIXENSE_LIBRARY_DEBUG "${LIB_DIR}/debug/libsixensed${ARCH_SUFFIX}.so" CACHE FILEPATH "Sixense debug lib") - -endif() - diff --git a/cmake/externals/sixense/CMakeLists.txt b/cmake/externals/sixense/CMakeLists.txt new file mode 100644 index 0000000000..c80b492509 --- /dev/null +++ b/cmake/externals/sixense/CMakeLists.txt @@ -0,0 +1,60 @@ +include(ExternalProject) +include(SelectLibraryConfigurations) + +set(EXTERNAL_NAME Sixense) + +string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) + +ExternalProject_Add( + ${EXTERNAL_NAME} + URL ./SixenseSDK_062612.zip + URL_MD5 10cc8dc470d2ac1244a88cf04bc549cc + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + LOG_DOWNLOAD 1 +) + +if (APPLE) + find_library(SIXENSE_LIBRARY_RELEASE lib/osx_x64/release_dll/libsixense_x64.dylib HINTS ${SIXENSE_SEARCH_DIRS}) + find_library(SIXENSE_LIBRARY_DEBUG lib/osx_x64/debug_dll/libsixensed_x64.dylib HINTS ${SIXENSE_SEARCH_DIRS}) +elseif (UNIX) + find_library(SIXENSE_LIBRARY_RELEASE lib/linux_x64/release/libsixense_x64.so HINTS ${SIXENSE_SEARCH_DIRS}) + # find_library(SIXENSE_LIBRARY_DEBUG lib/linux_x64/debug/libsixensed_x64.so HINTS ${SIXENSE_SEARCH_DIRS}) +elseif (WIN32) +endif () + + + +ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) + +set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE INTERNAL) + +if (WIN32) + + if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + set(ARCH_DIR "x64") + set(ARCH_SUFFIX "_x64") + else() + set(ARCH_DIR "Win32") + set(ARCH_SUFFIX "") + endif() + + # FIXME need to account for different architectures + set(${EXTERNAL_NAME_UPPER}_LIBRARIES "${SOURCE_DIR}/lib/${ARCH_DIR}/release_dll/sixense${ARCH_SUFFIX}.lib" CACHE TYPE INTERNAL) + add_paths_to_fixup_libs(${SOURCE_DIR}/bin/win32) + +elseif(APPLE) + + # FIXME need to account for different architectures + set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/osx32/libopenvr_api.dylib CACHE TYPE INTERNAL) + add_paths_to_fixup_libs(${SOURCE_DIR}/bin/osx32) + +elseif(NOT ANDROID) + + # FIXME need to account for different architectures + set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/linux32/libopenvr_api.so CACHE TYPE INTERNAL) + add_paths_to_fixup_libs(${SOURCE_DIR}/bin/linux32) + +endif() + diff --git a/cmake/modules/FindSixense.cmake b/cmake/modules/FindSixense.cmake index 64cc1e0ffb..98b37d5410 100644 --- a/cmake/modules/FindSixense.cmake +++ b/cmake/modules/FindSixense.cmake @@ -51,7 +51,7 @@ select_library_configurations(SIXENSE) set(SIXENSE_REQUIREMENTS SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES) if (WIN32) - list(APPEND SIXENSE_REQUIREMENTS SIXENSE_DEBUG_DLL_PATH SIXENSE_RELEASE_DLL_PATH) + list(APPEND SIXENSE_REQUIREMENTS SIXENSE_DEBUG_DLL_PATH SIXENSE_RELEASE_DLL_PATH SIXENSE_DEVICE_DLL_PATH) endif () set(SIXENSE_LIBRARIES "${SIXENSE_LIBRARY}") diff --git a/libraries/input-plugins/CMakeLists.txt b/libraries/input-plugins/CMakeLists.txt index 28af865c7a..c3ded6c587 100644 --- a/libraries/input-plugins/CMakeLists.txt +++ b/libraries/input-plugins/CMakeLists.txt @@ -28,11 +28,10 @@ if (WIN32) target_link_libraries(${TARGET_NAME} ${OPENVR_LIBRARIES}) endif() -add_dependency_external_projects(Sixense) -find_package(Sixense REQUIRED) -target_include_directories(${TARGET_NAME} PRIVATE ${SIXENSE_INCLUDE_DIRS}) -target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES}) -message( ${SIXENSE_INCLUDE_DIRS}) +#add_dependency_external_projects(Sixense) +#find_package(Sixense REQUIRED) +#target_include_directories(${TARGET_NAME} PRIVATE ${SIXENSE_INCLUDE_DIRS}) +#target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES}) # perform standard include and linking for found externals foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) @@ -70,4 +69,4 @@ foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) add_definitions(-DSIXENSE_LIB_FILENAME=\"${${${EXTERNAL}_UPPERCASE}_LIBRARY_RELEASE}\") endif () endif () -endforeach() +endforeach() \ No newline at end of file From 0a8c1846e9539e5320cefde79d8416bbd0cb1124 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Wed, 19 Aug 2015 10:24:31 -0700 Subject: [PATCH 071/102] This assert causes dev builds to fail when starting interface. --- libraries/render-utils/src/OffscreenQmlSurface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/OffscreenQmlSurface.cpp b/libraries/render-utils/src/OffscreenQmlSurface.cpp index 0dfd95a725..9923849aab 100644 --- a/libraries/render-utils/src/OffscreenQmlSurface.cpp +++ b/libraries/render-utils/src/OffscreenQmlSurface.cpp @@ -239,7 +239,7 @@ private: return; } - Q_ASSERT(toGlm(_quickWindow->geometry().size()) == _size); + //Q_ASSERT(toGlm(_quickWindow->geometry().size()) == _size); //Q_ASSERT(toGlm(_quickWindow->geometry().size()) == _textures._size); _renderControl->sync(); From 92ae3e758c9a849c60e13132a18566ea062732e4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Aug 2015 12:28:07 -0700 Subject: [PATCH 072/102] restore DEFAULT_FAR_CLIP to 16km --- libraries/octree/src/ViewFrustum.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/octree/src/ViewFrustum.h b/libraries/octree/src/ViewFrustum.h index 3e41b58bb6..fe40cfd53c 100644 --- a/libraries/octree/src/ViewFrustum.h +++ b/libraries/octree/src/ViewFrustum.h @@ -31,7 +31,7 @@ const float DEFAULT_KEYHOLE_RADIUS = 3.0f; const float DEFAULT_FIELD_OF_VIEW_DEGREES = 45.0f; const float DEFAULT_ASPECT_RATIO = 16.0f/9.0f; const float DEFAULT_NEAR_CLIP = 0.08f; -const float DEFAULT_FAR_CLIP = (float)TREE_SCALE; +const float DEFAULT_FAR_CLIP = (float)HALF_TREE_SCALE; class ViewFrustum { public: From 9605294ea8b1b8fd2fd8062f427b2d9455de3955 Mon Sep 17 00:00:00 2001 From: Chris Collins Date: Wed, 19 Aug 2015 12:55:52 -0700 Subject: [PATCH 073/102] Removed HMDcontrol.js from default scripts Removed HMDcontrol.js from default scripts. Will put back when HMDcontrol is fixed --- examples/defaultScripts.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js index 922047b90c..c06ecd393d 100644 --- a/examples/defaultScripts.js +++ b/examples/defaultScripts.js @@ -17,5 +17,4 @@ Script.load("users.js"); Script.load("grab.js"); Script.load("directory.js"); Script.load("mouseLook.js"); -Script.load("hmdControls.js"); Script.load("dialTone.js"); From 846ca3b86b59b84190a3a72ee747eb3c3ce67910 Mon Sep 17 00:00:00 2001 From: Chris Collins Date: Wed, 19 Aug 2015 12:58:26 -0700 Subject: [PATCH 074/102] removed mouselook removed mouselook --- examples/defaultScripts.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js index c06ecd393d..c602c36382 100644 --- a/examples/defaultScripts.js +++ b/examples/defaultScripts.js @@ -16,5 +16,4 @@ Script.load("notifications.js"); Script.load("users.js"); Script.load("grab.js"); Script.load("directory.js"); -Script.load("mouseLook.js"); Script.load("dialTone.js"); From 6860f3d126e4c7688016ca3536072034111dd82d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 19 Aug 2015 14:32:26 -0700 Subject: [PATCH 075/102] add readWithoutCopy for clarity in Packet read --- assignment-client/src/AssignmentClientMonitor.cpp | 2 +- assignment-client/src/audio/AudioMixerClientData.cpp | 2 +- .../src/avatars/AvatarMixerClientData.cpp | 2 +- libraries/audio/src/InboundAudioStream.cpp | 4 ++-- libraries/avatars/src/AvatarHashMap.cpp | 10 +++++----- libraries/entities/src/EntityTree.cpp | 2 +- libraries/networking/src/LimitedNodeList.cpp | 2 +- libraries/networking/src/NodeList.cpp | 2 +- libraries/networking/src/udt/Packet.cpp | 7 +++++++ libraries/networking/src/udt/Packet.h | 3 ++- 10 files changed, 22 insertions(+), 14 deletions(-) diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 72765dd0df..ddea6cc702 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -203,7 +203,7 @@ void AssignmentClientMonitor::checkSpares() { void AssignmentClientMonitor::handleChildStatusPacket(QSharedPointer packet) { // read out the sender ID - QUuid senderID = QUuid::fromRfc4122(packet->read(NUM_BYTES_RFC4122_UUID)); + QUuid senderID = QUuid::fromRfc4122(packet->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); auto nodeList = DependencyManager::get(); diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 10a5992fd8..7e822951d8 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -90,7 +90,7 @@ int AudioMixerClientData::parseData(NLPacket& packet) { // grab the stream identifier for this injected audio packet.seek(sizeof(quint16)); - QUuid streamIdentifier = QUuid::fromRfc4122(packet.read(NUM_BYTES_RFC4122_UUID)); + QUuid streamIdentifier = QUuid::fromRfc4122(packet.readWithoutCopy(NUM_BYTES_RFC4122_UUID)); bool isStereo; packet.readPrimitive(&isStereo); diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index fec51f76cb..65660b178e 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -15,7 +15,7 @@ int AvatarMixerClientData::parseData(NLPacket& packet) { // compute the offset to the data payload - return _avatar.parseDataFromBuffer(packet.read(packet.bytesLeftToRead())); + return _avatar.parseDataFromBuffer(packet.readWithoutCopy(packet.bytesLeftToRead())); } bool AvatarMixerClientData::checkAndSetHasReceivedFirstPackets() { diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index 8888c9bae5..d552db1735 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -112,7 +112,7 @@ int InboundAudioStream::parseData(NLPacket& packet) { // parse the info after the seq number and before the audio data (the stream properties) int prePropertyPosition = packet.pos(); - int propertyBytes = parseStreamProperties(packet.getType(), packet.read(packet.bytesLeftToRead()), networkSamples); + int propertyBytes = parseStreamProperties(packet.getType(), packet.readWithoutCopy(packet.bytesLeftToRead()), networkSamples); packet.seek(prePropertyPosition + propertyBytes); // handle this packet based on its arrival status. @@ -131,7 +131,7 @@ int InboundAudioStream::parseData(NLPacket& packet) { if (packet.getType() == PacketType::SilentAudioFrame) { writeDroppableSilentSamples(networkSamples); } else { - parseAudioData(packet.getType(), packet.read(packet.bytesLeftToRead()), networkSamples); + parseAudioData(packet.getType(), packet.readWithoutCopy(packet.bytesLeftToRead()), networkSamples); } break; } diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 5c65f89990..d2ec5d68f0 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -53,11 +53,11 @@ void AvatarHashMap::processAvatarDataPacket(QSharedPointer packet, Sha // enumerate over all of the avatars in this packet // only add them if mixerWeakPointer points to something (meaning that mixer is still around) while (packet->bytesLeftToRead()) { - QUuid sessionUUID = QUuid::fromRfc4122(packet->read(NUM_BYTES_RFC4122_UUID)); + QUuid sessionUUID = QUuid::fromRfc4122(packet->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); int positionBeforeRead = packet->pos(); - QByteArray byteArray = packet->read(packet->bytesLeftToRead()); + QByteArray byteArray = packet->readWithoutCopy(packet->bytesLeftToRead()); if (sessionUUID != _lastOwnerSessionUUID) { AvatarSharedPointer avatar = _avatarHash.value(sessionUUID); @@ -114,14 +114,14 @@ void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer packet, } void AvatarHashMap::processAvatarBillboardPacket(QSharedPointer packet, SharedNodePointer sendingNode) { - QUuid sessionUUID = QUuid::fromRfc4122(packet->read(NUM_BYTES_RFC4122_UUID)); + QUuid sessionUUID = QUuid::fromRfc4122(packet->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); AvatarSharedPointer avatar = _avatarHash.value(sessionUUID); if (!avatar) { avatar = addAvatar(sessionUUID, sendingNode); } - QByteArray billboard = packet->read(packet->bytesLeftToRead()); + QByteArray billboard = packet->readWithoutCopy(packet->bytesLeftToRead()); if (avatar->getBillboard() != billboard) { avatar->setBillboard(billboard); } @@ -129,7 +129,7 @@ void AvatarHashMap::processAvatarBillboardPacket(QSharedPointer packet void AvatarHashMap::processKillAvatar(QSharedPointer packet, SharedNodePointer sendingNode) { // read the node id - QUuid sessionUUID = QUuid::fromRfc4122(packet->read(NUM_BYTES_RFC4122_UUID)); + QUuid sessionUUID = QUuid::fromRfc4122(packet->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); removeAvatar(sessionUUID); } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index ba2691aa3b..ba0e3f495f 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -873,7 +873,7 @@ int EntityTree::processEraseMessage(NLPacket& packet, const SharedNodePointer& s break; // bail to prevent buffer overflow } - QUuid entityID = QUuid::fromRfc4122(packet.read(NUM_BYTES_RFC4122_UUID)); + QUuid entityID = QUuid::fromRfc4122(packet.readWithoutCopy(NUM_BYTES_RFC4122_UUID)); EntityItemID entityItemID(entityID); entityItemIDsToDelete << entityItemID; diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index fdb3461c1f..48febf39bd 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -397,7 +397,7 @@ void LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) { void LimitedNodeList::processKillNode(NLPacket& packet) { // read the node id - QUuid nodeUUID = QUuid::fromRfc4122(packet.read(NUM_BYTES_RFC4122_UUID)); + QUuid nodeUUID = QUuid::fromRfc4122(packet.readWithoutCopy(NUM_BYTES_RFC4122_UUID)); // kill the node with this UUID, if it exists killNodeWithUUID(nodeUUID); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 563b7d7080..6616707579 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -463,7 +463,7 @@ void NodeList::processDomainServerConnectionTokenPacket(QSharedPointer return; } // read in the connection token from the packet, then send domain-server checkin - _domainHandler.setConnectionToken(QUuid::fromRfc4122(packet->read(NUM_BYTES_RFC4122_UUID))); + _domainHandler.setConnectionToken(QUuid::fromRfc4122(packet->readWithoutCopy(NUM_BYTES_RFC4122_UUID))); sendDomainServerCheckIn(); } diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 13f8a39e26..81747749be 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -213,6 +213,13 @@ void Packet::writeSequenceNumber(SequenceNumber seqNum) { } QByteArray Packet::read(qint64 maxSize) { + qint64 sizeToRead = std::min(size() - pos(), maxSize); + QByteArray data { getPayload() + pos(), (int) sizeToRead }; + seek(pos() + sizeToRead); + return data; +} + +QByteArray Packet::readWithoutCopy(qint64 maxSize) { qint64 sizeToRead = std::min(size() - pos(), maxSize); QByteArray data { QByteArray::fromRawData(getPayload() + pos(), sizeToRead) }; seek(pos() + sizeToRead); diff --git a/libraries/networking/src/udt/Packet.h b/libraries/networking/src/udt/Packet.h index 91b5974e09..569ff4b9a4 100644 --- a/libraries/networking/src/udt/Packet.h +++ b/libraries/networking/src/udt/Packet.h @@ -81,7 +81,8 @@ public: using QIODevice::read; QByteArray read(qint64 maxSize); - + QByteArray readWithoutCopy(qint64 maxSize); // this can only be used if packet will stay in scope + template qint64 peekPrimitive(T* data); template qint64 readPrimitive(T* data); template qint64 writePrimitive(const T& data); From c8fbb64bbf11ff53ba3172e60aa47d3edd23c2a1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 19 Aug 2015 14:36:16 -0700 Subject: [PATCH 076/102] fix AvatarHashMap read due to COW --- libraries/avatars/src/AvatarHashMap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index d2ec5d68f0..4378e818ec 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -121,7 +121,7 @@ void AvatarHashMap::processAvatarBillboardPacket(QSharedPointer packet avatar = addAvatar(sessionUUID, sendingNode); } - QByteArray billboard = packet->readWithoutCopy(packet->bytesLeftToRead()); + QByteArray billboard = packet->read(packet->bytesLeftToRead()); if (avatar->getBillboard() != billboard) { avatar->setBillboard(billboard); } From 010a3d8220a11783f155028a41ce9fc8b46321ca Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Aug 2015 17:12:03 -0700 Subject: [PATCH 077/102] fix create in negative space bug --- examples/edit.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index f0d782cd4a..deda035d5e 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -1036,6 +1036,7 @@ function handeMenuEvent(menuItem) { // This function tries to find a reasonable position to place a new entity based on the camera // position. If a reasonable position within the world bounds can't be found, `null` will // be returned. The returned position will also take into account grid snapping settings. +// FIXME - technically we should guard against very large positions too function getPositionToCreateEntity() { var distance = cameraManager.enabled ? cameraManager.zoomDistance : DEFAULT_ENTITY_DRAG_DROP_DISTANCE; var direction = Quat.getFront(Camera.orientation); @@ -1055,9 +1056,9 @@ function getPositionToCreateEntity() { return null; } - placementPosition.x = Math.max(0, placementPosition.x); - placementPosition.y = Math.max(0, placementPosition.y); - placementPosition.z = Math.max(0, placementPosition.z); + placementPosition.x = Math.max(-HALF_TREE_SCALE, placementPosition.x); + placementPosition.y = Math.max(-HALF_TREE_SCALE, placementPosition.y); + placementPosition.z = Math.max(-HALF_TREE_SCALE, placementPosition.z); return placementPosition; } From 2056f588e3575e0dae35b66c288f0147fe7bbe39 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 19 Aug 2015 18:03:16 -0700 Subject: [PATCH 078/102] if environment variable HIFI_MEMORY_DEBUGGING is defined when cmake is run, enable -fsanitize=address on linux --- assignment-client/CMakeLists.txt | 10 +++++++++- domain-server/CMakeLists.txt | 8 ++++++++ interface/CMakeLists.txt | 8 ++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index edd68e12bf..7e3b2e6af9 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -18,4 +18,12 @@ if (UNIX) endif (UNIX) include_application_version() -copy_dlls_beside_windows_executable() \ No newline at end of file +copy_dlls_beside_windows_executable() + +if (DEFINED ENV{HIFI_MEMORY_DEBUGGING}) + if (UNIX) + MESSAGE("-- assignment-client memory debugging is enabled.") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") + endif (UNIX) +endif () diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index e4fa1d874d..0d56e34cf2 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -33,3 +33,11 @@ target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES}) include_application_version() copy_dlls_beside_windows_executable() + +if (DEFINED ENV{HIFI_MEMORY_DEBUGGING}) + if (UNIX) + MESSAGE("-- domain-server memory debugging is enabled.") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") + endif (UNIX) +endif () diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index acafafa006..16d8bacd23 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -206,3 +206,11 @@ else (APPLE) endif (APPLE) copy_dlls_beside_windows_executable() + +if (DEFINED ENV{HIFI_MEMORY_DEBUGGING}) + if (UNIX) + MESSAGE("-- interface memory debugging is enabled.") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") + endif (UNIX) +endif () From 6a7f367e5fecc2e37000818e1965be57789323f1 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Aug 2015 21:11:48 -0700 Subject: [PATCH 079/102] fix throttled rendering for the 2D display plugin --- interface/src/Application.cpp | 27 ++++++++- interface/src/Application.h | 3 + interface/src/GLCanvas.cpp | 59 ++----------------- interface/src/GLCanvas.h | 10 ---- interface/src/Menu.h | 2 +- .../Basic2DWindowOpenGLDisplayPlugin.cpp | 21 +++++++ .../Basic2DWindowOpenGLDisplayPlugin.h | 6 ++ .../src/display-plugins/OpenGLDisplayPlugin.h | 4 +- .../plugins/src/plugins/PluginContainer.h | 1 + 9 files changed, 64 insertions(+), 69 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4dd61b7982..15f4a48405 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -175,8 +175,6 @@ public: using namespace std; // Starfield information -static uint8_t THROTTLED_IDLE_TIMER_DELAY = 10; - const qint64 MAXIMUM_CACHE_SIZE = 10 * BYTES_PER_GIGABYTES; // 10GB static QTimer* locationUpdateTimer = NULL; @@ -737,6 +735,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _keyboardFocusHighlight->setVisible(false); } }); + + connect(this, &Application::applicationStateChanged, this, &Application::activeChanged); } void Application::aboutToQuit() { @@ -2108,8 +2108,11 @@ void Application::idle() { // Once rendering is off on another thread we should be able to have Application::idle run at start(0) in // perpetuity and not expect events to get backed up. + bool isThrottled = getActiveDisplayPlugin()->isThrottled(); + static const int THROTTLED_IDLE_TIMER_DELAY = MSECS_PER_SECOND / 15; static const int IDLE_TIMER_DELAY_MS = 2; - int desiredInterval = getActiveDisplayPlugin()->isThrottled() ? THROTTLED_IDLE_TIMER_DELAY : IDLE_TIMER_DELAY_MS; + int desiredInterval = isThrottled ? THROTTLED_IDLE_TIMER_DELAY : IDLE_TIMER_DELAY_MS; + //qDebug() << "isThrottled:" << isThrottled << "desiredInterval:" << desiredInterval; if (idleTimer->interval() != desiredInterval) { idleTimer->start(desiredInterval); @@ -4612,6 +4615,24 @@ void Application::checkSkeleton() { } } +bool Application::isForeground() { + return _isForeground && !getWindow()->isMinimized(); +} + +void Application::activeChanged(Qt::ApplicationState state) { + switch (state) { + case Qt::ApplicationActive: + _isForeground = true; + break; + + case Qt::ApplicationSuspended: + case Qt::ApplicationHidden: + case Qt::ApplicationInactive: + default: + _isForeground = false; + break; + } +} void Application::showFriendsWindow() { const QString FRIENDS_WINDOW_TITLE = "Add/Remove Friends"; const QString FRIENDS_WINDOW_URL = "https://metaverse.highfidelity.com/user/friends"; diff --git a/interface/src/Application.h b/interface/src/Application.h index 4819bd08a4..a1765109ce 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -291,6 +291,7 @@ public: virtual void unsetFullscreen(const QScreen* avoid) override; virtual void showDisplayPluginsTools() override; virtual QGLWidget* getPrimarySurface() override; + virtual bool isForeground() override; void setActiveDisplayPlugin(const QString& pluginName); @@ -476,6 +477,7 @@ private slots: void faceTrackerMuteToggled(); void setCursorVisible(bool visible); + void activeChanged(Qt::ApplicationState state); private: void resetCameras(Camera& camera, const glm::uvec2& size); @@ -688,6 +690,7 @@ private: SimpleMovingAverage _simsPerSecond{10}; int _simsPerSecondReport = 0; quint64 _lastSimsPerSecondUpdate = 0; + bool _isForeground = true; // starts out assumed to be in foreground }; #endif // hifi_Application_h diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 0d0d335b67..bfa2dacf3a 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -18,8 +18,6 @@ #include "MainWindow.h" -const int MSECS_PER_FRAME_WHEN_THROTTLED = 66; - static QGLFormat& getDesiredGLFormat() { // Specify an OpenGL 3.3 format using the Core profile. // That is, no old-school fixed pipeline functionality @@ -35,10 +33,7 @@ static QGLFormat& getDesiredGLFormat() { return glFormat; } -GLCanvas::GLCanvas() : QGLWidget(getDesiredGLFormat()), - _throttleRendering(false), - _idleRenderInterval(MSECS_PER_FRAME_WHEN_THROTTLED) -{ +GLCanvas::GLCanvas() : QGLWidget(getDesiredGLFormat()) { #ifdef Q_OS_LINUX // Cause GLCanvas::eventFilter to be called. // It wouldn't hurt to do this on Mac and PC too; but apparently it's only needed on linux. @@ -46,15 +41,6 @@ GLCanvas::GLCanvas() : QGLWidget(getDesiredGLFormat()), #endif } -void GLCanvas::stopFrameTimer() { - _frameTimer.stop(); -} - -bool GLCanvas::isThrottleRendering() const { - return (_throttleRendering - || (Application::getInstance()->getWindow()->isMinimized() && Application::getInstance()->isThrottleFPSEnabled())); -} - int GLCanvas::getDeviceWidth() const { return width() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f); } @@ -66,17 +52,17 @@ int GLCanvas::getDeviceHeight() const { void GLCanvas::initializeGL() { setAttribute(Qt::WA_AcceptTouchEvents); setAcceptDrops(true); - connect(Application::getInstance(), SIGNAL(applicationStateChanged(Qt::ApplicationState)), this, SLOT(activeChanged(Qt::ApplicationState))); - connect(&_frameTimer, SIGNAL(timeout()), this, SLOT(throttleRender())); - // Note, we *DO NOT* want Qt to automatically swap buffers for us. This results in the "ringing" bug mentioned in WL#19514 when we're throttling the framerate. setAutoBufferSwap(false); } void GLCanvas::paintGL() { PROFILE_RANGE(__FUNCTION__); - if (!_throttleRendering && - (!Application::getInstance()->getWindow()->isMinimized() || !Application::getInstance()->isThrottleFPSEnabled())) { + + // FIXME - I'm not sure why this still remains, it appears as if this GLCanvas gets a single paintGL call near + // the beginning of the application starting up. I'm not sure if we really need to call Application::paintGL() + // in this case, since the display plugins eventually handle all the painting + if ((!Application::getInstance()->getWindow()->isMinimized() || !Application::getInstance()->isThrottleFPSEnabled())) { Application::getInstance()->paintGL(); } } @@ -85,39 +71,6 @@ void GLCanvas::resizeGL(int width, int height) { Application::getInstance()->resizeGL(); } -void GLCanvas::activeChanged(Qt::ApplicationState state) { - switch (state) { - case Qt::ApplicationActive: - // If we're active, stop the frame timer and the throttle. - _frameTimer.stop(); - _throttleRendering = false; - break; - - case Qt::ApplicationSuspended: - case Qt::ApplicationHidden: - // If we're hidden or are about to suspend, don't render anything. - _throttleRendering = false; - _frameTimer.stop(); - break; - - default: - // Otherwise, throttle. - if (!_throttleRendering && !Application::getInstance()->isAboutToQuit() - && Application::getInstance()->isThrottleFPSEnabled()) { - _frameTimer.start(_idleRenderInterval); - _throttleRendering = true; - } - break; - } -} - -void GLCanvas::throttleRender() { - _frameTimer.start(_idleRenderInterval); - if (!Application::getInstance()->getWindow()->isMinimized()) { - Application::getInstance()->paintGL(); - } -} - int updateTime = 0; bool GLCanvas::event(QEvent* event) { switch (event->type()) { diff --git a/interface/src/GLCanvas.h b/interface/src/GLCanvas.h index bcaa9577d1..73c5b5e8bf 100644 --- a/interface/src/GLCanvas.h +++ b/interface/src/GLCanvas.h @@ -23,28 +23,18 @@ class GLCanvas : public QGLWidget { public: GLCanvas(); - void stopFrameTimer(); - - bool isThrottleRendering() const; - int getDeviceWidth() const; int getDeviceHeight() const; QSize getDeviceSize() const { return QSize(getDeviceWidth(), getDeviceHeight()); } protected: - QTimer _frameTimer; - bool _throttleRendering; - int _idleRenderInterval; - virtual void initializeGL(); virtual void paintGL(); virtual void resizeGL(int width, int height); virtual bool event(QEvent* event); private slots: - void activeChanged(Qt::ApplicationState state); - void throttleRender(); bool eventFilter(QObject*, QEvent* event); }; diff --git a/interface/src/Menu.h b/interface/src/Menu.h index b0a78fdd83..ca46b80f92 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -283,7 +283,7 @@ namespace MenuOption { const QString TestPing = "Test Ping"; const QString ThirdPerson = "Third Person"; const QString ThreePointCalibration = "3 Point Calibration"; - const QString ThrottleFPSIfNotFocus = "Throttle FPS If Not Focus"; + const QString ThrottleFPSIfNotFocus = "Throttle FPS If Not Focus"; // FIXME - this value duplicated in Basic2DWindowOpenGLDisplayPlugin.cpp const QString ToolWindow = "Tool Window"; const QString TransmitterDrive = "Transmitter Drive"; const QString TurnWithHead = "Turn using Head"; diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp index ce6467cd55..e478223281 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp @@ -34,3 +34,24 @@ void Basic2DWindowOpenGLDisplayPlugin::deactivate() { // container->removeMenu(MENU_PATH); MainWindowOpenGLDisplayPlugin::deactivate(); } + +int Basic2DWindowOpenGLDisplayPlugin::getDesiredInterval(bool isThrottled) const { + static const int THROTTLED_PAINT_TIMER_DELAY = MSECS_PER_SECOND / 15; + static const int PAINT_TIMER_DELAY_MS = 1; + + return isThrottled ? THROTTLED_PAINT_TIMER_DELAY : PAINT_TIMER_DELAY_MS; +} + +bool Basic2DWindowOpenGLDisplayPlugin::isThrottled() const { + static const QString ThrottleFPSIfNotFocus = "Throttle FPS If Not Focus"; // FIXME - this value duplicated in Menu.h + + bool shouldThrottle = (!CONTAINER->isForeground() && CONTAINER->isOptionChecked(ThrottleFPSIfNotFocus)); + + if (_isThrottled != shouldThrottle) { + int desiredInterval = getDesiredInterval(shouldThrottle); + _timer.start(desiredInterval); + _isThrottled = shouldThrottle; + } + + return shouldThrottle; +} \ No newline at end of file diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h index d19326f007..612d15377a 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h @@ -18,6 +18,12 @@ public: virtual const QString & getName() const override; + virtual bool isThrottled() const override; + +protected: + int getDesiredInterval(bool isThrottled) const; + mutable bool _isThrottled = false; + private: static const QString NAME; }; diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index 9986610a50..9b6b92d8d4 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -37,8 +37,8 @@ protected: virtual void doneCurrent() = 0; virtual void swapBuffers() = 0; - QTimer _timer; - ProgramPtr _program; + mutable QTimer _timer; + ProgramPtr _program; ShapeWrapperPtr _plane; }; diff --git a/libraries/plugins/src/plugins/PluginContainer.h b/libraries/plugins/src/plugins/PluginContainer.h index 85c5c814de..7f6346a181 100644 --- a/libraries/plugins/src/plugins/PluginContainer.h +++ b/libraries/plugins/src/plugins/PluginContainer.h @@ -26,4 +26,5 @@ public: virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) = 0; virtual void showDisplayPluginsTools() = 0; virtual QGLWidget* getPrimarySurface() = 0; + virtual bool isForeground() = 0; }; From 002aea333352b58bf6c107363066a26e486ddb40 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 20 Aug 2015 00:30:44 -0700 Subject: [PATCH 080/102] Add fullscreen menu item to 2D display plugin --- .../Basic2DWindowOpenGLDisplayPlugin.cpp | 27 ++++++++++++------- .../Basic2DWindowOpenGLDisplayPlugin.h | 3 +++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp index e478223281..7667fa1a29 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp @@ -9,12 +9,11 @@ #include #include +#include const QString Basic2DWindowOpenGLDisplayPlugin::NAME("2D Display"); -const QString MENU_PARENT = "View"; -const QString MENU_NAME = "Display Options"; -const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME; +const QString MENU_PATH = "Display"; const QString FULLSCREEN = "Fullscreen"; const QString& Basic2DWindowOpenGLDisplayPlugin::getName() const { @@ -22,16 +21,19 @@ const QString& Basic2DWindowOpenGLDisplayPlugin::getName() const { } void Basic2DWindowOpenGLDisplayPlugin::activate() { -// container->addMenu(MENU_PATH); -// container->addMenuItem(MENU_PATH, FULLSCREEN, -// [this] (bool clicked) { this->setFullscreen(clicked); }, -// true, false); + CONTAINER->addMenu(MENU_PATH); + CONTAINER->addMenuItem(MENU_PATH, FULLSCREEN, + [this](bool clicked) { + if (clicked) { + CONTAINER->setFullscreen(getFullscreenTarget()); + } else { + CONTAINER->unsetFullscreen(); + } + }, true, false); MainWindowOpenGLDisplayPlugin::activate(); } void Basic2DWindowOpenGLDisplayPlugin::deactivate() { -// container->removeMenuItem(MENU_NAME, FULLSCREEN); -// container->removeMenu(MENU_PATH); MainWindowOpenGLDisplayPlugin::deactivate(); } @@ -54,4 +56,9 @@ bool Basic2DWindowOpenGLDisplayPlugin::isThrottled() const { } return shouldThrottle; -} \ No newline at end of file +} + +// FIXME target the screen the window is currently on +QScreen* Basic2DWindowOpenGLDisplayPlugin::getFullscreenTarget() { + return qApp->primaryScreen(); +} diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h index 612d15377a..477e214f4e 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h @@ -9,6 +9,7 @@ #include "MainWindowOpenGLDisplayPlugin.h" +class QScreen; class Basic2DWindowOpenGLDisplayPlugin : public MainWindowOpenGLDisplayPlugin { Q_OBJECT @@ -26,4 +27,6 @@ protected: private: static const QString NAME; + QScreen* getFullscreenTarget(); + int _fullscreenTarget{ -1 }; }; From 9faf45219604941cf3ae9ee48f4107094d77b254 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 20 Aug 2015 00:16:50 -0700 Subject: [PATCH 081/102] Make sure that items added via plugins can be removed as well --- interface/src/Application.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 15f4a48405..5f8b17f178 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4746,6 +4746,7 @@ static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool acti } static QVector> _currentDisplayPluginActions; +static bool _activatingDisplayPlugin{false}; void Application::updateDisplayMode() { auto menu = Menu::getInstance(); @@ -4792,7 +4793,9 @@ void Application::updateDisplayMode() { if (newDisplayPlugin) { _offscreenContext->makeCurrent(); + _activatingDisplayPlugin = true; newDisplayPlugin->activate(); + _activatingDisplayPlugin = false; _offscreenContext->makeCurrent(); offscreenUi->resize(fromGlm(newDisplayPlugin->getRecommendedUiSize())); _offscreenContext->makeCurrent(); @@ -4909,14 +4912,17 @@ void Application::removeMenu(const QString& menuName) { void Application::addMenuItem(const QString& path, const QString& name, std::function onClicked, bool checkable, bool checked, const QString& groupName) { auto menu = Menu::getInstance(); MenuWrapper* parentItem = menu->getMenu(path); - QAction* action = parentItem->addAction(name); + QAction* action = menu->addActionToQMenuAndActionHash(parentItem, name); connect(action, &QAction::triggered, [=] { onClicked(action->isChecked()); }); action->setCheckable(checkable); action->setChecked(checked); - _currentDisplayPluginActions.push_back({ path, name }); - _currentInputPluginActions.push_back({ path, name }); + if (_activatingDisplayPlugin) { + _currentDisplayPluginActions.push_back({ path, name }); + } else { + _currentInputPluginActions.push_back({ path, name }); + } } void Application::removeMenuItem(const QString& menuName, const QString& menuItem) { From 2b26f302fd0353c668230c632b950057ecdf741d Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Thu, 20 Aug 2015 08:01:33 -0600 Subject: [PATCH 082/102] Better handling of socket binding --- .../embedded-webserver/src/HTTPManager.cpp | 30 +++++++++++++++---- .../embedded-webserver/src/HTTPManager.h | 11 ++++++- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/libraries/embedded-webserver/src/HTTPManager.cpp b/libraries/embedded-webserver/src/HTTPManager.cpp index 19443e01da..0d91672904 100644 --- a/libraries/embedded-webserver/src/HTTPManager.cpp +++ b/libraries/embedded-webserver/src/HTTPManager.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include #include #include @@ -19,16 +20,18 @@ #include "EmbeddedWebserverLogging.h" #include "HTTPManager.h" +const int SOCKET_ERROR_EXIT_CODE = 2; + HTTPManager::HTTPManager(quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler, QObject* parent) : QTcpServer(parent), _documentRoot(documentRoot), - _requestHandler(requestHandler) + _requestHandler(requestHandler), + _port(port) { - // start listening on the passed port - if (!listen(QHostAddress("0.0.0.0"), port)) { - qCDebug(embeddedwebserver) << "Failed to open HTTP server socket:" << errorString(); - return; - } + bindSocket(); + _isListeningTimer = new QTimer(this); + connect(_isListeningTimer, &QTimer::timeout, this, &HTTPManager::isTcpServerListening); + _isListeningTimer->start(10000); } void HTTPManager::incomingConnection(qintptr socketDescriptor) { @@ -157,3 +160,18 @@ bool HTTPManager::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool HTTPManager::requestHandledByRequestHandler(HTTPConnection* connection, const QUrl& url) { return _requestHandler && _requestHandler->handleHTTPRequest(connection, url); } + +void HTTPManager::isTcpServerListening() { + if (!isListening()) { + qCWarning(embeddedwebserver) << "Socket on port " << QString::number(_port) << " is no longer listening"; + bindSocket(); + }} + +bool HTTPManager::bindSocket() { + qCDebug(embeddedwebserver) << "Attempting to bind TCP socket on port " << QString::number(_port); + if (!listen(QHostAddress::Any, _port)) { + qCWarning(embeddedwebserver) << "Failed to open HTTP server socket:" << errorString() << " can't continue"; + QCoreApplication::exit(SOCKET_ERROR_EXIT_CODE); + } + return true; +} \ No newline at end of file diff --git a/libraries/embedded-webserver/src/HTTPManager.h b/libraries/embedded-webserver/src/HTTPManager.h index 83c4103c15..6375b10205 100644 --- a/libraries/embedded-webserver/src/HTTPManager.h +++ b/libraries/embedded-webserver/src/HTTPManager.h @@ -17,6 +17,7 @@ #define hifi_HTTPManager_h #include +#include class HTTPConnection; class HTTPSConnection; @@ -35,14 +36,22 @@ public: HTTPManager(quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler = NULL, QObject* parent = 0); bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false); + +private slots: + void isTcpServerListening(); + +private: + bool bindSocket(); protected: /// Accepts all pending connections virtual void incomingConnection(qintptr socketDescriptor); virtual bool requestHandledByRequestHandler(HTTPConnection* connection, const QUrl& url); -protected: + QString _documentRoot; HTTPRequestHandler* _requestHandler; + QTimer* _isListeningTimer; + const quint16 _port; }; #endif // hifi_HTTPManager_h From f87f3eb03319af5b6fedff39b09a2b4f00403866 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Thu, 20 Aug 2015 08:02:45 -0600 Subject: [PATCH 083/102] Typo --- libraries/embedded-webserver/src/HTTPManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/embedded-webserver/src/HTTPManager.cpp b/libraries/embedded-webserver/src/HTTPManager.cpp index 0d91672904..c0d49e8638 100644 --- a/libraries/embedded-webserver/src/HTTPManager.cpp +++ b/libraries/embedded-webserver/src/HTTPManager.cpp @@ -165,7 +165,8 @@ void HTTPManager::isTcpServerListening() { if (!isListening()) { qCWarning(embeddedwebserver) << "Socket on port " << QString::number(_port) << " is no longer listening"; bindSocket(); - }} + } +} bool HTTPManager::bindSocket() { qCDebug(embeddedwebserver) << "Attempting to bind TCP socket on port " << QString::number(_port); From 2c23dab2e74b5333603be7ba224445135e683833 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Thu, 20 Aug 2015 08:03:37 -0600 Subject: [PATCH 084/102] More specific logging --- libraries/embedded-webserver/src/HTTPManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/embedded-webserver/src/HTTPManager.cpp b/libraries/embedded-webserver/src/HTTPManager.cpp index c0d49e8638..6e953598de 100644 --- a/libraries/embedded-webserver/src/HTTPManager.cpp +++ b/libraries/embedded-webserver/src/HTTPManager.cpp @@ -171,7 +171,7 @@ void HTTPManager::isTcpServerListening() { bool HTTPManager::bindSocket() { qCDebug(embeddedwebserver) << "Attempting to bind TCP socket on port " << QString::number(_port); if (!listen(QHostAddress::Any, _port)) { - qCWarning(embeddedwebserver) << "Failed to open HTTP server socket:" << errorString() << " can't continue"; + qCritical() << "Failed to open HTTP server socket:" << errorString() << " can't continue"; QCoreApplication::exit(SOCKET_ERROR_EXIT_CODE); } return true; From 129761c002781c0c48341dda89d78142af765279 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Thu, 20 Aug 2015 08:10:19 -0600 Subject: [PATCH 085/102] making qtimer interval a const --- libraries/embedded-webserver/src/HTTPManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/embedded-webserver/src/HTTPManager.cpp b/libraries/embedded-webserver/src/HTTPManager.cpp index 6e953598de..72436fc55e 100644 --- a/libraries/embedded-webserver/src/HTTPManager.cpp +++ b/libraries/embedded-webserver/src/HTTPManager.cpp @@ -21,6 +21,7 @@ #include "HTTPManager.h" const int SOCKET_ERROR_EXIT_CODE = 2; +const int SOCKET_CHECK_INTERVAL_IN_MS = 30000; HTTPManager::HTTPManager(quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler, QObject* parent) : QTcpServer(parent), @@ -31,7 +32,7 @@ HTTPManager::HTTPManager(quint16 port, const QString& documentRoot, HTTPRequestH bindSocket(); _isListeningTimer = new QTimer(this); connect(_isListeningTimer, &QTimer::timeout, this, &HTTPManager::isTcpServerListening); - _isListeningTimer->start(10000); + _isListeningTimer->start(SOCKET_CHECK_INTERVAL_IN_MS); } void HTTPManager::incomingConnection(qintptr socketDescriptor) { From cd050b2e60ddd787058db61443a3ae7eca71a562 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 20 Aug 2015 09:53:58 -0700 Subject: [PATCH 086/102] don't show hmd tools for direct mod HMDs --- interface/src/Application.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5f8b17f178..a28435e258 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4803,10 +4803,17 @@ void Application::updateDisplayMode() { oldDisplayPlugin = _displayPlugin; _displayPlugin = newDisplayPlugin; - + + // If the displayPlugin is a screen based HMD, then it will want the HMDTools displayed + // Direct Mode HMDs (like windows Oculus) will be isHmd() but will have a screen of -1 + bool newPluginWantsHMDTools = newDisplayPlugin ? + (newDisplayPlugin->isHmd() && (newDisplayPlugin->getHmdScreen() >= 0)) : false; + bool oldPluginWantedHMDTools = oldDisplayPlugin ? + (oldDisplayPlugin->isHmd() && (oldDisplayPlugin->getHmdScreen() >= 0)) : false; + // Only show the hmd tools after the correct plugin has // been activated so that it's UI is setup correctly - if (newDisplayPlugin->isHmd()) { + if (newPluginWantsHMDTools) { showDisplayPluginsTools(); } @@ -4815,7 +4822,7 @@ void Application::updateDisplayMode() { _offscreenContext->makeCurrent(); // if the old plugin was HMD and the new plugin is not HMD, then hide our hmdtools - if (oldDisplayPlugin->isHmd() && !newDisplayPlugin->isHmd()) { + if (oldPluginWantedHMDTools && !newPluginWantsHMDTools) { DependencyManager::get()->hmdTools(false); } } From c25082d86f45c5562750ddd81e6afb77f159b903 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 20 Aug 2015 10:14:16 -0700 Subject: [PATCH 087/102] use -fsanitize=address in all code rather than just the top-level links --- CMakeLists.txt | 6 ++++++ assignment-client/CMakeLists.txt | 11 +++-------- cmake/macros/MemoryDebugger.cmake | 21 +++++++++++++++++++++ domain-server/CMakeLists.txt | 10 ++-------- gvr-interface/CMakeLists.txt | 4 +++- ice-server/CMakeLists.txt | 4 +++- interface/CMakeLists.txt | 10 ++-------- libraries/animation/CMakeLists.txt | 4 +++- libraries/audio-client/CMakeLists.txt | 4 +++- libraries/audio/CMakeLists.txt | 2 ++ libraries/auto-updater/CMakeLists.txt | 3 +++ libraries/avatars/CMakeLists.txt | 2 ++ libraries/display-plugins/CMakeLists.txt | 4 +++- libraries/embedded-webserver/CMakeLists.txt | 4 +++- libraries/entities-renderer/CMakeLists.txt | 2 ++ libraries/entities/CMakeLists.txt | 2 ++ libraries/environment/CMakeLists.txt | 4 +++- libraries/fbx/CMakeLists.txt | 4 +++- libraries/gpu/CMakeLists.txt | 2 ++ libraries/input-plugins/CMakeLists.txt | 4 +++- libraries/model/CMakeLists.txt | 4 +++- libraries/networking/CMakeLists.txt | 4 +++- libraries/octree/CMakeLists.txt | 2 ++ libraries/physics/CMakeLists.txt | 2 ++ libraries/plugins/CMakeLists.txt | 5 +++-- libraries/render-utils/CMakeLists.txt | 2 ++ libraries/render/CMakeLists.txt | 4 +++- libraries/script-engine/CMakeLists.txt | 2 ++ libraries/shared/CMakeLists.txt | 2 ++ libraries/ui/CMakeLists.txt | 5 +++-- tests/CMakeLists.txt | 2 ++ tests/animation/CMakeLists.txt | 2 ++ tests/audio/CMakeLists.txt | 4 +++- tests/entities/CMakeLists.txt | 4 +++- tests/jitter/CMakeLists.txt | 4 +++- tests/networking/CMakeLists.txt | 4 +++- tests/octree/CMakeLists.txt | 4 +++- tests/physics/CMakeLists.txt | 2 ++ tests/render-utils/CMakeLists.txt | 3 +++ tests/shaders/CMakeLists.txt | 3 +++ tests/shared/CMakeLists.txt | 4 +++- tests/ui/CMakeLists.txt | 4 +++- tools/CMakeLists.txt | 3 ++- tools/mtc/CMakeLists.txt | 4 +++- tools/scribe/CMakeLists.txt | 5 ++++- tools/vhacd-util/CMakeLists.txt | 2 ++ 46 files changed, 143 insertions(+), 50 deletions(-) create mode 100644 cmake/macros/MemoryDebugger.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 38bcb42e26..bc4c938f08 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -213,3 +213,9 @@ endif () if (ANDROID OR DESKTOP_GVR) add_subdirectory(gvr-interface) endif () + +if (DEFINED ENV{HIFI_MEMORY_DEBUGGING}) + if (UNIX) + MESSAGE("-- Memory debugging is enabled") + endif (UNIX) +endif () diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index 7e3b2e6af9..315eeb6b83 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -18,12 +18,7 @@ if (UNIX) endif (UNIX) include_application_version() -copy_dlls_beside_windows_executable() -if (DEFINED ENV{HIFI_MEMORY_DEBUGGING}) - if (UNIX) - MESSAGE("-- assignment-client memory debugging is enabled.") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") - SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") - endif (UNIX) -endif () +setup_memory_debugger() + +copy_dlls_beside_windows_executable() diff --git a/cmake/macros/MemoryDebugger.cmake b/cmake/macros/MemoryDebugger.cmake new file mode 100644 index 0000000000..cb907efa96 --- /dev/null +++ b/cmake/macros/MemoryDebugger.cmake @@ -0,0 +1,21 @@ +# +# MemoryDebugger.cmake +# +# Copyright 2015 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 +# + +macro(SETUP_MEMORY_DEBUGGER) +if (DEFINED ENV{HIFI_MEMORY_DEBUGGING}) + SET( HIFI_MEMORY_DEBUGGING true ) +endif () + +if (HIFI_MEMORY_DEBUGGING) + if (UNIX) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libasan -static-libstdc++ -fsanitize=address") + endif (UNIX) +endif () +endmacro(SETUP_MEMORY_DEBUGGER) diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index 0d56e34cf2..d2f30b6c25 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -1,5 +1,7 @@ set(TARGET_NAME domain-server) +setup_memory_debugger() + if (UPPER_CMAKE_BUILD_TYPE MATCHES DEBUG AND NOT WIN32) set(_SHOULD_SYMLINK_RESOURCES TRUE) else () @@ -33,11 +35,3 @@ target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES}) include_application_version() copy_dlls_beside_windows_executable() - -if (DEFINED ENV{HIFI_MEMORY_DEBUGGING}) - if (UNIX) - MESSAGE("-- domain-server memory debugging is enabled.") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") - SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") - endif (UNIX) -endif () diff --git a/gvr-interface/CMakeLists.txt b/gvr-interface/CMakeLists.txt index a986fcae0d..c4880a80b6 100644 --- a/gvr-interface/CMakeLists.txt +++ b/gvr-interface/CMakeLists.txt @@ -88,4 +88,6 @@ if (ANDROID) endif (ANDROID) -copy_dlls_beside_windows_executable() \ No newline at end of file +setup_memory_debugger() + +copy_dlls_beside_windows_executable() diff --git a/ice-server/CMakeLists.txt b/ice-server/CMakeLists.txt index 13d89fc4a2..d62192bcec 100644 --- a/ice-server/CMakeLists.txt +++ b/ice-server/CMakeLists.txt @@ -1,9 +1,11 @@ set(TARGET_NAME ice-server) +setup_memory_debugger() + # setup the project and link required Qt modules setup_hifi_project(Network) # link the shared hifi libraries link_hifi_libraries(embedded-webserver networking shared) -copy_dlls_beside_windows_executable() \ No newline at end of file +copy_dlls_beside_windows_executable() diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 16d8bacd23..d858673774 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -205,12 +205,6 @@ else (APPLE) endif() endif (APPLE) -copy_dlls_beside_windows_executable() +setup_memory_debugger() -if (DEFINED ENV{HIFI_MEMORY_DEBUGGING}) - if (UNIX) - MESSAGE("-- interface memory debugging is enabled.") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") - SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") - endif (UNIX) -endif () +copy_dlls_beside_windows_executable() diff --git a/libraries/animation/CMakeLists.txt b/libraries/animation/CMakeLists.txt index 8c75d5620c..fc7fa23dcc 100644 --- a/libraries/animation/CMakeLists.txt +++ b/libraries/animation/CMakeLists.txt @@ -3,4 +3,6 @@ set(TARGET_NAME animation) # use setup_hifi_library macro to setup our project and link appropriate Qt modules setup_hifi_library(Network Script) -link_hifi_libraries(shared gpu model fbx) \ No newline at end of file +setup_memory_debugger() + +link_hifi_libraries(shared gpu model fbx) diff --git a/libraries/audio-client/CMakeLists.txt b/libraries/audio-client/CMakeLists.txt index 43a2016acf..c313aecbc0 100644 --- a/libraries/audio-client/CMakeLists.txt +++ b/libraries/audio-client/CMakeLists.txt @@ -1,5 +1,7 @@ set(TARGET_NAME audio-client) +setup_memory_debugger() + # use setup_hifi_library macro to setup our project and link appropriate Qt modules setup_hifi_library(Network Multimedia) @@ -25,4 +27,4 @@ if (APPLE) find_library(CoreAudio CoreAudio) find_library(CoreFoundation CoreFoundation) target_link_libraries(${TARGET_NAME} ${CoreAudio} ${CoreFoundation}) -endif () \ No newline at end of file +endif () diff --git a/libraries/audio/CMakeLists.txt b/libraries/audio/CMakeLists.txt index c03f588d94..a0d40b1a10 100644 --- a/libraries/audio/CMakeLists.txt +++ b/libraries/audio/CMakeLists.txt @@ -1,5 +1,7 @@ set(TARGET_NAME audio) +setup_memory_debugger() + # use setup_hifi_library macro to setup our project and link appropriate Qt modules setup_hifi_library(Network) diff --git a/libraries/auto-updater/CMakeLists.txt b/libraries/auto-updater/CMakeLists.txt index b3665af2cb..6960d8368d 100644 --- a/libraries/auto-updater/CMakeLists.txt +++ b/libraries/auto-updater/CMakeLists.txt @@ -1,3 +1,6 @@ set(TARGET_NAME auto-updater) + +setup_memory_debugger() + setup_hifi_library(Network) link_hifi_libraries(shared networking) diff --git a/libraries/avatars/CMakeLists.txt b/libraries/avatars/CMakeLists.txt index acc939b25c..b05c667c71 100644 --- a/libraries/avatars/CMakeLists.txt +++ b/libraries/avatars/CMakeLists.txt @@ -1,5 +1,7 @@ set(TARGET_NAME avatars) +setup_memory_debugger() + # use setup_hifi_library macro to setup our project and link appropriate Qt modules setup_hifi_library(Network Script) diff --git a/libraries/display-plugins/CMakeLists.txt b/libraries/display-plugins/CMakeLists.txt index 321b13f191..79b41fa957 100644 --- a/libraries/display-plugins/CMakeLists.txt +++ b/libraries/display-plugins/CMakeLists.txt @@ -1,5 +1,7 @@ set(TARGET_NAME display-plugins) +setup_memory_debugger() + # use setup_hifi_library macro to setup our project and link appropriate Qt modules setup_hifi_library(OpenGL) @@ -31,4 +33,4 @@ if (WIN32) find_package(OpenVR REQUIRED) target_include_directories(${TARGET_NAME} PRIVATE ${OPENVR_INCLUDE_DIRS}) target_link_libraries(${TARGET_NAME} ${OPENVR_LIBRARIES}) -endif() \ No newline at end of file +endif() diff --git a/libraries/embedded-webserver/CMakeLists.txt b/libraries/embedded-webserver/CMakeLists.txt index 955487e540..2d8915998b 100644 --- a/libraries/embedded-webserver/CMakeLists.txt +++ b/libraries/embedded-webserver/CMakeLists.txt @@ -1,4 +1,6 @@ set(TARGET_NAME embedded-webserver) +setup_memory_debugger() + # use setup_hifi_library macro to setup our project and link appropriate Qt modules -setup_hifi_library(Network) \ No newline at end of file +setup_hifi_library(Network) diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index c4dddb8971..3387715348 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -26,4 +26,6 @@ find_package(PolyVox REQUIRED) target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${POLYVOX_INCLUDE_DIRS}) target_link_libraries(${TARGET_NAME} ${POLYVOX_LIBRARIES}) +setup_memory_debugger() + link_hifi_libraries(shared gpu script-engine render render-utils) diff --git a/libraries/entities/CMakeLists.txt b/libraries/entities/CMakeLists.txt index f7936ff125..368257661e 100644 --- a/libraries/entities/CMakeLists.txt +++ b/libraries/entities/CMakeLists.txt @@ -1,5 +1,7 @@ set(TARGET_NAME entities) +setup_memory_debugger() + # use setup_hifi_library macro to setup our project and link appropriate Qt modules setup_hifi_library(Network Script) diff --git a/libraries/environment/CMakeLists.txt b/libraries/environment/CMakeLists.txt index a2ee9e3f55..fbdc614d26 100644 --- a/libraries/environment/CMakeLists.txt +++ b/libraries/environment/CMakeLists.txt @@ -7,4 +7,6 @@ add_dependency_external_projects(glm) find_package(GLM REQUIRED) target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) -link_hifi_libraries(shared networking) \ No newline at end of file +setup_memory_debugger() + +link_hifi_libraries(shared networking) diff --git a/libraries/fbx/CMakeLists.txt b/libraries/fbx/CMakeLists.txt index 1ce1c74922..c06bb0efc1 100644 --- a/libraries/fbx/CMakeLists.txt +++ b/libraries/fbx/CMakeLists.txt @@ -7,4 +7,6 @@ add_dependency_external_projects(glm) find_package(GLM REQUIRED) target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) -link_hifi_libraries(shared gpu model networking octree) \ No newline at end of file +setup_memory_debugger() + +link_hifi_libraries(shared gpu model networking octree) diff --git a/libraries/gpu/CMakeLists.txt b/libraries/gpu/CMakeLists.txt index 7a88580f7f..84320297eb 100644 --- a/libraries/gpu/CMakeLists.txt +++ b/libraries/gpu/CMakeLists.txt @@ -1,5 +1,7 @@ set(TARGET_NAME gpu) +setup_memory_debugger() + AUTOSCRIBE_SHADER_LIB(gpu) # use setup_hifi_library macro to setup our project and link appropriate Qt modules diff --git a/libraries/input-plugins/CMakeLists.txt b/libraries/input-plugins/CMakeLists.txt index c3ded6c587..4428327deb 100644 --- a/libraries/input-plugins/CMakeLists.txt +++ b/libraries/input-plugins/CMakeLists.txt @@ -33,6 +33,8 @@ endif() #target_include_directories(${TARGET_NAME} PRIVATE ${SIXENSE_INCLUDE_DIRS}) #target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES}) +setup_memory_debugger() + # perform standard include and linking for found externals foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) @@ -69,4 +71,4 @@ foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) add_definitions(-DSIXENSE_LIB_FILENAME=\"${${${EXTERNAL}_UPPERCASE}_LIBRARY_RELEASE}\") endif () endif () -endforeach() \ No newline at end of file +endforeach() diff --git a/libraries/model/CMakeLists.txt b/libraries/model/CMakeLists.txt index 563f347952..2099f83fec 100755 --- a/libraries/model/CMakeLists.txt +++ b/libraries/model/CMakeLists.txt @@ -1,7 +1,9 @@ set(TARGET_NAME model) - + AUTOSCRIBE_SHADER_LIB(gpu model) +setup_memory_debugger() + # use setup_hifi_library macro to setup our project and link appropriate Qt modules setup_hifi_library() diff --git a/libraries/networking/CMakeLists.txt b/libraries/networking/CMakeLists.txt index d79e6bde58..d0e0b850c7 100644 --- a/libraries/networking/CMakeLists.txt +++ b/libraries/networking/CMakeLists.txt @@ -1,5 +1,7 @@ set(TARGET_NAME networking) +setup_memory_debugger() + # use setup_hifi_library macro to setup our project and link appropriate Qt modules setup_hifi_library(Network) @@ -29,4 +31,4 @@ target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES} ${TBB_LIBRARIES}) # append tbb includes to our list of includes to bubble target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${TBB_INCLUDE_DIRS}) -include_application_version() \ No newline at end of file +include_application_version() diff --git a/libraries/octree/CMakeLists.txt b/libraries/octree/CMakeLists.txt index cc36aead15..8b9ff6bda2 100644 --- a/libraries/octree/CMakeLists.txt +++ b/libraries/octree/CMakeLists.txt @@ -1,5 +1,7 @@ set(TARGET_NAME octree) +setup_memory_debugger() + # use setup_hifi_library macro to setup our project and link appropriate Qt modules setup_hifi_library() diff --git a/libraries/physics/CMakeLists.txt b/libraries/physics/CMakeLists.txt index b1f9fbb79c..802665b948 100644 --- a/libraries/physics/CMakeLists.txt +++ b/libraries/physics/CMakeLists.txt @@ -1,5 +1,7 @@ set(TARGET_NAME physics) +setup_memory_debugger() + # use setup_hifi_library macro to setup our project and link appropriate Qt modules setup_hifi_library() diff --git a/libraries/plugins/CMakeLists.txt b/libraries/plugins/CMakeLists.txt index 28b136ccf4..98fd5fdc93 100644 --- a/libraries/plugins/CMakeLists.txt +++ b/libraries/plugins/CMakeLists.txt @@ -7,6 +7,7 @@ link_hifi_libraries(shared) add_dependency_external_projects(glm) find_package(GLM REQUIRED) + +setup_memory_debugger() + target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) - - diff --git a/libraries/render-utils/CMakeLists.txt b/libraries/render-utils/CMakeLists.txt index 0ea71e54e3..ceb1a192ab 100644 --- a/libraries/render-utils/CMakeLists.txt +++ b/libraries/render-utils/CMakeLists.txt @@ -40,4 +40,6 @@ add_dependency_external_projects(oglplus) find_package(OGLPLUS REQUIRED) target_include_directories(${TARGET_NAME} PUBLIC ${OGLPLUS_INCLUDE_DIRS}) +setup_memory_debugger() + link_hifi_libraries(animation fbx shared gpu model render environment) diff --git a/libraries/render/CMakeLists.txt b/libraries/render/CMakeLists.txt index 4d2be949e6..1f73d93519 100644 --- a/libraries/render/CMakeLists.txt +++ b/libraries/render/CMakeLists.txt @@ -1,5 +1,7 @@ set(TARGET_NAME render) +setup_memory_debugger() + AUTOSCRIBE_SHADER_LIB(gpu model) # use setup_hifi_library macro to setup our project and link appropriate Qt modules @@ -21,4 +23,4 @@ if (WIN32) target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}") endif () endif() -endif (WIN32) \ No newline at end of file +endif (WIN32) diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index 99d9149c3a..6bb53389af 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -1,5 +1,7 @@ set(TARGET_NAME script-engine) +setup_memory_debugger() + # use setup_hifi_library macro to setup our project and link appropriate Qt modules setup_hifi_library(Gui Network Script Widgets) diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index 00a80619bc..a80f4194ef 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -1,5 +1,7 @@ set(TARGET_NAME shared) +setup_memory_debugger() + # use setup_hifi_library macro to setup our project and link appropriate Qt modules # TODO: there isn't really a good reason to have Script linked here - let's get what is requiring it out (RegisteredMetaTypes.cpp) setup_hifi_library(Gui Network Script Widgets) diff --git a/libraries/ui/CMakeLists.txt b/libraries/ui/CMakeLists.txt index 1aefc99c78..68caa940c1 100644 --- a/libraries/ui/CMakeLists.txt +++ b/libraries/ui/CMakeLists.txt @@ -7,6 +7,7 @@ link_hifi_libraries(render-utils shared) add_dependency_external_projects(glm) find_package(GLM REQUIRED) + +setup_memory_debugger() + target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) - - diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1593b649a0..c2dc30c4bb 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -35,3 +35,5 @@ set_target_properties("all-tests" PROPERTIES FOLDER "hidden/test-targets") set_target_properties("all-tests" PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD TRUE EXCLUDE_FROM_ALL TRUE) + +setup_memory_debugger() diff --git a/tests/animation/CMakeLists.txt b/tests/animation/CMakeLists.txt index 2e9dbc9424..bc1e93a94f 100644 --- a/tests/animation/CMakeLists.txt +++ b/tests/animation/CMakeLists.txt @@ -6,4 +6,6 @@ macro (setup_testcase_dependencies) copy_dlls_beside_windows_executable() endmacro () +setup_memory_debugger() + setup_hifi_testcase() diff --git a/tests/audio/CMakeLists.txt b/tests/audio/CMakeLists.txt index 8e894e929e..c56ef049bd 100644 --- a/tests/audio/CMakeLists.txt +++ b/tests/audio/CMakeLists.txt @@ -6,4 +6,6 @@ macro (SETUP_TESTCASE_DEPENDENCIES) copy_dlls_beside_windows_executable() endmacro () -setup_hifi_testcase() \ No newline at end of file +setup_memory_debugger() + +setup_hifi_testcase() diff --git a/tests/entities/CMakeLists.txt b/tests/entities/CMakeLists.txt index 0077549100..f83efe7f64 100644 --- a/tests/entities/CMakeLists.txt +++ b/tests/entities/CMakeLists.txt @@ -9,4 +9,6 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") # link in the shared libraries link_hifi_libraries(entities avatars shared octree gpu model fbx networking animation environment) -copy_dlls_beside_windows_executable() \ No newline at end of file +setup_memory_debugger() + +copy_dlls_beside_windows_executable() diff --git a/tests/jitter/CMakeLists.txt b/tests/jitter/CMakeLists.txt index 7b636aa87f..ba46582b02 100644 --- a/tests/jitter/CMakeLists.txt +++ b/tests/jitter/CMakeLists.txt @@ -7,4 +7,6 @@ macro (setup_testcase_dependencies) copy_dlls_beside_windows_executable() endmacro() -setup_hifi_testcase() \ No newline at end of file +setup_memory_debugger() + +setup_hifi_testcase() diff --git a/tests/networking/CMakeLists.txt b/tests/networking/CMakeLists.txt index 3be2fff027..fcf32d89c8 100644 --- a/tests/networking/CMakeLists.txt +++ b/tests/networking/CMakeLists.txt @@ -7,4 +7,6 @@ macro (setup_testcase_dependencies) copy_dlls_beside_windows_executable() endmacro () -setup_hifi_testcase() \ No newline at end of file +setup_memory_debugger() + +setup_hifi_testcase() diff --git a/tests/octree/CMakeLists.txt b/tests/octree/CMakeLists.txt index a605a4088b..77511c682a 100644 --- a/tests/octree/CMakeLists.txt +++ b/tests/octree/CMakeLists.txt @@ -7,4 +7,6 @@ macro (setup_testcase_dependencies) copy_dlls_beside_windows_executable() endmacro () -setup_hifi_testcase(Script Network) \ No newline at end of file +setup_memory_debugger() + +setup_hifi_testcase(Script Network) diff --git a/tests/physics/CMakeLists.txt b/tests/physics/CMakeLists.txt index 36cf21c681..1a6f49430b 100644 --- a/tests/physics/CMakeLists.txt +++ b/tests/physics/CMakeLists.txt @@ -21,4 +21,6 @@ macro (SETUP_TESTCASE_DEPENDENCIES) copy_dlls_beside_windows_executable() endmacro () +setup_memory_debugger() + setup_hifi_testcase(Script) diff --git a/tests/render-utils/CMakeLists.txt b/tests/render-utils/CMakeLists.txt index 97d3214744..1b47f85099 100644 --- a/tests/render-utils/CMakeLists.txt +++ b/tests/render-utils/CMakeLists.txt @@ -9,4 +9,7 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") link_hifi_libraries(render-utils gpu shared) message(${PROJECT_BINARY_DIR}) + +setup_memory_debugger() + copy_dlls_beside_windows_executable() diff --git a/tests/shaders/CMakeLists.txt b/tests/shaders/CMakeLists.txt index eefdf2aa3a..3ee9f4ae9f 100644 --- a/tests/shaders/CMakeLists.txt +++ b/tests/shaders/CMakeLists.txt @@ -18,4 +18,7 @@ include_directories("${PROJECT_BINARY_DIR}/../../libraries/entities-renderer/") include_directories("${PROJECT_BINARY_DIR}/../../libraries/model/") message(${PROJECT_BINARY_DIR}) + +setup_memory_debugger() + copy_dlls_beside_windows_executable() diff --git a/tests/shared/CMakeLists.txt b/tests/shared/CMakeLists.txt index bc6eab0212..c3d6cfd810 100644 --- a/tests/shared/CMakeLists.txt +++ b/tests/shared/CMakeLists.txt @@ -8,4 +8,6 @@ macro (setup_testcase_dependencies) copy_dlls_beside_windows_executable() endmacro () -setup_hifi_testcase() \ No newline at end of file +setup_memory_debugger() + +setup_hifi_testcase() diff --git a/tests/ui/CMakeLists.txt b/tests/ui/CMakeLists.txt index ad1009d925..c0f20a280f 100644 --- a/tests/ui/CMakeLists.txt +++ b/tests/ui/CMakeLists.txt @@ -13,4 +13,6 @@ endif() # link in the shared libraries link_hifi_libraries(ui render-utils gpu shared) -copy_dlls_beside_windows_executable() \ No newline at end of file +setup_memory_debugger() + +copy_dlls_beside_windows_executable() diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 55994f3d89..4d8618b37c 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,3 +1,5 @@ +setup_memory_debugger() + # add the tool directories add_subdirectory(mtc) set_target_properties(mtc PROPERTIES FOLDER "Tools") @@ -7,4 +9,3 @@ set_target_properties(scribe PROPERTIES FOLDER "Tools") add_subdirectory(vhacd-util) set_target_properties(vhacd-util PROPERTIES FOLDER "Tools") - diff --git a/tools/mtc/CMakeLists.txt b/tools/mtc/CMakeLists.txt index 5c598eaf0b..fe5f1920bc 100644 --- a/tools/mtc/CMakeLists.txt +++ b/tools/mtc/CMakeLists.txt @@ -1,4 +1,6 @@ set(TARGET_NAME mtc) setup_hifi_project() -copy_dlls_beside_windows_executable() \ No newline at end of file +setup_memory_debugger() + +copy_dlls_beside_windows_executable() diff --git a/tools/scribe/CMakeLists.txt b/tools/scribe/CMakeLists.txt index b71a287e46..0abf70f727 100755 --- a/tools/scribe/CMakeLists.txt +++ b/tools/scribe/CMakeLists.txt @@ -1,2 +1,5 @@ set(TARGET_NAME scribe) -setup_hifi_project() \ No newline at end of file + +setup_memory_debugger() + +setup_hifi_project() diff --git a/tools/vhacd-util/CMakeLists.txt b/tools/vhacd-util/CMakeLists.txt index c94b2ad083..b79a6a1893 100644 --- a/tools/vhacd-util/CMakeLists.txt +++ b/tools/vhacd-util/CMakeLists.txt @@ -8,6 +8,8 @@ find_package(VHACD REQUIRED) target_include_directories(${TARGET_NAME} PUBLIC ${VHACD_INCLUDE_DIRS}) target_link_libraries(${TARGET_NAME} ${VHACD_LIBRARIES}) +setup_memory_debugger() + if (UNIX AND NOT APPLE) include(FindOpenMP) if(OPENMP_FOUND) From 0ac885da80ab10197608c5c7f902d6259deffc63 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 20 Aug 2015 10:17:13 -0700 Subject: [PATCH 088/102] fix when memory debugging message is printed --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index bc4c938f08..b2f35b1443 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -215,6 +215,9 @@ if (ANDROID OR DESKTOP_GVR) endif () if (DEFINED ENV{HIFI_MEMORY_DEBUGGING}) + SET( HIFI_MEMORY_DEBUGGING true ) +endif () +if (HIFI_MEMORY_DEBUGGING) if (UNIX) MESSAGE("-- Memory debugging is enabled") endif (UNIX) From f8344183846c6e1a17b57d004f8af86fa0e94309 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 20 Aug 2015 11:23:16 -0700 Subject: [PATCH 089/102] Fix edit.js to warn when creating entities outside of world bounds --- examples/edit.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index deda035d5e..988e0a04b1 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -1036,7 +1036,6 @@ function handeMenuEvent(menuItem) { // This function tries to find a reasonable position to place a new entity based on the camera // position. If a reasonable position within the world bounds can't be found, `null` will // be returned. The returned position will also take into account grid snapping settings. -// FIXME - technically we should guard against very large positions too function getPositionToCreateEntity() { var distance = cameraManager.enabled ? cameraManager.zoomDistance : DEFAULT_ENTITY_DRAG_DROP_DISTANCE; var direction = Quat.getFront(Camera.orientation); @@ -1047,18 +1046,20 @@ function getPositionToCreateEntity() { var HALF_TREE_SCALE = 16384; - var cameraOutOfBounds = cameraPosition.x < -HALF_TREE_SCALE || cameraPosition.y < -HALF_TREE_SCALE || - cameraPosition.z < -HALF_TREE_SCALE; - var placementOutOfBounds = placementPosition.x < -HALF_TREE_SCALE || placementPosition.y < -HALF_TREE_SCALE || - placementPosition.z < -HALF_TREE_SCALE; + var cameraOutOfBounds = Math.abs(cameraPosition.x) > HALF_TREE_SCALE + || Math.abs(cameraPosition.y) > HALF_TREE_SCALE + || Math.abs(cameraPosition.z) > HALF_TREE_SCALE; + var placementOutOfBounds = Math.abs(placementPosition.x) > HALF_TREE_SCALE + || Math.abs(placementPosition.y) > HALF_TREE_SCALE + || Math.abs(placementPosition.z) > HALF_TREE_SCALE; if (cameraOutOfBounds && placementOutOfBounds) { return null; } - placementPosition.x = Math.max(-HALF_TREE_SCALE, placementPosition.x); - placementPosition.y = Math.max(-HALF_TREE_SCALE, placementPosition.y); - placementPosition.z = Math.max(-HALF_TREE_SCALE, placementPosition.z); + placementPosition.x = Math.min(HALF_TREE_SCALE, Math.max(-HALF_TREE_SCALE, placementPosition.x)); + placementPosition.y = Math.min(HALF_TREE_SCALE, Math.max(-HALF_TREE_SCALE, placementPosition.y)); + placementPosition.z = Math.min(HALF_TREE_SCALE, Math.max(-HALF_TREE_SCALE, placementPosition.z)); return placementPosition; } From e93b360908141742750fe10a231bc41e6132effa Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 20 Aug 2015 12:12:43 -0700 Subject: [PATCH 090/102] expose options property to AI script interface --- libraries/audio/src/AudioInjector.cpp | 30 +++++++++---------- libraries/audio/src/AudioInjector.h | 9 +++--- libraries/avatars/src/Player.cpp | 2 +- .../script-engine/src/ScriptAudioInjector.h | 6 ++-- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 22d57176a5..8fd7cb9ce5 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -77,9 +77,9 @@ void AudioInjector::injectAudio() { int byteOffset = (int) floorf(AudioConstants::SAMPLE_RATE * _options.secondOffset * (_options.stereo ? 2.0f : 1.0f)); byteOffset *= sizeof(int16_t); - _currentSendPosition = byteOffset; + _currentSendOffset = byteOffset; } else { - _currentSendPosition = 0; + _currentSendOffset = 0; } if (_options.localOnly) { @@ -119,7 +119,7 @@ void AudioInjector::injectLocally() { _localBuffer->setVolume(_options.volume); // give our current send position to the local buffer - _localBuffer->setCurrentOffset(_currentSendPosition); + _localBuffer->setCurrentOffset(_currentSendOffset); success = _localAudioInterface->outputLocalInjector(_options.stereo, this); @@ -144,9 +144,9 @@ void AudioInjector::injectLocally() { const uchar MAX_INJECTOR_VOLUME = 0xFF; void AudioInjector::injectToMixer() { - if (_currentSendPosition < 0 || - _currentSendPosition >= _audioData.size()) { - _currentSendPosition = 0; + if (_currentSendOffset < 0 || + _currentSendOffset >= _audioData.size()) { + _currentSendOffset = 0; } auto nodeList = DependencyManager::get(); @@ -203,15 +203,15 @@ void AudioInjector::injectToMixer() { // loop to send off our audio in NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL byte chunks quint16 outgoingInjectedAudioSequenceNumber = 0; - while (_currentSendPosition < _audioData.size() && !_shouldStop) { + while (_currentSendOffset < _audioData.size() && !_shouldStop) { int bytesToCopy = std::min(((_options.stereo) ? 2 : 1) * AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL, - _audioData.size() - _currentSendPosition); + _audioData.size() - _currentSendOffset); // Measure the loudness of this frame _loudness = 0.0f; for (int i = 0; i < bytesToCopy; i += sizeof(int16_t)) { - _loudness += abs(*reinterpret_cast(_audioData.data() + _currentSendPosition + i)) / + _loudness += abs(*reinterpret_cast(_audioData.data() + _currentSendOffset + i)) / (AudioConstants::MAX_SAMPLE_VALUE / 2.0f); } _loudness /= (float)(bytesToCopy / sizeof(int16_t)); @@ -220,7 +220,7 @@ void AudioInjector::injectToMixer() { // pack the sequence number audioPacket->writePrimitive(outgoingInjectedAudioSequenceNumber); - + audioPacket->seek(positionOptionOffset); audioPacket->writePrimitive(_options.position); audioPacket->writePrimitive(_options.orientation); @@ -232,7 +232,7 @@ void AudioInjector::injectToMixer() { audioPacket->seek(audioDataOffset); // copy the next NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL bytes to the packet - audioPacket->write(_audioData.data() + _currentSendPosition, bytesToCopy); + audioPacket->write(_audioData.data() + _currentSendOffset, bytesToCopy); // set the correct size used for this packet audioPacket->setPayloadSize(audioPacket->pos()); @@ -246,11 +246,11 @@ void AudioInjector::injectToMixer() { outgoingInjectedAudioSequenceNumber++; } - _currentSendPosition += bytesToCopy; + _currentSendOffset += bytesToCopy; // send two packets before the first sleep so the mixer can start playback right away - if (_currentSendPosition != bytesToCopy && _currentSendPosition < _audioData.size()) { + if (_currentSendOffset != bytesToCopy && _currentSendOffset < _audioData.size()) { // process events in case we have been told to stop and be deleted QCoreApplication::processEvents(); @@ -268,8 +268,8 @@ void AudioInjector::injectToMixer() { } } - if (shouldLoop && _currentSendPosition >= _audioData.size()) { - _currentSendPosition = 0; + if (shouldLoop && _currentSendOffset >= _audioData.size()) { + _currentSendOffset = 0; } } } diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 88d3f1e151..d65925b865 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -31,7 +31,6 @@ class AbstractAudioInterface; class AudioInjector : public QObject { Q_OBJECT - Q_PROPERTY(AudioInjectorOptions options WRITE setOptions READ getOptions) public: AudioInjector(QObject* parent); AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions); @@ -39,7 +38,8 @@ public: bool isFinished() const { return _isFinished; } - int getCurrentSendPosition() const { return _currentSendPosition; } + int getCurrentSendOffset() const { return _currentSendOffset; } + void setCurrentSendOffset(int currentSendOffset) { _currentSendOffset = currentSendOffset; } AudioInjectorLocalBuffer* getLocalBuffer() const { return _localBuffer; } bool isLocalOnly() const { return _options.localOnly; } @@ -58,9 +58,8 @@ public slots: void stopAndDeleteLater(); const AudioInjectorOptions& getOptions() const { return _options; } - void setOptions(const AudioInjectorOptions& options) { _options = options; } + void setOptions(const AudioInjectorOptions& options) { _options = options; } - void setCurrentSendPosition(int currentSendPosition) { _currentSendPosition = currentSendPosition; } float getLoudness() const { return _loudness; } bool isPlaying() const { return _isPlaying; } void restartPortionAfterFinished(); @@ -82,7 +81,7 @@ private: bool _isStarted = false; bool _isFinished = false; bool _shouldDeleteAfterFinish = false; - int _currentSendPosition = 0; + int _currentSendOffset = 0; AbstractAudioInterface* _localAudioInterface = NULL; AudioInjectorLocalBuffer* _localBuffer = NULL; }; diff --git a/libraries/avatars/src/Player.cpp b/libraries/avatars/src/Player.cpp index e7d94f0735..29544924b2 100644 --- a/libraries/avatars/src/Player.cpp +++ b/libraries/avatars/src/Player.cpp @@ -371,7 +371,7 @@ void Player::setAudioInjectorPosition() { int MSEC_PER_SEC = 1000; int FRAME_SIZE = sizeof(AudioConstants::AudioSample) * _recording->numberAudioChannel(); int currentAudioFrame = elapsed() * FRAME_SIZE * (AudioConstants::SAMPLE_RATE / MSEC_PER_SEC); - _injector->setCurrentSendPosition(currentAudioFrame); + _injector->setCurrentSendOffset(currentAudioFrame); } void Player::setPlayFromCurrentLocation(bool playFromCurrentLocation) { diff --git a/libraries/script-engine/src/ScriptAudioInjector.h b/libraries/script-engine/src/ScriptAudioInjector.h index 92bc5d31da..0d16b26fdf 100644 --- a/libraries/script-engine/src/ScriptAudioInjector.h +++ b/libraries/script-engine/src/ScriptAudioInjector.h @@ -21,13 +21,15 @@ class ScriptAudioInjector : public QObject { Q_PROPERTY(bool isPlaying READ isPlaying) Q_PROPERTY(float loudness READ getLoudness) + Q_PROPERTY(AudioInjectorOptions options WRITE setOptions READ getOptions) public: ScriptAudioInjector(AudioInjector* injector); ~ScriptAudioInjector(); public slots: void restart() { _injector->restart(); } void stop() { _injector->stop(); } - + + const AudioInjectorOptions& getOptions() const { return _injector->getOptions(); } void setOptions(const AudioInjectorOptions& options) { _injector->setOptions(options); } float getLoudness() const { return _injector->getLoudness(); } @@ -49,4 +51,4 @@ Q_DECLARE_METATYPE(ScriptAudioInjector*) QScriptValue injectorToScriptValue(QScriptEngine* engine, ScriptAudioInjector* const& in); void injectorFromScriptValue(const QScriptValue& object, ScriptAudioInjector*& out); -#endif // hifi_ScriptAudioInjector_h \ No newline at end of file +#endif // hifi_ScriptAudioInjector_h From f26849c7e15a25b836308f9c3a613e43ef48eded Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 20 Aug 2015 12:34:50 -0700 Subject: [PATCH 091/102] Proper HMD scaling. --- interface/src/avatar/MyAvatar.cpp | 40 +++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 52473a6d47..cd968c3d59 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -846,7 +846,7 @@ void MyAvatar::sendKillAvatar() { void MyAvatar::updateLookAtTargetAvatar() { // // Look at the avatar whose eyes are closest to the ray in direction of my avatar's head - // + // And set the correctedLookAt for all (nearby) avatars that are looking at me. _lookAtTargetAvatar.reset(); _targetAvatarPosition = glm::vec3(0.0f); @@ -870,14 +870,39 @@ void MyAvatar::updateLookAtTargetAvatar() { smallestAngleTo = angleTo; } if (Application::getInstance()->isLookingAtMyAvatar(avatar)) { + // Alter their gaze to look directly at my camera; this looks more natural than looking at my avatar's face. // Offset their gaze according to whether they're looking at one of my eyes or my mouth. - glm::vec3 gazeOffset = avatar->getHead()->getLookAtPosition() - getHead()->getEyePosition(); - const float HUMAN_EYE_SEPARATION = 0.065f; - float myEyeSeparation = glm::length(getHead()->getLeftEyePosition() - getHead()->getRightEyePosition()); - gazeOffset = gazeOffset * HUMAN_EYE_SEPARATION / myEyeSeparation; - avatar->getHead()->setCorrectedLookAtPosition(Application::getInstance()->getViewFrustum()->getPosition() - + gazeOffset); + + // The camera isn't at the point midway between the avatar eyes. (Even without an HMD, the head can be offset a bit.) + // First find out where (in world space) the person is looking relative to that bridge-of-the-avatar point. + // (We will be adding that offset to the camera position, after making some other adjustments.) + glm::vec3 lookAtPosition = avatar->getHead()->getLookAtPosition(); + glm::vec3 gazeOffset = lookAtPosition - getHead()->getEyePosition(); + + // Scale by proportional differences between avatar and human. + glm::mat4 leftEye = Application::getInstance()->getEyeOffset(Eye::Left); // Pose? + glm::mat4 rightEye = Application::getInstance()->getEyeOffset(Eye::Right); + glm::vec3 leftEyePosition = glm::vec3(leftEye[3]); + glm::vec3 rightEyePosition = glm::vec3(rightEye[3]); + float humanEyeSeparationInModelSpace = glm::length(leftEyePosition - rightEyePosition); + float avatarEyeSeparation = glm::length(getHead()->getLeftEyePosition() - getHead()->getRightEyePosition()); + gazeOffset = gazeOffset * humanEyeSeparationInModelSpace / avatarEyeSeparation; + + // If the camera is also not oriented with the head, adjust by getting the offset in head-space... + /* Not needed (i.e., code is a no-op), but I'm leaving the example code here in case something like this is needed someday. + glm::quat avatarHeadOrientation = getHead()->getOrientation(); + glm::vec3 gazeOffsetLocalToHead = glm::inverse(avatarHeadOrientation) * gazeOffset; + // ... and treat that as though it were in camera space, bringing it back to world space. + // But camera is fudged to make the picture feel like the avatar's orientation. + glm::quat humanOrientation = Application::getInstance()->getViewFrustum()->getOrientation(); // or just avatar getOrienation() ? + gazeOffset = humanOrientation * gazeOffsetLocalToHead; + */ + + // And now we can finally add that offset to the camera. + glm::vec3 corrected = Application::getInstance()->getViewFrustum()->getPosition() + gazeOffset; + avatar->getHead()->setCorrectedLookAtPosition(corrected); + } else { avatar->getHead()->clearCorrectedLookAtPosition(); } @@ -1114,6 +1139,7 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, fl getHead()->render(renderArgs, 1.0f, renderFrustum); } + // This is drawing the lookat vectors from our avatar to wherever we're looking. if (qApp->isHMDMode()) { glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition(); From e9b3d481650e7fdfa1baa6044b07677fc22aba0b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 20 Aug 2015 16:10:31 -0700 Subject: [PATCH 092/102] Add menu item that disables adjusting eyelids to follow pupil Developer > Avatar > Disable Eyelid Adjustment --- interface/src/Menu.cpp | 1 + interface/src/Menu.h | 1 + interface/src/avatar/Head.cpp | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index f074dc5ac7..11bc38c85e 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -444,6 +444,7 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderFocusIndicator, 0, false); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ShowWhosLookingAtMe, 0, false); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::FixGaze, 0, false); + addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::DisableEyelidAdjustment, 0, false); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::Connexion, 0, false, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index ca46b80f92..278da363d1 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -168,6 +168,7 @@ namespace MenuOption { const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DeleteBookmark = "Delete Bookmark..."; const QString DisableActivityLogger = "Disable Activity Logger"; + const QString DisableEyelidAdjustment = "Disable Eyelid Adjustment"; const QString DisableLightEntities = "Disable Light Entities"; const QString DisableNackPackets = "Disable Entity NACK Packets"; const QString DiskCacheEditor = "Disk Cache Editor"; diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 9ab2c83a79..d645253eab 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -277,6 +277,10 @@ void Head::calculateMouthShapes() { void Head::applyEyelidOffset(glm::quat headOrientation) { // Adjusts the eyelid blendshape coefficients so that the eyelid follows the iris as the head pitches. + if (Menu::getInstance()->isOptionChecked(MenuOption::DisableEyelidAdjustment)) { + return; + } + glm::quat eyeRotation = rotationBetween(headOrientation * IDENTITY_FRONT, getLookAtPosition() - _eyePosition); eyeRotation = eyeRotation * glm::angleAxis(safeEulerAngles(headOrientation).y, IDENTITY_UP); // Rotation w.r.t. head float eyePitch = safeEulerAngles(eyeRotation).x; From 05f4145acb97974b8fb40a85ac28e2a333b647c0 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 20 Aug 2015 16:28:40 -0700 Subject: [PATCH 093/102] Checkpoint. Working? --- interface/src/avatar/MyAvatar.cpp | 54 ++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index cd968c3d59..1b8a3b2f89 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -843,6 +843,7 @@ void MyAvatar::sendKillAvatar() { DependencyManager::get()->broadcastToNodes(std::move(killPacket), NodeSet() << NodeType::AvatarMixer); } +static int counter = 0; void MyAvatar::updateLookAtTargetAvatar() { // // Look at the avatar whose eyes are closest to the ray in direction of my avatar's head @@ -872,21 +873,34 @@ void MyAvatar::updateLookAtTargetAvatar() { if (Application::getInstance()->isLookingAtMyAvatar(avatar)) { // Alter their gaze to look directly at my camera; this looks more natural than looking at my avatar's face. - // Offset their gaze according to whether they're looking at one of my eyes or my mouth. + glm::vec3 lookAtPosition = avatar->getHead()->getLookAtPosition(); // A position, in world space, on my avatar. // The camera isn't at the point midway between the avatar eyes. (Even without an HMD, the head can be offset a bit.) + // Let's get everything to world space: + glm::vec3 avatarLeftEye = getHead()->getLeftEyePosition(); + glm::vec3 avatarRightEye = getHead()->getRightEyePosition(); + // When not in HMD, these might both answer identity (i.e., the bridge of the nose). That's ok. + // By my inpsection of the code and live testing, getEyeOffset and getEyePose are the same. (Application hands identity as offset matrix.) + glm::mat4 leftEye = Application::getInstance()->getEyeOffset(Eye::Left); + glm::mat4 rightEye = Application::getInstance()->getEyeOffset(Eye::Right); + glm::vec3 leftEyeHeadLocal = glm::vec3(leftEye[3]); + glm::vec3 rightEyeHeadLocal = glm::vec3(rightEye[3]); + auto humanSystem = Application::getInstance()->getViewFrustum(); + glm::vec3 humanLeftEye = humanSystem->getPosition() + (humanSystem->getOrientation() * leftEyeHeadLocal); + glm::vec3 humanRightEye = humanSystem->getPosition() + (humanSystem->getOrientation() * rightEyeHeadLocal); + + // debugging or some code paths + glm::vec3 avatarAverage = avatarLeftEye + ((avatarRightEye - avatarLeftEye) * 0.5f); + glm::vec3 humanAverage = humanLeftEye + ((humanRightEye - humanLeftEye) * 0.5f); + +#if 1 // First find out where (in world space) the person is looking relative to that bridge-of-the-avatar point. // (We will be adding that offset to the camera position, after making some other adjustments.) - glm::vec3 lookAtPosition = avatar->getHead()->getLookAtPosition(); glm::vec3 gazeOffset = lookAtPosition - getHead()->getEyePosition(); // Scale by proportional differences between avatar and human. - glm::mat4 leftEye = Application::getInstance()->getEyeOffset(Eye::Left); // Pose? - glm::mat4 rightEye = Application::getInstance()->getEyeOffset(Eye::Right); - glm::vec3 leftEyePosition = glm::vec3(leftEye[3]); - glm::vec3 rightEyePosition = glm::vec3(rightEye[3]); - float humanEyeSeparationInModelSpace = glm::length(leftEyePosition - rightEyePosition); - float avatarEyeSeparation = glm::length(getHead()->getLeftEyePosition() - getHead()->getRightEyePosition()); + float humanEyeSeparationInModelSpace = glm::length(humanLeftEye - humanRightEye); + float avatarEyeSeparation = glm::length(avatarLeftEye - avatarRightEye); gazeOffset = gazeOffset * humanEyeSeparationInModelSpace / avatarEyeSeparation; // If the camera is also not oriented with the head, adjust by getting the offset in head-space... @@ -895,13 +909,30 @@ void MyAvatar::updateLookAtTargetAvatar() { glm::vec3 gazeOffsetLocalToHead = glm::inverse(avatarHeadOrientation) * gazeOffset; // ... and treat that as though it were in camera space, bringing it back to world space. // But camera is fudged to make the picture feel like the avatar's orientation. - glm::quat humanOrientation = Application::getInstance()->getViewFrustum()->getOrientation(); // or just avatar getOrienation() ? + glm::quat humanOrientation = humanSystem->getOrientation(); // or just avatar getOrienation() ? gazeOffset = humanOrientation * gazeOffsetLocalToHead; - */ + glm::vec3 corrected = humanSystem->getPosition() + gazeOffset; + */ // And now we can finally add that offset to the camera. glm::vec3 corrected = Application::getInstance()->getViewFrustum()->getPosition() + gazeOffset; +#else + //glm::vec3 gazeOffset = ((humanRightEye - avatarRightEye) + (humanLeftEye - avatarLeftEye)) * 0.5f; + glm::vec3 gazeOffset = humanAverage - avatarAverage; + glm::vec3 corrected = lookAtPosition + gazeOffset; +#endif avatar->getHead()->setCorrectedLookAtPosition(corrected); + + if (counter++ > 60) { + counter = 0; + qCDebug(interfaceapp) << Application::getInstance()->isHMDMode(); + qCDebug(interfaceapp) << "camera:" << Application::getInstance()->getViewFrustum()->getPosition() << "delta from av human:" << (humanAverage - Application::getInstance()->getViewFrustum()->getPosition()); + + qCDebug(interfaceapp) << "lt avatar:" << avatarLeftEye << " lt human:" << humanLeftEye; + qCDebug(interfaceapp) << "rt avatar:" << avatarRightEye << " rt human:" << humanRightEye; + qCDebug(interfaceapp) << "av avatar:" << avatarAverage << " av humn:" << humanAverage; + qCDebug(interfaceapp) << "offset:" << gazeOffset << " corrected:" << corrected << " from:" << lookAtPosition; + } } else { avatar->getHead()->clearCorrectedLookAtPosition(); @@ -1140,6 +1171,7 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, fl } // This is drawing the lookat vectors from our avatar to wherever we're looking. + /* if (qApp->isHMDMode()) { glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition(); @@ -1155,7 +1187,7 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, fl cameraPosition + getOrientation() * (rightEyePosition - headPosition)); } else { getHead()->renderLookAts(renderArgs); - } + }*/ getHand()->render(renderArgs, true); } From ea02583875178380c429046fd5e8ef3fcfb8258a Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 20 Aug 2015 17:33:10 -0700 Subject: [PATCH 094/102] Cleanup. --- interface/src/avatar/MyAvatar.cpp | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 1b8a3b2f89..501c7eb8d5 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -881,6 +881,7 @@ void MyAvatar::updateLookAtTargetAvatar() { glm::vec3 avatarRightEye = getHead()->getRightEyePosition(); // When not in HMD, these might both answer identity (i.e., the bridge of the nose). That's ok. // By my inpsection of the code and live testing, getEyeOffset and getEyePose are the same. (Application hands identity as offset matrix.) + // This might be more work than needed for any given use, but as we explore different formulations, we go mad if we don't work in world space. glm::mat4 leftEye = Application::getInstance()->getEyeOffset(Eye::Left); glm::mat4 rightEye = Application::getInstance()->getEyeOffset(Eye::Right); glm::vec3 leftEyeHeadLocal = glm::vec3(leftEye[3]); @@ -888,12 +889,8 @@ void MyAvatar::updateLookAtTargetAvatar() { auto humanSystem = Application::getInstance()->getViewFrustum(); glm::vec3 humanLeftEye = humanSystem->getPosition() + (humanSystem->getOrientation() * leftEyeHeadLocal); glm::vec3 humanRightEye = humanSystem->getPosition() + (humanSystem->getOrientation() * rightEyeHeadLocal); - - // debugging or some code paths - glm::vec3 avatarAverage = avatarLeftEye + ((avatarRightEye - avatarLeftEye) * 0.5f); - glm::vec3 humanAverage = humanLeftEye + ((humanRightEye - humanLeftEye) * 0.5f); -#if 1 + // First find out where (in world space) the person is looking relative to that bridge-of-the-avatar point. // (We will be adding that offset to the camera position, after making some other adjustments.) glm::vec3 gazeOffset = lookAtPosition - getHead()->getEyePosition(); @@ -916,23 +913,8 @@ void MyAvatar::updateLookAtTargetAvatar() { // And now we can finally add that offset to the camera. glm::vec3 corrected = Application::getInstance()->getViewFrustum()->getPosition() + gazeOffset; -#else - //glm::vec3 gazeOffset = ((humanRightEye - avatarRightEye) + (humanLeftEye - avatarLeftEye)) * 0.5f; - glm::vec3 gazeOffset = humanAverage - avatarAverage; - glm::vec3 corrected = lookAtPosition + gazeOffset; -#endif + avatar->getHead()->setCorrectedLookAtPosition(corrected); - - if (counter++ > 60) { - counter = 0; - qCDebug(interfaceapp) << Application::getInstance()->isHMDMode(); - qCDebug(interfaceapp) << "camera:" << Application::getInstance()->getViewFrustum()->getPosition() << "delta from av human:" << (humanAverage - Application::getInstance()->getViewFrustum()->getPosition()); - - qCDebug(interfaceapp) << "lt avatar:" << avatarLeftEye << " lt human:" << humanLeftEye; - qCDebug(interfaceapp) << "rt avatar:" << avatarRightEye << " rt human:" << humanRightEye; - qCDebug(interfaceapp) << "av avatar:" << avatarAverage << " av humn:" << humanAverage; - qCDebug(interfaceapp) << "offset:" << gazeOffset << " corrected:" << corrected << " from:" << lookAtPosition; - } } else { avatar->getHead()->clearCorrectedLookAtPosition(); From 642e56903329bbbe3c70d0795f40a2fc3f7913f7 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 20 Aug 2015 17:38:49 -0700 Subject: [PATCH 095/102] Uncomment code that was commented out to simplify debugging. --- interface/src/avatar/MyAvatar.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 501c7eb8d5..eada41eb29 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1153,7 +1153,6 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, fl } // This is drawing the lookat vectors from our avatar to wherever we're looking. - /* if (qApp->isHMDMode()) { glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition(); @@ -1169,7 +1168,7 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, fl cameraPosition + getOrientation() * (rightEyePosition - headPosition)); } else { getHead()->renderLookAts(renderArgs); - }*/ + } getHand()->render(renderArgs, true); } From 1b3d7fabc8a4ac6021441d671d249885ee4c741d Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 7 Aug 2015 17:58:43 -0700 Subject: [PATCH 096/102] ResourceCache, NetworkGeometry and Model refactoring and optimizations. * Removed validation logic from Resource class, Qt does this internally and is more standards compliant. This should result in more accurate caching and faster resource fetching when cache is stale and validation fails. * Added loaded and failed slots to Resource class, so it does not have to be polled. * NetworkGeometry now uses multiple Resource objects to download the fst/mapping file and the fbx/obj models. * NetworkGeometry is no longer a subclass of Resource * NetworkGeometry now has signals for success and failure, you no longer have to poll it to determine when loading is complete (except for textures *sigh*) Some functionality was removed * NetworkGeometry no longer has a fallback * NetworkGeometry no longer loads LODs or has lod logic. * The number of FBXGeometry copies is greatly reduced. * Model::setURL no supports fallback URL, delayLoad or retainCurrent option. This can result in a pop when switching avatars, and there's no longer a default if avatar loading fails. --- interface/src/ModelPackager.cpp | 11 +- interface/src/ModelPackager.h | 4 +- interface/src/avatar/Avatar.cpp | 24 +- interface/src/avatar/Head.cpp | 3 - libraries/animation/src/AnimationCache.cpp | 17 +- libraries/animation/src/AnimationCache.h | 9 +- .../src/RenderableZoneEntityItem.cpp | 4 +- libraries/fbx/src/FBXReader.cpp | 22 +- libraries/fbx/src/FBXReader.h | 4 +- libraries/fbx/src/OBJReader.cpp | 9 +- libraries/fbx/src/OBJReader.h | 4 +- libraries/networking/src/ResourceCache.cpp | 115 +-- libraries/networking/src/ResourceCache.h | 17 +- libraries/render-utils/src/GeometryCache.cpp | 806 +++++++----------- libraries/render-utils/src/GeometryCache.h | 145 ++-- libraries/render-utils/src/Model.cpp | 175 +--- libraries/render-utils/src/Model.h | 21 +- tests/networking/src/ResourceTests.cpp | 95 +++ tests/networking/src/ResourceTests.h | 23 + tools/vhacd-util/src/VHACDUtil.cpp | 7 +- 20 files changed, 682 insertions(+), 833 deletions(-) create mode 100644 tests/networking/src/ResourceTests.cpp create mode 100644 tests/networking/src/ResourceTests.h diff --git a/interface/src/ModelPackager.cpp b/interface/src/ModelPackager.cpp index 09d572c31d..0b564f3574 100644 --- a/interface/src/ModelPackager.cpp +++ b/interface/src/ModelPackager.cpp @@ -106,16 +106,17 @@ bool ModelPackager::loadModel() { } qCDebug(interfaceapp) << "Reading FBX file : " << _fbxInfo.filePath(); QByteArray fbxContents = fbx.readAll(); - _geometry = readFBX(fbxContents, QVariantHash(), _fbxInfo.filePath()); - + + _geometry.reset(readFBX(fbxContents, QVariantHash(), _fbxInfo.filePath())); + // make sure we have some basic mappings - populateBasicMapping(_mapping, _fbxInfo.filePath(), _geometry); + populateBasicMapping(_mapping, _fbxInfo.filePath(), *_geometry); return true; } bool ModelPackager::editProperties() { // open the dialog to configure the rest - ModelPropertiesDialog properties(_modelType, _mapping, _modelFile.path(), _geometry); + ModelPropertiesDialog properties(_modelType, _mapping, _modelFile.path(), *_geometry); if (properties.exec() == QDialog::Rejected) { return false; } @@ -339,7 +340,7 @@ void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename void ModelPackager::listTextures() { _textures.clear(); - foreach (FBXMesh mesh, _geometry.meshes) { + foreach (FBXMesh mesh, _geometry->meshes) { foreach (FBXMeshPart part, mesh.parts) { if (!part.diffuseTexture.filename.isEmpty() && part.diffuseTexture.content.isEmpty() && !_textures.contains(part.diffuseTexture.filename)) { diff --git a/interface/src/ModelPackager.h b/interface/src/ModelPackager.h index c681ae436f..10942833f9 100644 --- a/interface/src/ModelPackager.h +++ b/interface/src/ModelPackager.h @@ -39,11 +39,11 @@ private: QString _texDir; QVariantHash _mapping; - FBXGeometry _geometry; + std::unique_ptr _geometry; QStringList _textures; }; -#endif // hifi_ModelPackager_h \ No newline at end of file +#endif // hifi_ModelPackager_h diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index c1a1d11268..19f84018f8 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -196,7 +196,6 @@ void Avatar::simulate(float deltaTime) { PerformanceTimer perfTimer("hand"); getHand()->simulate(deltaTime, false); } - _skeletonModel.setLODDistance(getLODDistance()); if (!_shouldRenderBillboard && inViewFrustum) { { @@ -562,24 +561,22 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { } void Avatar::fixupModelsInScene() { - if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { - return; - } // check to see if when we added our models to the scene they were ready, if they were not ready, then // fix them up in the scene render::ScenePointer scene = Application::getInstance()->getMain3DScene(); render::PendingChanges pendingChanges; - if (_skeletonModel.needsFixupInScene()) { + if (_skeletonModel.isRenderable() && _skeletonModel.needsFixupInScene()) { _skeletonModel.removeFromScene(scene, pendingChanges); _skeletonModel.addToScene(scene, pendingChanges); } - if (getHead()->getFaceModel().needsFixupInScene()) { - getHead()->getFaceModel().removeFromScene(scene, pendingChanges); - getHead()->getFaceModel().addToScene(scene, pendingChanges); + Model& faceModel = getHead()->getFaceModel(); + if (faceModel.isRenderable() && faceModel.needsFixupInScene()) { + faceModel.removeFromScene(scene, pendingChanges); + faceModel.addToScene(scene, pendingChanges); } for (auto attachmentModel : _attachmentModels) { - if (attachmentModel->needsFixupInScene()) { + if (attachmentModel->isRenderable() && attachmentModel->needsFixupInScene()) { attachmentModel->removeFromScene(scene, pendingChanges); attachmentModel->addToScene(scene, pendingChanges); } @@ -621,11 +618,8 @@ void Avatar::simulateAttachments(float deltaTime) { int jointIndex = getJointIndex(attachment.jointName); glm::vec3 jointPosition; glm::quat jointRotation; - if (!isMyAvatar()) { - model->setLODDistance(getLODDistance()); - } if (_skeletonModel.getJointPositionInWorldFrame(jointIndex, jointPosition) && - _skeletonModel.getJointCombinedRotation(jointIndex, jointRotation)) { + _skeletonModel.getJointCombinedRotation(jointIndex, jointRotation)) { model->setTranslation(jointPosition + jointRotation * attachment.translation * _scale); model->setRotation(jointRotation * attachment.rotation); model->setScaleToFit(true, _scale * attachment.scale, true); // hack to force rescale @@ -978,12 +972,12 @@ void Avatar::scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const { void Avatar::setFaceModelURL(const QUrl& faceModelURL) { AvatarData::setFaceModelURL(faceModelURL); - getHead()->getFaceModel().setURL(_faceModelURL, AvatarData::defaultFullAvatarModelUrl(), true, !isMyAvatar()); + getHead()->getFaceModel().setURL(_faceModelURL); } void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { AvatarData::setSkeletonModelURL(skeletonModelURL); - _skeletonModel.setURL(_skeletonModelURL, AvatarData::defaultFullAvatarModelUrl(), true, !isMyAvatar()); + _skeletonModel.setURL(_skeletonModelURL); } void Avatar::setAttachmentData(const QVector& attachmentData) { diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index d645253eab..3806dd6edc 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -233,9 +233,6 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { _saccade = glm::vec3(); } - if (!isMine) { - _faceModel.setLODDistance(static_cast(_owningAvatar)->getLODDistance()); - } _leftEyePosition = _rightEyePosition = getPosition(); if (!billboard) { _faceModel.simulate(deltaTime); diff --git a/libraries/animation/src/AnimationCache.cpp b/libraries/animation/src/AnimationCache.cpp index 634e0589b7..7f3f393a8b 100644 --- a/libraries/animation/src/AnimationCache.cpp +++ b/libraries/animation/src/AnimationCache.cpp @@ -13,6 +13,7 @@ #include #include "AnimationCache.h" +#include "AnimationLogging.h" static int animationPointerMetaTypeId = qRegisterMetaType(); @@ -62,11 +63,15 @@ void AnimationReader::run() { QSharedPointer animation = _animation.toStrongRef(); if (!animation.isNull()) { QMetaObject::invokeMethod(animation.data(), "setGeometry", - Q_ARG(const FBXGeometry&, readFBX(_reply->readAll(), QVariantHash(), _reply->property("url").toString()))); + Q_ARG(FBXGeometry*, readFBX(_reply->readAll(), QVariantHash(), _reply->property("url").toString()))); } _reply->deleteLater(); } +bool Animation::isLoaded() const { + return _loaded && _geometry; +} + QStringList Animation::getJointNames() const { if (QThread::currentThread() != thread()) { QStringList result; @@ -75,7 +80,7 @@ QStringList Animation::getJointNames() const { return result; } QStringList names; - foreach (const FBXJoint& joint, _geometry.joints) { + foreach (const FBXJoint& joint, _geometry->joints) { names.append(joint.name); } return names; @@ -88,15 +93,15 @@ QVector Animation::getFrames() const { Q_RETURN_ARG(QVector, result)); return result; } - return _geometry.animationFrames; + return _geometry->animationFrames; } const QVector& Animation::getFramesReference() const { - return _geometry.animationFrames; + return _geometry->animationFrames; } -void Animation::setGeometry(const FBXGeometry& geometry) { - _geometry = geometry; +void Animation::setGeometry(FBXGeometry* geometry) { + _geometry.reset(geometry); finishedLoading(true); } diff --git a/libraries/animation/src/AnimationCache.h b/libraries/animation/src/AnimationCache.h index 6a0a77f659..3ff5957fa2 100644 --- a/libraries/animation/src/AnimationCache.h +++ b/libraries/animation/src/AnimationCache.h @@ -52,7 +52,10 @@ public: Animation(const QUrl& url); - const FBXGeometry& getGeometry() const { return _geometry; } + const FBXGeometry& getGeometry() const { return *_geometry; } + + virtual bool isLoaded() const override; + Q_INVOKABLE QStringList getJointNames() const; @@ -62,13 +65,13 @@ public: protected: - Q_INVOKABLE void setGeometry(const FBXGeometry& geometry); + Q_INVOKABLE void setGeometry(FBXGeometry* geometry); virtual void downloadFinished(QNetworkReply* reply); private: - FBXGeometry _geometry; + std::unique_ptr _geometry; }; diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index bb0a35f7b0..930a684617 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -38,7 +38,7 @@ void RenderableZoneEntityItem::changeProperties(Lambda setNewProperties) { _model = getModel(); _needsInitialSimulation = true; - _model->setURL(getCompoundShapeURL(), QUrl(), true, true); + _model->setURL(getCompoundShapeURL()); } if (oldPosition != getPosition() || oldRotation != getRotation() || @@ -85,7 +85,7 @@ void RenderableZoneEntityItem::initialSimulation() { void RenderableZoneEntityItem::updateGeometry() { if (_model && !_model->isActive() && hasCompoundShapeURL()) { // Since we have a delayload, we need to update the geometry if it has been downloaded - _model->setURL(getCompoundShapeURL(), QUrl(), true); + _model->setURL(getCompoundShapeURL()); } if (_model && _model->isActive() && _needsInitialSimulation) { initialSimulation(); diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 2db5f5fa51..f0d13f8792 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1373,12 +1373,12 @@ FBXLight extractLight(const FBXNode& object) { #if USE_MODEL_MESH -void buildModelMesh(ExtractedMesh& extracted) { +void buildModelMesh(ExtractedMesh& extracted, const QString& url) { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("buildModelMesh failed -- .*"); if (extracted.mesh.vertices.size() == 0) { extracted.mesh._mesh = model::Mesh(); - qCDebug(modelformat) << "buildModelMesh failed -- no vertices"; + qCDebug(modelformat) << "buildModelMesh failed -- no vertices, url = " << url; return; } FBXMesh& fbxMesh = extracted.mesh; @@ -1465,7 +1465,7 @@ void buildModelMesh(ExtractedMesh& extracted) { if (! totalIndices) { extracted.mesh._mesh = model::Mesh(); - qCDebug(modelformat) << "buildModelMesh failed -- no indices"; + qCDebug(modelformat) << "buildModelMesh failed -- no indices, url = " << url; return; } @@ -1505,7 +1505,7 @@ void buildModelMesh(ExtractedMesh& extracted) { mesh.setPartBuffer(pbv); } else { extracted.mesh._mesh = model::Mesh(); - qCDebug(modelformat) << "buildModelMesh failed -- no parts"; + qCDebug(modelformat) << "buildModelMesh failed -- no parts, url = " << url; return; } @@ -1530,7 +1530,7 @@ QByteArray fileOnUrl(const QByteArray& filenameString, const QString& url) { return filename; } -FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) { +FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) { QHash meshes; QHash modelIDsToNames; QHash meshIDsToMeshIndices; @@ -1615,7 +1615,9 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, #if defined(DEBUG_FBXREADER) int unknown = 0; #endif - FBXGeometry geometry; + FBXGeometry* geometryPtr = new FBXGeometry; + FBXGeometry& geometry = *geometryPtr; + float unitScaleFactor = 1.0f; glm::vec3 ambientColor; QString hifiGlobalNodeID; @@ -2680,7 +2682,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, extracted.mesh.isEye = (maxJointIndex == geometry.leftEyeJointIndex || maxJointIndex == geometry.rightEyeJointIndex); # if USE_MODEL_MESH - buildModelMesh(extracted); + buildModelMesh(extracted, url); # endif if (extracted.mesh.isEye) { @@ -2761,15 +2763,15 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, } } - return geometry; + return geometryPtr; } -FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) { +FBXGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) { QBuffer buffer(const_cast(&model)); buffer.open(QIODevice::ReadOnly); return readFBX(&buffer, mapping, url, loadLightmaps, lightmapLevel); } -FBXGeometry readFBX(QIODevice* device, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) { +FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) { return extractFBXGeometry(parseFBX(device), mapping, url, loadLightmaps, lightmapLevel); } diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index b8a22b0b80..471a9c1777 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -272,10 +272,10 @@ Q_DECLARE_METATYPE(FBXGeometry) /// Reads FBX geometry from the supplied model and mapping data. /// \exception QString if an error occurs in parsing -FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f); +FBXGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f); /// Reads FBX geometry from the supplied model and mapping data. /// \exception QString if an error occurs in parsing -FBXGeometry readFBX(QIODevice* device, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f); +FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f); #endif // hifi_FBXReader_h diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index b7ae948490..841fdcfad9 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -399,15 +399,16 @@ done: } -FBXGeometry OBJReader::readOBJ(const QByteArray& model, const QVariantHash& mapping) { +FBXGeometry* OBJReader::readOBJ(const QByteArray& model, const QVariantHash& mapping) { QBuffer buffer(const_cast(&model)); buffer.open(QIODevice::ReadOnly); return readOBJ(&buffer, mapping, nullptr); } -FBXGeometry OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, QUrl* url) { - FBXGeometry geometry; +FBXGeometry* OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, QUrl* url) { + FBXGeometry* geometryPtr = new FBXGeometry(); + FBXGeometry& geometry = *geometryPtr; OBJTokenizer tokenizer(device); float scaleGuess = 1.0f; @@ -545,7 +546,7 @@ FBXGeometry OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, Q qCDebug(modelformat) << "OBJ reader fail: " << e.what(); } - return geometry; + return geometryPtr; } diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h index 2e7b050b0a..df4c88553e 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJReader.h @@ -71,8 +71,8 @@ public: QHash materials; QNetworkReply* request(QUrl& url, bool isTest); - FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping); - FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping, QUrl* url); + FBXGeometry* readOBJ(const QByteArray& model, const QVariantHash& mapping); + FBXGeometry* readOBJ(QIODevice* device, const QVariantHash& mapping, QUrl* url); private: QUrl* _url = nullptr; diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index e127380630..75028abe93 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -320,7 +320,6 @@ void Resource::attemptRequest() { void Resource::finishedLoading(bool success) { if (success) { _loaded = true; - emit loaded(); } else { _failedToLoad = true; } @@ -333,91 +332,26 @@ void Resource::reinsert() { static const int REPLY_TIMEOUT_MS = 5000; void Resource::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { - if (!_reply->isFinished()) { - _bytesReceived = bytesReceived; - _bytesTotal = bytesTotal; - _replyTimer->start(REPLY_TIMEOUT_MS); - return; - } - _reply->disconnect(this); - _replyTimer->disconnect(this); - QNetworkReply* reply = _reply; - _reply = nullptr; - _replyTimer->deleteLater(); - _replyTimer = nullptr; - ResourceCache::requestCompleted(this); - - downloadFinished(reply); + _bytesReceived = bytesReceived; + _bytesTotal = bytesTotal; + _replyTimer->start(REPLY_TIMEOUT_MS); } void Resource::handleReplyError() { - handleReplyError(_reply->error(), qDebug() << _reply->errorString()); + handleReplyErrorInternal(_reply->error()); } void Resource::handleReplyTimeout() { - handleReplyError(QNetworkReply::TimeoutError, qDebug() << "Timed out loading" << _reply->url() << - "received" << _bytesReceived << "total" << _bytesTotal); -} - -void Resource::maybeRefresh() { - if (Q_LIKELY(NetworkAccessManager::getInstance().cache())) { - QNetworkReply* reply = qobject_cast(sender()); - QVariant variant = reply->header(QNetworkRequest::LastModifiedHeader); - QNetworkCacheMetaData metaData = NetworkAccessManager::getInstance().cache()->metaData(_url); - if (variant.isValid() && variant.canConvert() && metaData.isValid()) { - QDateTime lastModified = variant.value(); - QDateTime lastModifiedOld = metaData.lastModified(); - if (lastModified.isValid() && lastModifiedOld.isValid() && - lastModifiedOld >= lastModified) { // With >=, cache won't thrash in eventually-consistent cdn. - qCDebug(networking) << "Using cached version of" << _url.fileName(); - // We don't need to update, return - return; - } - } else if (!variant.isValid() || !variant.canConvert() || - !variant.value().isValid() || variant.value().isNull()) { - qCDebug(networking) << "Cannot determine when" << _url.fileName() << "was modified last, cached version might be outdated"; - return; - } - qCDebug(networking) << "Loaded" << _url.fileName() << "from the disk cache but the network version is newer, refreshing."; - refresh(); - } + handleReplyErrorInternal(QNetworkReply::TimeoutError); } void Resource::makeRequest() { _reply = NetworkAccessManager::getInstance().get(_request); - + connect(_reply, SIGNAL(downloadProgress(qint64,qint64)), SLOT(handleDownloadProgress(qint64,qint64))); connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(handleReplyError())); connect(_reply, SIGNAL(finished()), SLOT(handleReplyFinished())); - - if (_reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool()) { - // If the file as been updated since it was cached, refresh it - QNetworkRequest request(_request); - request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); - request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false); - QNetworkReply* reply = NetworkAccessManager::getInstance().head(request); - connect(reply, &QNetworkReply::finished, this, &Resource::maybeRefresh); - } else { - if (Q_LIKELY(NetworkAccessManager::getInstance().cache())) { - QNetworkCacheMetaData metaData = NetworkAccessManager::getInstance().cache()->metaData(_url); - bool needUpdate = false; - if (metaData.expirationDate().isNull() || metaData.expirationDate() <= QDateTime::currentDateTime()) { - // If the expiration date is NULL or in the past, - // put one far enough away that it won't be an issue. - metaData.setExpirationDate(QDateTime::currentDateTime().addYears(100)); - needUpdate = true; - } - if (metaData.lastModified().isNull()) { - // If the lastModified date is NULL, set it to now. - metaData.setLastModified(QDateTime::currentDateTime()); - needUpdate = true; - } - if (needUpdate) { - NetworkAccessManager::getInstance().cache()->updateMetaData(metaData); - } - } - } - + _replyTimer = new QTimer(this); connect(_replyTimer, SIGNAL(timeout()), SLOT(handleReplyTimeout())); _replyTimer->setSingleShot(true); @@ -425,7 +359,8 @@ void Resource::makeRequest() { _bytesReceived = _bytesTotal = 0; } -void Resource::handleReplyError(QNetworkReply::NetworkError error, QDebug debug) { +void Resource::handleReplyErrorInternal(QNetworkReply::NetworkError error) { + _reply->disconnect(this); _replyTimer->disconnect(this); _reply->deleteLater(); @@ -433,7 +368,7 @@ void Resource::handleReplyError(QNetworkReply::NetworkError error, QDebug debug) _replyTimer->deleteLater(); _replyTimer = nullptr; ResourceCache::requestCompleted(this); - + // retry for certain types of failures switch (error) { case QNetworkReply::RemoteHostClosedError: @@ -444,26 +379,46 @@ void Resource::handleReplyError(QNetworkReply::NetworkError error, QDebug debug) case QNetworkReply::UnknownNetworkError: case QNetworkReply::UnknownProxyError: case QNetworkReply::UnknownContentError: - case QNetworkReply::ProtocolFailure: { + case QNetworkReply::ProtocolFailure: { // retry with increasing delays const int MAX_ATTEMPTS = 8; const int BASE_DELAY_MS = 1000; if (++_attempts < MAX_ATTEMPTS) { QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, SLOT(attemptRequest())); - debug << "-- retrying..."; + qCWarning(networking) << "error downloading url =" << _url.toDisplayString() << ", error =" << error << ", retrying (" << _attempts << "/" << MAX_ATTEMPTS << ")"; return; } // fall through to final failure - } + } default: + qCCritical(networking) << "error downloading, url =" << _url.toDisplayString() << ", error =" << error; + emit failed(error); finishedLoading(false); break; } } void Resource::handleReplyFinished() { - qCDebug(networking) << "Got finished without download progress/error?" << _url; - handleDownloadProgress(0, 0); + + bool fromCache = _reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(); + qCDebug(networking) << "success downloading url =" << _url.toDisplayString() << (fromCache ? "from cache" : ""); + + _reply->disconnect(this); + _replyTimer->disconnect(this); + QNetworkReply* reply = _reply; + _reply = nullptr; + _replyTimer->deleteLater(); + _replyTimer = nullptr; + ResourceCache::requestCompleted(this); + + finishedLoading(true); + emit loaded(*reply); + downloadFinished(reply); +} + + +void Resource::downloadFinished(QNetworkReply* reply) { + ; } uint qHash(const QPointer& value, uint seed) { diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 93ddfe77be..9a88c434e1 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -150,7 +150,7 @@ public: float getLoadPriority(); /// Checks whether the resource has loaded. - bool isLoaded() const { return _loaded; } + virtual bool isLoaded() const { return _loaded; } /// For loading resources, returns the number of bytes received. qint64 getBytesReceived() const { return _bytesReceived; } @@ -174,21 +174,22 @@ public: signals: /// Fired when the resource has been loaded. - void loaded(); + void loaded(QNetworkReply& request); + + /// Fired when resource failed to load. + void failed(QNetworkReply::NetworkError error); + + /// Fired when resource is refreshed. void onRefresh(); protected slots: void attemptRequest(); - - /// Refreshes the resource if the last modified date on the network - /// is greater than the last modified date in the cache. - void maybeRefresh(); protected: virtual void init(); /// Called when the download has finished. The recipient should delete the reply when done with it. - virtual void downloadFinished(QNetworkReply* reply) = 0; + virtual void downloadFinished(QNetworkReply* reply); /// Should be called by subclasses when all the loading that will be done has been done. Q_INVOKABLE void finishedLoading(bool success); @@ -216,7 +217,7 @@ private: void makeRequest(); - void handleReplyError(QNetworkReply::NetworkError error, QDebug debug); + void handleReplyErrorInternal(QNetworkReply::NetworkError error); friend class ResourceCache; diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 31b030f75a..f48ceb9b62 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include @@ -50,6 +49,13 @@ GeometryCache::~GeometryCache() { #endif //def WANT_DEBUG } +QSharedPointer GeometryCache::createResource(const QUrl& url, const QSharedPointer& fallback, + bool delayLoad, const void* extra) { + // NetworkGeometry is no longer a subclass of Resource, but requires this method because, it is pure virtual. + assert(false); + return QSharedPointer(); +} + const int NUM_VERTICES_PER_TRIANGLE = 3; const int NUM_TRIANGLES_PER_QUAD = 2; const int NUM_VERTICES_PER_TRIANGULATED_QUAD = NUM_VERTICES_PER_TRIANGLE * NUM_TRIANGLES_PER_QUAD; @@ -1643,19 +1649,6 @@ void GeometryCache::renderLine(gpu::Batch& batch, const glm::vec2& p1, const glm batch.draw(gpu::LINES, 2, 0); } - -QSharedPointer GeometryCache::getGeometry(const QUrl& url, const QUrl& fallback, bool delayLoad) { - return getResource(url, fallback, delayLoad, NULL).staticCast(); -} - -QSharedPointer GeometryCache::createResource(const QUrl& url, const QSharedPointer& fallback, - bool delayLoad, const void* extra) { - QSharedPointer geometry(new NetworkGeometry(url, fallback.staticCast(), delayLoad), - &Resource::allReferencesCleared); - geometry->setLODParent(geometry); - return geometry.staticCast(); -} - void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { if (!_standardDrawPipeline) { auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(standardTransformPNTC_vert))); @@ -1685,33 +1678,82 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { } } -const float NetworkGeometry::NO_HYSTERESIS = -1.0f; +GeometryReader::GeometryReader(const QUrl& url, QNetworkReply* reply, const QVariantHash& mapping) : + _url(url), + _reply(reply), + _mapping(mapping) { +} -NetworkGeometry::NetworkGeometry(const QUrl& url, const QSharedPointer& fallback, bool delayLoad, - const QVariantHash& mapping, const QUrl& textureBase) : - Resource(url, delayLoad), - _mapping(mapping), - _textureBase(textureBase.isValid() ? textureBase : url), - _fallback(fallback) -{ - - if (url.isEmpty()) { - // make the minimal amount of dummy geometry to satisfy Model - FBXJoint joint = { false, QVector(), -1, 0.0f, 0.0f, glm::vec3(), glm::mat4(), glm::quat(), glm::quat(), - glm::quat(), glm::mat4(), glm::mat4(), glm::vec3(), glm::vec3(), glm::quat(), glm::quat(), - glm::mat4(), QString(""), false}; - _geometry.joints.append(joint); - _geometry.leftEyeJointIndex = -1; - _geometry.rightEyeJointIndex = -1; - _geometry.neckJointIndex = -1; - _geometry.rootJointIndex = -1; - _geometry.leanJointIndex = -1; - _geometry.headJointIndex = -1; - _geometry.leftHandJointIndex = -1; - _geometry.rightHandJointIndex = -1; +void GeometryReader::run() { + try { + if (!_reply) { + throw QString("Reply is NULL ?!"); + } + QString urlname = _url.path().toLower(); + bool urlValid = true; + urlValid &= !urlname.isEmpty(); + urlValid &= !_url.path().isEmpty(); + urlValid &= _url.path().toLower().endsWith(".fbx") || _url.path().toLower().endsWith(".obj"); + + if (urlValid) { + // Let's read the binaries from the network + FBXGeometry* fbxgeo = nullptr; + if (_url.path().toLower().endsWith(".fbx")) { + const bool grabLightmaps = true; + const float lightmapLevel = 1.0f; + fbxgeo = readFBX(_reply, _mapping, _url.path(), grabLightmaps, lightmapLevel); + } else if (_url.path().toLower().endsWith(".obj")) { + fbxgeo = OBJReader().readOBJ(_reply, _mapping, &_url); + } else { + QString errorStr("usupported format"); + emit onError(NetworkGeometry::ModelParseError, errorStr); + } + emit onSuccess(fbxgeo); + } else { + throw QString("url is invalid"); + } + + } catch (const QString& error) { + qCDebug(renderutils) << "Error reading " << _url << ": " << error; + emit onError(NetworkGeometry::ModelParseError, error); } - - connect(this, &Resource::loaded, this, &NetworkGeometry::replaceTexturesWithPendingChanges); + _reply->deleteLater(); +} + +NetworkGeometry::NetworkGeometry(const QUrl& url, bool delayLoad, const QVariantHash& mapping, const QUrl& textureBaseUrl) : + _url(url), + _mapping(mapping), + _textureBaseUrl(textureBaseUrl) { + + if (delayLoad) { + _state = DelayState; + } else { + attemptRequestInternal(); + } +} + +NetworkGeometry::~NetworkGeometry() { + if (_resource) { + _resource->deleteLater(); + } +} + +void NetworkGeometry::attemptRequest() { + if (_state == DelayState) { + attemptRequestInternal(); + } +} + +void NetworkGeometry::attemptRequestInternal() { + if (_url.path().toLower().endsWith(".fst")) { + requestMapping(_url); + } else { + requestModel(_url); + } +} + +bool NetworkGeometry::isLoaded() const { + return _state == SuccessState; } bool NetworkGeometry::isLoadedWithTextures() const { @@ -1719,12 +1761,12 @@ bool NetworkGeometry::isLoadedWithTextures() const { return false; } if (!_isLoadedWithTextures) { - foreach (const NetworkMesh& mesh, _meshes) { - foreach (const NetworkMeshPart& part, mesh.parts) { - if ((part.diffuseTexture && !part.diffuseTexture->isLoaded()) || - (part.normalTexture && !part.normalTexture->isLoaded()) || - (part.specularTexture && !part.specularTexture->isLoaded()) || - (part.emissiveTexture && !part.emissiveTexture->isLoaded())) { + for (auto&& mesh : _meshes) { + for (auto && part : mesh->_parts) { + if ((part->diffuseTexture && !part->diffuseTexture->isLoaded()) || + (part->normalTexture && !part->normalTexture->isLoaded()) || + (part->specularTexture && !part->specularTexture->isLoaded()) || + (part->emissiveTexture && !part->emissiveTexture->isLoaded())) { return false; } } @@ -1734,183 +1776,38 @@ bool NetworkGeometry::isLoadedWithTextures() const { return true; } -QSharedPointer NetworkGeometry::getLODOrFallback(float distance, float& hysteresis, bool delayLoad) const { - if (_lodParent.data() != this) { - return _lodParent.data()->getLODOrFallback(distance, hysteresis, delayLoad); - } - if (_failedToLoad && _fallback) { - return _fallback; - } - QSharedPointer lod = _lodParent; - float lodDistance = 0.0f; - QMap >::const_iterator it = _lods.upperBound(distance); - if (it != _lods.constBegin()) { - it = it - 1; - lod = it.value(); - lodDistance = it.key(); - } - if (hysteresis != NO_HYSTERESIS && hysteresis != lodDistance) { - // if we previously selected a different distance, make sure we've moved far enough to justify switching - const float HYSTERESIS_PROPORTION = 0.1f; - if (glm::abs(distance - qMax(hysteresis, lodDistance)) / fabsf(hysteresis - lodDistance) < HYSTERESIS_PROPORTION) { - lod = _lodParent; - lodDistance = 0.0f; - it = _lods.upperBound(hysteresis); - if (it != _lods.constBegin()) { - it = it - 1; - lod = it.value(); - lodDistance = it.key(); - } - } - } - if (lod && lod->isLoaded()) { - hysteresis = lodDistance; - return lod; - } - // if the ideal LOD isn't loaded, we need to make sure it's started to load, and possibly return the closest loaded one - if (!delayLoad) { - lod->ensureLoading(); - } - float closestDistance = FLT_MAX; - if (isLoaded()) { - lod = _lodParent; - closestDistance = distance; - } - for (it = _lods.constBegin(); it != _lods.constEnd(); it++) { - float distanceToLOD = glm::abs(distance - it.key()); - if (it.value()->isLoaded() && distanceToLOD < closestDistance) { - lod = it.value(); - closestDistance = distanceToLOD; - } - } - hysteresis = NO_HYSTERESIS; - return lod; -} - -uint qHash(const QWeakPointer& animation, uint seed = 0) { - return qHash(animation.data(), seed); -} - -QVector NetworkGeometry::getJointMappings(const AnimationPointer& animation) { - QVector mappings = _jointMappings.value(animation); - if (mappings.isEmpty() && isLoaded() && animation && animation->isLoaded()) { - const FBXGeometry& animationGeometry = animation->getGeometry(); - for (int i = 0; i < animationGeometry.joints.size(); i++) { - mappings.append(_geometry.jointIndices.value(animationGeometry.joints.at(i).name) - 1); - } - _jointMappings.insert(animation, mappings); - } - return mappings; -} - -void NetworkGeometry::setLoadPriority(const QPointer& owner, float priority) { - Resource::setLoadPriority(owner, priority); - - for (int i = 0; i < _meshes.size(); i++) { - NetworkMesh& mesh = _meshes[i]; - for (int j = 0; j < mesh.parts.size(); j++) { - NetworkMeshPart& part = mesh.parts[j]; - if (part.diffuseTexture) { - part.diffuseTexture->setLoadPriority(owner, priority); - } - if (part.normalTexture) { - part.normalTexture->setLoadPriority(owner, priority); - } - if (part.specularTexture) { - part.specularTexture->setLoadPriority(owner, priority); - } - if (part.emissiveTexture) { - part.emissiveTexture->setLoadPriority(owner, priority); - } - } - } -} - -void NetworkGeometry::setLoadPriorities(const QHash, float>& priorities) { - Resource::setLoadPriorities(priorities); - - for (int i = 0; i < _meshes.size(); i++) { - NetworkMesh& mesh = _meshes[i]; - for (int j = 0; j < mesh.parts.size(); j++) { - NetworkMeshPart& part = mesh.parts[j]; - if (part.diffuseTexture) { - part.diffuseTexture->setLoadPriorities(priorities); - } - if (part.normalTexture) { - part.normalTexture->setLoadPriorities(priorities); - } - if (part.specularTexture) { - part.specularTexture->setLoadPriorities(priorities); - } - if (part.emissiveTexture) { - part.emissiveTexture->setLoadPriorities(priorities); - } - } - } -} - -void NetworkGeometry::clearLoadPriority(const QPointer& owner) { - Resource::clearLoadPriority(owner); - - for (int i = 0; i < _meshes.size(); i++) { - NetworkMesh& mesh = _meshes[i]; - for (int j = 0; j < mesh.parts.size(); j++) { - NetworkMeshPart& part = mesh.parts[j]; - if (part.diffuseTexture) { - part.diffuseTexture->clearLoadPriority(owner); - } - if (part.normalTexture) { - part.normalTexture->clearLoadPriority(owner); - } - if (part.specularTexture) { - part.specularTexture->clearLoadPriority(owner); - } - if (part.emissiveTexture) { - part.emissiveTexture->clearLoadPriority(owner); - } - } - } -} - void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& url) { if (_meshes.size() > 0) { auto textureCache = DependencyManager::get(); - for (int i = 0; i < _meshes.size(); i++) { - NetworkMesh& mesh = _meshes[i]; - for (int j = 0; j < mesh.parts.size(); j++) { - NetworkMeshPart& part = mesh.parts[j]; - + for (size_t i = 0; i < _meshes.size(); i++) { + NetworkMesh& mesh = *(_meshes[i].get()); + for (size_t j = 0; j < mesh._parts.size(); j++) { + NetworkMeshPart& part = *(mesh._parts[j].get()); QSharedPointer matchingTexture = QSharedPointer(); if (part.diffuseTextureName == name) { - part.diffuseTexture = textureCache->getTexture(url, DEFAULT_TEXTURE, _geometry.meshes[i].isEye); - part.diffuseTexture->setLoadPriorities(_loadPriorities); + part.diffuseTexture = textureCache->getTexture(url, DEFAULT_TEXTURE, _geometry->meshes[i].isEye); } else if (part.normalTextureName == name) { part.normalTexture = textureCache->getTexture(url); - part.normalTexture->setLoadPriorities(_loadPriorities); } else if (part.specularTextureName == name) { part.specularTexture = textureCache->getTexture(url); - part.specularTexture->setLoadPriorities(_loadPriorities); } else if (part.emissiveTextureName == name) { part.emissiveTexture = textureCache->getTexture(url); - part.emissiveTexture->setLoadPriorities(_loadPriorities); } } } } else { - qCDebug(renderutils) << "Adding a name url pair to pending" << name << url; - // we don't have meshes downloaded yet, so hold this texture as pending - _pendingTextureChanges.insert(name, url); + qCWarning(renderutils) << "Ignoring setTextureWirthNameToURL() geometry not ready." << name << url; } _isLoadedWithTextures = false; } QStringList NetworkGeometry::getTextureNames() const { QStringList result; - for (int i = 0; i < _meshes.size(); i++) { - const NetworkMesh& mesh = _meshes[i]; - for (int j = 0; j < mesh.parts.size(); j++) { - const NetworkMeshPart& part = mesh.parts[j]; - + for (size_t i = 0; i < _meshes.size(); i++) { + const NetworkMesh& mesh = *(_meshes[i].get()); + for (size_t j = 0; j < mesh._parts.size(); j++) { + const NetworkMeshPart& part = *(mesh._parts[j].get()); + if (!part.diffuseTextureName.isEmpty() && part.diffuseTexture) { QString textureURL = part.diffuseTexture->getURL().toString(); result << part.diffuseTextureName + ":" + textureURL; @@ -1935,320 +1832,259 @@ QStringList NetworkGeometry::getTextureNames() const { return result; } -void NetworkGeometry::replaceTexturesWithPendingChanges() { - QHash::Iterator it = _pendingTextureChanges.begin(); - - while (it != _pendingTextureChanges.end()) { - setTextureWithNameToURL(it.key(), it.value()); - it = _pendingTextureChanges.erase(it); +void NetworkGeometry::requestMapping(const QUrl& url) { + _state = RequestMappingState; + if (_resource) { + _resource->deleteLater(); } + _resource = new Resource(url, false); + connect(_resource, SIGNAL(loaded(QNetworkReply&)), SLOT(mappingRequestDone(QNetworkReply&))); + connect(_resource, SIGNAL(failed(QNetworkReply::NetworkError)), SLOT(mappingRequestError(QNetworkReply::NetworkError))); } -/// Reads geometry in a worker thread. -class GeometryReader : public QRunnable { -public: - - GeometryReader(const QWeakPointer& geometry, const QUrl& url, - QNetworkReply* reply, const QVariantHash& mapping); - - virtual void run(); - -private: - - QWeakPointer _geometry; - QUrl _url; - QNetworkReply* _reply; - QVariantHash _mapping; -}; - -GeometryReader::GeometryReader(const QWeakPointer& geometry, const QUrl& url, - QNetworkReply* reply, const QVariantHash& mapping) : - _geometry(geometry), - _url(url), - _reply(reply), - _mapping(mapping) { +void NetworkGeometry::requestModel(const QUrl& url) { + _state = RequestModelState; + if (_resource) { + _resource->deleteLater(); + } + _resource = new Resource(url, false); + connect(_resource, SIGNAL(loaded(QNetworkReply&)), SLOT(modelRequestDone(QNetworkReply&))); + connect(_resource, SIGNAL(failed(QNetworkReply::NetworkError)), SLOT(modelRequestError(QNetworkReply::NetworkError))); } -void GeometryReader::run() { - QSharedPointer geometry = _geometry.toStrongRef(); - if (geometry.isNull()) { - _reply->deleteLater(); - return; - } - try { - if (!_reply) { - throw QString("Reply is NULL ?!"); - } - QString urlname = _url.path().toLower(); - bool urlValid = true; - urlValid &= !urlname.isEmpty(); - urlValid &= !_url.path().isEmpty(); - urlValid &= _url.path().toLower().endsWith(".fbx") - || _url.path().toLower().endsWith(".obj") - || _url.path().toLower().endsWith(".svo"); +void NetworkGeometry::mappingRequestDone(QNetworkReply& reply) { + assert(_state == RequestMappingState); - if (urlValid) { - // Let's read the binaries from the network - FBXGeometry fbxgeo; - if (_url.path().toLower().endsWith(".fbx")) { - bool grabLightmaps = true; - float lightmapLevel = 1.0f; - // HACK: For monday 12/01/2014 we need to kill lighmaps loading in starchamber... - if (_url.path().toLower().endsWith("loungev4_11-18.fbx")) { - grabLightmaps = false; - } else if (_url.path().toLower().endsWith("apt8_reboot.fbx")) { - lightmapLevel = 4.0f; - } else if (_url.path().toLower().endsWith("palaceoforinthilian4.fbx")) { - lightmapLevel = 3.5f; - } - fbxgeo = readFBX(_reply, _mapping, _url.path(), grabLightmaps, lightmapLevel); - } else if (_url.path().toLower().endsWith(".obj")) { - fbxgeo = OBJReader().readOBJ(_reply, _mapping, &_url); + // parse the mapping file + _mapping = FSTReader::readMapping(reply.readAll()); + + QUrl replyUrl = reply.url(); + QString modelUrlStr = _mapping.value("filename").toString(); + if (modelUrlStr.isNull()) { + qCDebug(renderutils) << "Mapping file " << _url << "has no \"filename\" entry"; + emit onFailure(*this, MissingFilenameInMapping); + } else { + // read _textureBase from mapping file, if present + QString texdir = _mapping.value("texdir").toString(); + if (!texdir.isNull()) { + if (!texdir.endsWith('/')) { + texdir += '/'; } - QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&, fbxgeo)); - } else { - throw QString("url is invalid"); + _textureBaseUrl = replyUrl.resolved(texdir); } - } catch (const QString& error) { - qCDebug(renderutils) << "Error reading " << _url << ": " << error; - QMetaObject::invokeMethod(geometry.data(), "finishedLoading", Q_ARG(bool, false)); - } - _reply->deleteLater(); -} - -void NetworkGeometry::init() { - _mapping = QVariantHash(); - _geometry = FBXGeometry(); - _meshes.clear(); - _lods.clear(); - _pendingTextureChanges.clear(); - _request.setUrl(_url); - Resource::init(); -} - -void NetworkGeometry::downloadFinished(QNetworkReply* reply) { - QUrl url = reply->url(); - if (url.path().toLower().endsWith(".fst")) { - // it's a mapping file; parse it and get the mesh filename - _mapping = FSTReader::readMapping(reply->readAll()); - reply->deleteLater(); - QString filename = _mapping.value("filename").toString(); - if (filename.isNull()) { - qCDebug(renderutils) << "Mapping file " << url << " has no filename."; - finishedLoading(false); - - } else { - QString texdir = _mapping.value("texdir").toString(); - if (!texdir.isNull()) { - if (!texdir.endsWith('/')) { - texdir += '/'; - } - _textureBase = url.resolved(texdir); - } - QVariantHash lods = _mapping.value("lod").toHash(); - for (QVariantHash::const_iterator it = lods.begin(); it != lods.end(); it++) { - auto geometry = QSharedPointer::create(url.resolved(it.key()), - QSharedPointer(), true, _mapping, _textureBase); - geometry->setSelf(geometry.staticCast()); - geometry->setLODParent(_lodParent); - _lods.insert(it.value().toFloat(), geometry); - } - _request.setUrl(url.resolved(filename)); - - // make the request immediately only if we have no LODs to switch between - _startedLoading = false; - if (_lods.isEmpty()) { - attemptRequest(); - } - } - return; - } - - // send the reader off to the thread pool - QThreadPool::globalInstance()->start(new GeometryReader(_self, url, reply, _mapping)); -} - -void NetworkGeometry::reinsert() { - Resource::reinsert(); - - _lodParent = qWeakPointerCast(_self); - foreach (const QSharedPointer& lod, _lods) { - lod->setLODParent(_lodParent); + QUrl modelUrl = replyUrl.resolved(modelUrlStr); + requestModel(modelUrl); } } -void NetworkGeometry::setGeometry(const FBXGeometry& geometry) { - _geometry = geometry; +void NetworkGeometry::mappingRequestError(QNetworkReply::NetworkError error) { + assert(_state == RequestMappingState); + _state = ErrorState; + emit onFailure(*this, MappingRequestError); +} +void NetworkGeometry::modelRequestDone(QNetworkReply& reply) { + assert(_state == RequestModelState); + + _state = ParsingModelState; + + // asynchronously parse the model file. + GeometryReader* geometryReader = new GeometryReader(reply.url(), &reply, _mapping); + connect(geometryReader, SIGNAL(onSuccess(FBXGeometry*)), SLOT(modelParseSuccess(FBXGeometry*))); + connect(geometryReader, SIGNAL(onError(int, QString)), SLOT(modelParseError(int, QString))); + + QThreadPool::globalInstance()->start(geometryReader); +} + +void NetworkGeometry::modelRequestError(QNetworkReply::NetworkError error) { + assert(_state == RequestModelState); + _state = ErrorState; + emit onFailure(*this, ModelRequestError); +} + +static NetworkMesh* buildNetworkMesh(const FBXMesh& mesh, const QUrl& textureBaseUrl) { auto textureCache = DependencyManager::get(); - - foreach (const FBXMesh& mesh, _geometry.meshes) { - NetworkMesh networkMesh; - - int totalIndices = 0; - bool checkForTexcoordLightmap = false; - foreach (const FBXMeshPart& part, mesh.parts) { - NetworkMeshPart networkPart; - if (!part.diffuseTexture.filename.isEmpty()) { - networkPart.diffuseTexture = textureCache->getTexture( - _textureBase.resolved(QUrl(part.diffuseTexture.filename)), DEFAULT_TEXTURE, - mesh.isEye, part.diffuseTexture.content); - networkPart.diffuseTextureName = part.diffuseTexture.name; - networkPart.diffuseTexture->setLoadPriorities(_loadPriorities); - } - if (!part.normalTexture.filename.isEmpty()) { - networkPart.normalTexture = textureCache->getTexture( - _textureBase.resolved(QUrl(part.normalTexture.filename)), NORMAL_TEXTURE, - false, part.normalTexture.content); - networkPart.normalTextureName = part.normalTexture.name; - networkPart.normalTexture->setLoadPriorities(_loadPriorities); - } - if (!part.specularTexture.filename.isEmpty()) { - networkPart.specularTexture = textureCache->getTexture( - _textureBase.resolved(QUrl(part.specularTexture.filename)), SPECULAR_TEXTURE, - false, part.specularTexture.content); - networkPart.specularTextureName = part.specularTexture.name; - networkPart.specularTexture->setLoadPriorities(_loadPriorities); - } - if (!part.emissiveTexture.filename.isEmpty()) { - networkPart.emissiveTexture = textureCache->getTexture( - _textureBase.resolved(QUrl(part.emissiveTexture.filename)), EMISSIVE_TEXTURE, - false, part.emissiveTexture.content); - networkPart.emissiveTextureName = part.emissiveTexture.name; - networkPart.emissiveTexture->setLoadPriorities(_loadPriorities); - checkForTexcoordLightmap = true; - } - networkMesh.parts.append(networkPart); - - totalIndices += (part.quadIndices.size() + part.triangleIndices.size()); + NetworkMesh* networkMesh = new NetworkMesh(); + + int totalIndices = 0; + bool checkForTexcoordLightmap = false; + + // process network parts + foreach (const FBXMeshPart& part, mesh.parts) { + NetworkMeshPart* networkPart = new NetworkMeshPart(); + + if (!part.diffuseTexture.filename.isEmpty()) { + networkPart->diffuseTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(part.diffuseTexture.filename)), DEFAULT_TEXTURE, + mesh.isEye, part.diffuseTexture.content); + networkPart->diffuseTextureName = part.diffuseTexture.name; } - - { - networkMesh._indexBuffer = std::make_shared(); - networkMesh._indexBuffer->resize(totalIndices * sizeof(int)); - int offset = 0; - foreach(const FBXMeshPart& part, mesh.parts) { - networkMesh._indexBuffer->setSubData(offset, part.quadIndices.size() * sizeof(int), - (gpu::Byte*) part.quadIndices.constData()); - offset += part.quadIndices.size() * sizeof(int); - networkMesh._indexBuffer->setSubData(offset, part.triangleIndices.size() * sizeof(int), - (gpu::Byte*) part.triangleIndices.constData()); - offset += part.triangleIndices.size() * sizeof(int); - } + if (!part.normalTexture.filename.isEmpty()) { + networkPart->normalTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(part.normalTexture.filename)), NORMAL_TEXTURE, + false, part.normalTexture.content); + networkPart->normalTextureName = part.normalTexture.name; } - - { - networkMesh._vertexBuffer = std::make_shared(); - // if we don't need to do any blending, the positions/normals can be static - if (mesh.blendshapes.isEmpty()) { - int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3); - int tangentsOffset = normalsOffset + mesh.normals.size() * sizeof(glm::vec3); - int colorsOffset = tangentsOffset + mesh.tangents.size() * sizeof(glm::vec3); - int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3); - int texCoords1Offset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2); - int clusterIndicesOffset = texCoords1Offset + mesh.texCoords1.size() * sizeof(glm::vec2); - int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4); - - networkMesh._vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4)); - - networkMesh._vertexBuffer->setSubData(0, mesh.vertices.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.vertices.constData()); - networkMesh._vertexBuffer->setSubData(normalsOffset, mesh.normals.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.normals.constData()); - networkMesh._vertexBuffer->setSubData(tangentsOffset, - mesh.tangents.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.tangents.constData()); - networkMesh._vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.colors.constData()); - networkMesh._vertexBuffer->setSubData(texCoordsOffset, - mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords.constData()); - networkMesh._vertexBuffer->setSubData(texCoords1Offset, - mesh.texCoords1.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords1.constData()); - networkMesh._vertexBuffer->setSubData(clusterIndicesOffset, - mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterIndices.constData()); - networkMesh._vertexBuffer->setSubData(clusterWeightsOffset, - mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterWeights.constData()); - - // otherwise, at least the cluster indices/weights can be static - networkMesh._vertexStream = std::make_shared(); - networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, 0, sizeof(glm::vec3)); - if (mesh.normals.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, normalsOffset, sizeof(glm::vec3)); - if (mesh.tangents.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, tangentsOffset, sizeof(glm::vec3)); - if (mesh.colors.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, colorsOffset, sizeof(glm::vec3)); - if (mesh.texCoords.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, texCoordsOffset, sizeof(glm::vec2)); - if (mesh.texCoords1.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, texCoords1Offset, sizeof(glm::vec2)); - if (mesh.clusterIndices.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4)); - if (mesh.clusterWeights.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4)); - - int channelNum = 0; - networkMesh._vertexFormat = std::make_shared(); - networkMesh._vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); - if (mesh.normals.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); - if (mesh.tangents.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); - if (mesh.colors.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB)); - if (mesh.texCoords.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV)); - if (mesh.texCoords1.size()) { - networkMesh._vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV)); - } else if (checkForTexcoordLightmap && mesh.texCoords.size()) { - // need lightmap texcoord UV but doesn't have uv#1 so just reuse the same channel - networkMesh._vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, channelNum - 1, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV)); - } - if (mesh.clusterIndices.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW)); - if (mesh.clusterWeights.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW)); - } - else { - int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3); - int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3); - int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2); - int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4); - - networkMesh._vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4)); - networkMesh._vertexBuffer->setSubData(0, mesh.tangents.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.tangents.constData()); - networkMesh._vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.colors.constData()); - networkMesh._vertexBuffer->setSubData(texCoordsOffset, - mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords.constData()); - networkMesh._vertexBuffer->setSubData(clusterIndicesOffset, - mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterIndices.constData()); - networkMesh._vertexBuffer->setSubData(clusterWeightsOffset, - mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterWeights.constData()); - - networkMesh._vertexStream = std::make_shared(); - if (mesh.tangents.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, 0, sizeof(glm::vec3)); - if (mesh.colors.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, colorsOffset, sizeof(glm::vec3)); - if (mesh.texCoords.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, texCoordsOffset, sizeof(glm::vec2)); - if (mesh.clusterIndices.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4)); - if (mesh.clusterWeights.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4)); - - int channelNum = 0; - networkMesh._vertexFormat = std::make_shared(); - networkMesh._vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); - if (mesh.normals.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); - if (mesh.tangents.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); - if (mesh.colors.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB)); - if (mesh.texCoords.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV)); - if (mesh.clusterIndices.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW)); - if (mesh.clusterWeights.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW)); - - } + if (!part.specularTexture.filename.isEmpty()) { + networkPart->specularTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(part.specularTexture.filename)), SPECULAR_TEXTURE, + false, part.specularTexture.content); + networkPart->specularTextureName = part.specularTexture.name; } - - _meshes.append(networkMesh); + if (!part.emissiveTexture.filename.isEmpty()) { + networkPart->emissiveTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(part.emissiveTexture.filename)), EMISSIVE_TEXTURE, + false, part.emissiveTexture.content); + networkPart->emissiveTextureName = part.emissiveTexture.name; + checkForTexcoordLightmap = true; + } + networkMesh->_parts.emplace_back(networkPart); + totalIndices += (part.quadIndices.size() + part.triangleIndices.size()); } - - finishedLoading(true); + + // initialize index buffer + { + networkMesh->_indexBuffer = std::make_shared(); + networkMesh->_indexBuffer->resize(totalIndices * sizeof(int)); + int offset = 0; + foreach(const FBXMeshPart& part, mesh.parts) { + networkMesh->_indexBuffer->setSubData(offset, part.quadIndices.size() * sizeof(int), + (gpu::Byte*) part.quadIndices.constData()); + offset += part.quadIndices.size() * sizeof(int); + networkMesh->_indexBuffer->setSubData(offset, part.triangleIndices.size() * sizeof(int), + (gpu::Byte*) part.triangleIndices.constData()); + offset += part.triangleIndices.size() * sizeof(int); + } + } + + // initialize vertex buffer + { + networkMesh->_vertexBuffer = std::make_shared(); + // if we don't need to do any blending, the positions/normals can be static + if (mesh.blendshapes.isEmpty()) { + int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3); + int tangentsOffset = normalsOffset + mesh.normals.size() * sizeof(glm::vec3); + int colorsOffset = tangentsOffset + mesh.tangents.size() * sizeof(glm::vec3); + int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3); + int texCoords1Offset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2); + int clusterIndicesOffset = texCoords1Offset + mesh.texCoords1.size() * sizeof(glm::vec2); + int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4); + + networkMesh->_vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4)); + + networkMesh->_vertexBuffer->setSubData(0, mesh.vertices.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.vertices.constData()); + networkMesh->_vertexBuffer->setSubData(normalsOffset, mesh.normals.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.normals.constData()); + networkMesh->_vertexBuffer->setSubData(tangentsOffset, + mesh.tangents.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.tangents.constData()); + networkMesh->_vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.colors.constData()); + networkMesh->_vertexBuffer->setSubData(texCoordsOffset, + mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords.constData()); + networkMesh->_vertexBuffer->setSubData(texCoords1Offset, + mesh.texCoords1.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords1.constData()); + networkMesh->_vertexBuffer->setSubData(clusterIndicesOffset, + mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterIndices.constData()); + networkMesh->_vertexBuffer->setSubData(clusterWeightsOffset, + mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterWeights.constData()); + + // otherwise, at least the cluster indices/weights can be static + networkMesh->_vertexStream = std::make_shared(); + networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, 0, sizeof(glm::vec3)); + if (mesh.normals.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, normalsOffset, sizeof(glm::vec3)); + if (mesh.tangents.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, tangentsOffset, sizeof(glm::vec3)); + if (mesh.colors.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, colorsOffset, sizeof(glm::vec3)); + if (mesh.texCoords.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, texCoordsOffset, sizeof(glm::vec2)); + if (mesh.texCoords1.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, texCoords1Offset, sizeof(glm::vec2)); + if (mesh.clusterIndices.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4)); + if (mesh.clusterWeights.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4)); + + int channelNum = 0; + networkMesh->_vertexFormat = std::make_shared(); + networkMesh->_vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); + if (mesh.normals.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); + if (mesh.tangents.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); + if (mesh.colors.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB)); + if (mesh.texCoords.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV)); + if (mesh.texCoords1.size()) { + networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV)); + } else if (checkForTexcoordLightmap && mesh.texCoords.size()) { + // need lightmap texcoord UV but doesn't have uv#1 so just reuse the same channel + networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, channelNum - 1, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV)); + } + if (mesh.clusterIndices.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW)); + if (mesh.clusterWeights.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW)); + } + else { + int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3); + int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3); + int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2); + int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4); + + networkMesh->_vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4)); + networkMesh->_vertexBuffer->setSubData(0, mesh.tangents.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.tangents.constData()); + networkMesh->_vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.colors.constData()); + networkMesh->_vertexBuffer->setSubData(texCoordsOffset, + mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords.constData()); + networkMesh->_vertexBuffer->setSubData(clusterIndicesOffset, + mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterIndices.constData()); + networkMesh->_vertexBuffer->setSubData(clusterWeightsOffset, + mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterWeights.constData()); + + networkMesh->_vertexStream = std::make_shared(); + if (mesh.tangents.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, 0, sizeof(glm::vec3)); + if (mesh.colors.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, colorsOffset, sizeof(glm::vec3)); + if (mesh.texCoords.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, texCoordsOffset, sizeof(glm::vec2)); + if (mesh.clusterIndices.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4)); + if (mesh.clusterWeights.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4)); + + int channelNum = 0; + networkMesh->_vertexFormat = std::make_shared(); + networkMesh->_vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); + if (mesh.normals.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); + if (mesh.tangents.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); + if (mesh.colors.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB)); + if (mesh.texCoords.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV)); + if (mesh.clusterIndices.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW)); + if (mesh.clusterWeights.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW)); + } + } + + return networkMesh; +} + +void NetworkGeometry::modelParseSuccess(FBXGeometry* geometry) { + // assume owner ship of geometry pointer + _geometry.reset(geometry); + + foreach(const FBXMesh& mesh, _geometry->meshes) { + _meshes.emplace_back(buildNetworkMesh(mesh, _textureBaseUrl)); + } + + _state = SuccessState; + emit onSuccess(*this, *_geometry.get()); + + delete _resource; + _resource = nullptr; +} + +void NetworkGeometry::modelParseError(int error, QString str) { + _state = ErrorState; + emit onFailure(*this, (NetworkGeometry::Error)error); + + delete _resource; + _resource = nullptr; } bool NetworkMeshPart::isTranslucent() const { return diffuseTexture && diffuseTexture->isTranslucent(); } - bool NetworkMesh::isPartTranslucent(const FBXMesh& fbxMesh, int partIndex) const { assert(partIndex >= 0); - assert(partIndex < parts.size()); - return (parts.at(partIndex).isTranslucent() || fbxMesh.parts.at(partIndex).opacity != 1.0f); + assert((size_t)partIndex < _parts.size()); + return (_parts.at(partIndex)->isTranslucent() || fbxMesh.parts.at(partIndex).opacity != 1.0f); } int NetworkMesh::getTranslucentPartCount(const FBXMesh& fbxMesh) const { int count = 0; - for (int i = 0; i < parts.size(); i++) { + + for (size_t i = 0; i < _parts.size(); i++) { if (isPartTranslucent(fbxMesh, i)) { count++; } diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index f70eae6380..774df1561c 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -13,6 +13,7 @@ #define hifi_GeometryCache_h #include +#include #include #include @@ -129,6 +130,9 @@ public: int allocateID() { return _nextID++; } static const int UNKNOWN_ID; + virtual QSharedPointer createResource(const QUrl& url, const QSharedPointer& fallback, + bool delayLoad, const void* extra); + void renderSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec3& color, bool solid = true, int id = UNKNOWN_ID) { renderSphere(batch, radius, slices, stacks, glm::vec4(color, 1.0f), solid, id); } @@ -208,11 +212,6 @@ public: /// Set a batch to the simple pipeline, returning the previous pipeline void useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend = false); -protected: - - virtual QSharedPointer createResource(const QUrl& url, - const QSharedPointer& fallback, bool delayLoad, const void* extra); - private: GeometryCache(); virtual ~GeometryCache(); @@ -305,70 +304,104 @@ private: QHash > _networkGeometry; }; -/// Geometry loaded from the network. -class NetworkGeometry : public Resource { +class NetworkGeometry : public QObject { Q_OBJECT public: - - /// A hysteresis value indicating that we have no state memory. - static const float NO_HYSTERESIS; - - NetworkGeometry(const QUrl& url, const QSharedPointer& fallback, bool delayLoad, - const QVariantHash& mapping = QVariantHash(), const QUrl& textureBase = QUrl()); + // mapping is only used if url is a .fbx or .obj file, it is essentially the content of an fst file. + // if delayLoad is true, the url will not be immediately downloaded. + // use the attemptRequest method to initiate the download. + NetworkGeometry(const QUrl& url, bool delayLoad, const QVariantHash& mapping, const QUrl& textureBaseUrl = QUrl()); + ~NetworkGeometry(); - /// Checks whether the geometry and its textures are loaded. + const QUrl& getURL() const { return _url; } + + void attemptRequest(); + + // true when the geometry is loaded (but maybe not it's associated textures) + bool isLoaded() const; + + // true when the requested geometry and its textures are loaded. bool isLoadedWithTextures() const; - /// Returns a pointer to the geometry appropriate for the specified distance. - /// \param hysteresis a hysteresis parameter that prevents rapid model switching - QSharedPointer getLODOrFallback(float distance, float& hysteresis, bool delayLoad = false) const; + // WARNING: only valid when isLoaded returns true. + const FBXGeometry& getFBXGeometry() const { return *_geometry; } + const std::vector>& getMeshes() const { return _meshes; } - const FBXGeometry& getFBXGeometry() const { return _geometry; } - const QVector& getMeshes() const { return _meshes; } - - QVector getJointMappings(const AnimationPointer& animation); - - virtual void setLoadPriority(const QPointer& owner, float priority); - virtual void setLoadPriorities(const QHash, float>& priorities); - virtual void clearLoadPriority(const QPointer& owner); - void setTextureWithNameToURL(const QString& name, const QUrl& url); QStringList getTextureNames() const; - + + enum Error { + MissingFilenameInMapping = 0, + MappingRequestError, + ModelRequestError, + ModelParseError + }; + +signals: + // Fired when everything has downloaded and parsed successfully. + void onSuccess(NetworkGeometry& networkGeometry, FBXGeometry& fbxGeometry); + + // Fired when something went wrong. + void onFailure(NetworkGeometry& networkGeometry, Error error); + +protected slots: + void mappingRequestDone(QNetworkReply& reply); + void mappingRequestError(QNetworkReply::NetworkError error); + + void modelRequestDone(QNetworkReply& reply); + void modelRequestError(QNetworkReply::NetworkError error); + + void modelParseSuccess(FBXGeometry* geometry); + void modelParseError(int error, QString str); + protected: + void attemptRequestInternal(); + void requestMapping(const QUrl& url); + void requestModel(const QUrl& url); - virtual void init(); - virtual void downloadFinished(QNetworkReply* reply); - virtual void reinsert(); - - Q_INVOKABLE void setGeometry(const FBXGeometry& geometry); - -private slots: - void replaceTexturesWithPendingChanges(); -private: - - friend class GeometryCache; - - void setLODParent(const QWeakPointer& lodParent) { _lodParent = lodParent; } - + enum State { DelayState, + RequestMappingState, + RequestModelState, + ParsingModelState, + SuccessState, + ErrorState }; + State _state; + + QUrl _url; QVariantHash _mapping; - QUrl _textureBase; - QSharedPointer _fallback; - - QMap > _lods; - FBXGeometry _geometry; - QVector _meshes; - - QWeakPointer _lodParent; - - QHash, QVector > _jointMappings; - - QHash _pendingTextureChanges; + QUrl _textureBaseUrl; + Resource* _resource = nullptr; + std::unique_ptr _geometry; + std::vector> _meshes; + + // cache for isLoadedWithTextures() mutable bool _isLoadedWithTextures = false; }; +/// Reads geometry in a worker thread. +class GeometryReader : public QObject, public QRunnable { + Q_OBJECT + +public: + + GeometryReader(const QUrl& url, QNetworkReply* reply, const QVariantHash& mapping); + + virtual void run(); + +signals: + void onSuccess(FBXGeometry* geometry); + void onError(int error, QString str); + +private: + + QWeakPointer _geometry; + QUrl _url; + QNetworkReply* _reply; + QVariantHash _mapping; +}; + /// The state associated with a single mesh part. class NetworkMeshPart { public: @@ -394,9 +427,9 @@ public: gpu::BufferStreamPointer _vertexStream; gpu::Stream::FormatPointer _vertexFormat; - - QVector parts; - + + std::vector> _parts; + int getTranslucentPartCount(const FBXMesh& fbxMesh) const; bool isPartTranslucent(const FBXMesh& fbxMesh, int partIndex) const; }; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 7452c32ed2..c2d723a323 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -48,6 +48,8 @@ #include "model_lightmap_specular_map_frag.h" #include "model_translucent_frag.h" +#include "RenderUtilsLogging.h" + using namespace std; static int modelPointerTypeId = qRegisterMetaType >(); @@ -66,7 +68,6 @@ Model::Model(RigPointer rig, QObject* parent) : _snappedToRegistrationPoint(false), _showTrueJointTransforms(true), _cauterizeBones(false), - _lodDistance(0.0f), _pupilDilation(0.0f), _url(HTTP_INVALID_COM), _urlAsString(HTTP_INVALID_COM), @@ -234,7 +235,7 @@ QVector Model::createJointStates(const FBXGeometry& geometry) { }; void Model::initJointTransforms() { - if (!_geometry) { + if (!_geometry || !_geometry->isLoaded()) { return; } const FBXGeometry& geometry = _geometry->getFBXGeometry(); @@ -368,8 +369,10 @@ void Model::init() { } void Model::reset() { - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - _rig->reset(geometry.joints); + if (_geometry && _geometry->isLoaded()) { + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + _rig->reset(geometry.joints); + } _meshGroupsKnown = false; _readyWhenAdded = false; // in case any of our users are using scenes invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid @@ -378,68 +381,23 @@ void Model::reset() { bool Model::updateGeometry() { PROFILE_RANGE(__FUNCTION__); bool needFullUpdate = false; - bool needToRebuild = false; - if (_nextGeometry) { - _nextGeometry = _nextGeometry->getLODOrFallback(_lodDistance, _nextLODHysteresis); - _nextGeometry->setLoadPriority(this, -_lodDistance); - _nextGeometry->ensureLoading(); - if (_nextGeometry->isLoaded()) { - applyNextGeometry(); - needToRebuild = true; - } - } - if (!_geometry) { + + if (!_geometry || !_geometry->isLoaded()) { // geometry is not ready return false; } - QSharedPointer geometry = _geometry->getLODOrFallback(_lodDistance, _lodHysteresis); - if (_geometry != geometry) { + _needsReload = false; - // NOTE: it is theoretically impossible to reach here after passing through the applyNextGeometry() call above. - // Which means we don't need to worry about calling deleteGeometry() below immediately after creating new geometry. - - const FBXGeometry& newGeometry = geometry->getFBXGeometry(); - QVector newJointStates = createJointStates(newGeometry); - - if (! _rig->jointStatesEmpty()) { - // copy the existing joint states - const FBXGeometry& oldGeometry = _geometry->getFBXGeometry(); - for (QHash::const_iterator it = oldGeometry.jointIndices.constBegin(); - it != oldGeometry.jointIndices.constEnd(); it++) { - int oldIndex = it.value() - 1; - int newIndex = newGeometry.getJointIndex(it.key()); - if (newIndex != -1) { - newJointStates[newIndex].copyState(_rig->getJointState(oldIndex)); - } - } - } - - deleteGeometry(); - _dilatedTextures.clear(); - if (!geometry) { - std::cout << "WARNING: no geometry in Model::updateGeometry\n"; - } - setGeometry(geometry); - - _meshGroupsKnown = false; - _readyWhenAdded = false; // in case any of our users are using scenes - invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid - initJointStates(newJointStates); - needToRebuild = true; - } else if (_rig->jointStatesEmpty()) { + QSharedPointer geometry = _geometry; + if (_rig->jointStatesEmpty()) { const FBXGeometry& fbxGeometry = geometry->getFBXGeometry(); if (fbxGeometry.joints.size() > 0) { initJointStates(createJointStates(fbxGeometry)); needToRebuild = true; } - } else if (!geometry->isLoaded()) { - deleteGeometry(); - _dilatedTextures.clear(); } - _geometry->setLoadPriority(this, -_lodDistance); - _geometry->ensureLoading(); if (needToRebuild) { const FBXGeometry& fbxGeometry = geometry->getFBXGeometry(); @@ -454,7 +412,7 @@ bool Model::updateGeometry() { buffer->resize((mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3)); buffer->setSubData(0, mesh.vertices.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.vertices.constData()); buffer->setSubData(mesh.vertices.size() * sizeof(glm::vec3), - mesh.normals.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.normals.constData()); + mesh.normals.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.normals.constData()); } _blendedVertexBuffers.push_back(buffer); } @@ -1069,53 +1027,36 @@ int Model::getLastFreeJointIndex(int jointIndex) const { return (isActive() && jointIndex != -1) ? _geometry->getFBXGeometry().joints.at(jointIndex).freeLineage.last() : -1; } -void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bool delayLoad) { +void Model::setURL(const QUrl& url) { + // don't recreate the geometry if it's the same URL if (_url == url && _geometry && _geometry->getURL() == url) { return; } - _readyWhenAdded = false; // reset out render items. - _needsReload = true; - invalidCalculatedMeshBoxes(); - _url = url; _urlAsString = _url.toString(); + { + render::PendingChanges pendingChanges; + render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); + removeFromScene(scene, pendingChanges); + scene->enqueuePendingChanges(pendingChanges); + } + + _needsReload = true; + _meshGroupsKnown = false; + invalidCalculatedMeshBoxes(); + deleteGeometry(); + + _geometry.reset(new NetworkGeometry(url, false, QVariantHash())); onInvalidate(); - - // if so instructed, keep the current geometry until the new one is loaded - _nextGeometry = DependencyManager::get()->getGeometry(url, fallback, delayLoad); - _nextLODHysteresis = NetworkGeometry::NO_HYSTERESIS; - if (!retainCurrent || !isActive() || (_nextGeometry && _nextGeometry->isLoaded())) { - applyNextGeometry(); - } } -void Model::geometryRefreshed() { - QObject* sender = QObject::sender(); - - if (sender == _geometry) { - _readyWhenAdded = false; // reset out render items. - _needsReload = true; - invalidCalculatedMeshBoxes(); - - onInvalidate(); - - // if so instructed, keep the current geometry until the new one is loaded - _nextGeometry = DependencyManager::get()->getGeometry(_url); - _nextLODHysteresis = NetworkGeometry::NO_HYSTERESIS; - applyNextGeometry(); - } else { - sender->disconnect(this, SLOT(geometryRefreshed())); - } -} - - const QSharedPointer Model::getCollisionGeometry(bool delayLoad) { if (_collisionGeometry.isNull() && !_collisionUrl.isEmpty()) { - _collisionGeometry = DependencyManager::get()->getGeometry(_collisionUrl, QUrl(), delayLoad); + _collisionGeometry.reset(new NetworkGeometry(_collisionUrl, delayLoad, QVariantHash())); } if (_collisionGeometry && _collisionGeometry->isLoaded()) { @@ -1130,7 +1071,7 @@ void Model::setCollisionModelURL(const QUrl& url) { return; } _collisionUrl = url; - _collisionGeometry = DependencyManager::get()->getGeometry(url, QUrl(), true); + _collisionGeometry.reset(new NetworkGeometry(url, false, QVariantHash())); } bool Model::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const { @@ -1461,46 +1402,23 @@ void Model::setGeometry(const QSharedPointer& newGeometry) { if (_geometry == newGeometry) { return; } - - if (_geometry) { - _geometry->disconnect(_geometry.data(), &Resource::onRefresh, this, &Model::geometryRefreshed); - } _geometry = newGeometry; - QObject::connect(_geometry.data(), &Resource::onRefresh, this, &Model::geometryRefreshed); -} - -void Model::applyNextGeometry() { - // delete our local geometry and custom textures - deleteGeometry(); - _dilatedTextures.clear(); - _lodHysteresis = _nextLODHysteresis; - - // we retain a reference to the base geometry so that its reference count doesn't fall to zero - setGeometry(_nextGeometry); - - _meshGroupsKnown = false; - _readyWhenAdded = false; // in case any of our users are using scenes - _needsReload = false; // we are loaded now! - invalidCalculatedMeshBoxes(); - _nextGeometry.reset(); } void Model::deleteGeometry() { _blendedVertexBuffers.clear(); _rig->clearJointStates(); _meshStates.clear(); - _rig->deleteAnimations(); - - if (_geometry) { - _geometry->clearLoadPriority(this); - } - _blendedBlendshapeCoefficients.clear(); } AABox Model::getPartBounds(int meshIndex, int partIndex) { + if (!_geometry || !_geometry->isLoaded()) { + return AABox(); + } + if (meshIndex < _meshStates.size()) { const MeshState& state = _meshStates.at(meshIndex); bool isSkinned = state.clusterMatrices.size() > 1; @@ -1531,7 +1449,7 @@ AABox Model::getPartBounds(int meshIndex, int partIndex) { } void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent) { - // PROFILE_RANGE(__FUNCTION__); +// PROFILE_RANGE(__FUNCTION__); PerformanceTimer perfTimer("Model::renderPart"); if (!_readyWhenAdded) { return; // bail asap @@ -1557,14 +1475,14 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME const FBXGeometry& geometry = _geometry->getFBXGeometry(); - const QVector& networkMeshes = _geometry->getMeshes(); + const std::vector>& networkMeshes = _geometry->getMeshes(); // guard against partially loaded meshes - if (meshIndex >= networkMeshes.size() || meshIndex >= geometry.meshes.size() || meshIndex >= _meshStates.size() ) { + if (meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)geometry.meshes.size() || meshIndex >= (int)_meshStates.size() ) { return; } - const NetworkMesh& networkMesh = networkMeshes.at(meshIndex); + const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get()); const FBXMesh& mesh = geometry.meshes.at(meshIndex); const MeshState& state = _meshStates.at(meshIndex); @@ -1614,8 +1532,7 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown // to false to rebuild out mesh groups. - - if (meshIndex < 0 || meshIndex >= networkMeshes.size() || meshIndex > geometry.meshes.size()) { + if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex > geometry.meshes.size()) { _meshGroupsKnown = false; // regenerate these lists next time around. _readyWhenAdded = false; // in case any of our users are using scenes invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid @@ -1669,11 +1586,11 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran } // guard against partially loaded meshes - if (partIndex >= networkMesh.parts.size() || partIndex >= mesh.parts.size()) { + if (partIndex >= (int)networkMesh._parts.size() || partIndex >= mesh.parts.size()) { return; } - const NetworkMeshPart& networkPart = networkMesh.parts.at(partIndex); + const NetworkMeshPart& networkPart = *(networkMesh._parts.at(partIndex).get()); const FBXMeshPart& part = mesh.parts.at(partIndex); model::MaterialPointer material = part._material; @@ -1790,10 +1707,10 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran void Model::segregateMeshGroups() { const FBXGeometry& geometry = _geometry->getFBXGeometry(); - const QVector& networkMeshes = _geometry->getMeshes(); + const std::vector>& networkMeshes = _geometry->getMeshes(); // all of our mesh vectors must match in size - if (networkMeshes.size() != geometry.meshes.size() || + if ((int)networkMeshes.size() != geometry.meshes.size() || geometry.meshes.size() != _meshStates.size()) { qDebug() << "WARNING!!!! Mesh Sizes don't match! We will not segregate mesh groups yet."; return; @@ -1803,12 +1720,12 @@ void Model::segregateMeshGroups() { _opaqueRenderItems.clear(); // Run through all of the meshes, and place them into their segregated, but unsorted buckets - for (int i = 0; i < networkMeshes.size(); i++) { - const NetworkMesh& networkMesh = networkMeshes.at(i); + for (int i = 0; i < (int)networkMeshes.size(); i++) { + const NetworkMesh& networkMesh = *(networkMeshes.at(i).get()); const FBXMesh& mesh = geometry.meshes.at(i); const MeshState& state = _meshStates.at(i); - bool translucentMesh = networkMesh.getTranslucentPartCount(mesh) == networkMesh.parts.size(); + bool translucentMesh = networkMesh.getTranslucentPartCount(mesh) == (int)networkMesh._parts.size(); bool hasTangents = !mesh.tangents.isEmpty(); bool hasSpecular = mesh.hasSpecularTexture(); bool hasLightmap = mesh.hasEmissiveTexture(); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index c9b63b598e..e55bff6aca 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -68,11 +68,7 @@ public: /// Sets the URL of the model to render. - /// \param fallback the URL of a fallback model to render if the requested model fails to load - /// \param retainCurrent if true, keep rendering the current model until the new one is loaded - /// \param delayLoad if true, don't load the model immediately; wait until actually requested - Q_INVOKABLE void setURL(const QUrl& url, const QUrl& fallback = QUrl(), - bool retainCurrent = false, bool delayLoad = false); + Q_INVOKABLE void setURL(const QUrl& url); const QUrl& getURL() const { return _url; } const QString& getURLAsString() const { return _urlAsString; } @@ -89,7 +85,7 @@ public: render::Item::Status::Getters& statusGetters); void removeFromScene(std::shared_ptr scene, render::PendingChanges& pendingChanges); void renderSetup(RenderArgs* args); - bool isRenderable() const { return !_meshStates.isEmpty() || (isActive() && _geometry->getMeshes().isEmpty()); } + bool isRenderable() const { return !_meshStates.isEmpty() || (isActive() && _geometry->getMeshes().empty()); } bool isVisible() const { return _isVisible; } @@ -141,14 +137,11 @@ public: const QUrl& getCollisionURL() const { return _collisionUrl; } /// Returns a reference to the shared collision geometry. - const QSharedPointer getCollisionGeometry(bool delayLoad = true); + const QSharedPointer getCollisionGeometry(bool delayLoad = false); void setOffset(const glm::vec3& offset); const glm::vec3& getOffset() const { return _offset; } - /// Sets the distance parameter used for LOD computations. - void setLODDistance(float distance) { _lodDistance = distance; } - void setScaleToFit(bool scaleToFit, float largestDimension = 0.0f, bool forceRescale = false); bool getScaleToFit() const { return _scaleToFit; } /// is scale to fit enabled @@ -309,20 +302,12 @@ protected: // hook for derived classes to be notified when setUrl invalidates the current model. virtual void onInvalidate() {}; - void geometryRefreshed(); - private: - void applyNextGeometry(); void deleteGeometry(); QVector createJointStates(const FBXGeometry& geometry); void initJointTransforms(); - QSharedPointer _nextGeometry; - float _lodDistance; - float _lodHysteresis; - float _nextLODHysteresis; - QSharedPointer _collisionGeometry; float _pupilDilation; diff --git a/tests/networking/src/ResourceTests.cpp b/tests/networking/src/ResourceTests.cpp new file mode 100644 index 0000000000..f18f676398 --- /dev/null +++ b/tests/networking/src/ResourceTests.cpp @@ -0,0 +1,95 @@ +// +// ResoruceTests.cpp +// +// Copyright 2015 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 + +#include "ResourceCache.h" +#include "NetworkAccessManager.h" +#include "DependencyManager.h" + +#include "ResourceTests.h" + +QTEST_MAIN(ResourceTests) + +void ResourceTests::initTestCase() { + + auto resourceCacheSharedItems = DependencyManager::set(); + + const qint64 MAXIMUM_CACHE_SIZE = 1024 * 1024 * 1024; // 1GB + + // set up the file cache + //QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); + QString cachePath = "./resourceTestCache"; + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkDiskCache* cache = new QNetworkDiskCache(); + cache->setMaximumCacheSize(MAXIMUM_CACHE_SIZE); + cache->setCacheDirectory(cachePath); + cache->clear(); // clear the cache + networkAccessManager.setCache(cache); +} + +static Resource* resource = nullptr; + + +static bool waitForSignal(QObject *sender, const char *signal, int timeout = 1000) { + QEventLoop loop; + QTimer timer; + timer.setInterval(timeout); + timer.setSingleShot(true); + + loop.connect(sender, signal, SLOT(quit())); + loop.connect(&timer, SIGNAL(timeout()), SLOT(quit())); + timer.start(); + loop.exec(); + + return timer.isActive(); +} + +void ResourceTests::downloadFirst() { + + // download the Mery fst file + QUrl meryUrl = QUrl("http://hifi-public.s3.amazonaws.com/marketplace/contents/e21c0b95-e502-4d15-8c41-ea2fc40f1125/3585ddf674869a67d31d5964f7b52de1.fst"); + resource = new Resource(meryUrl, false); + + const int timeout = 1000; + QEventLoop loop; + QTimer timer; + timer.setInterval(timeout); + timer.setSingleShot(true); + + loop.connect(resource, SIGNAL(loaded(QNetworkReply&)), SLOT(quit())); + loop.connect(resource, SIGNAL(failed(QNetworkReply::NetworkError)), SLOT(quit())); + loop.connect(&timer, SIGNAL(timeout()), SLOT(quit())); + timer.start(); + loop.exec(); + + QVERIFY(resource->isLoaded()); +} + +void ResourceTests::downloadAgain() { + + // download the Mery fst file + QUrl meryUrl = QUrl("http://hifi-public.s3.amazonaws.com/marketplace/contents/e21c0b95-e502-4d15-8c41-ea2fc40f1125/3585ddf674869a67d31d5964f7b52de1.fst"); + resource = new Resource(meryUrl, false); + + const int timeout = 1000; + QEventLoop loop; + QTimer timer; + timer.setInterval(timeout); + timer.setSingleShot(true); + + loop.connect(resource, SIGNAL(loaded(QNetworkReply&)), SLOT(quit())); + loop.connect(resource, SIGNAL(failed(QNetworkReply::NetworkError)), SLOT(quit())); + loop.connect(&timer, SIGNAL(timeout()), SLOT(quit())); + timer.start(); + loop.exec(); + + QVERIFY(resource->isLoaded()); + +} diff --git a/tests/networking/src/ResourceTests.h b/tests/networking/src/ResourceTests.h new file mode 100644 index 0000000000..32fc151982 --- /dev/null +++ b/tests/networking/src/ResourceTests.h @@ -0,0 +1,23 @@ +// +// ResourceTests.h +// +// Copyright 2015 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_ResourceTests_h +#define hifi_ResourceTests_h + +#include + +class ResourceTests : public QObject { + Q_OBJECT +private slots: + void initTestCase(); + void downloadFirst(); + void downloadAgain(); +}; + +#endif // hifi_ResourceTests_h diff --git a/tools/vhacd-util/src/VHACDUtil.cpp b/tools/vhacd-util/src/VHACDUtil.cpp index 3c02c956e4..f39bea9cf9 100644 --- a/tools/vhacd-util/src/VHACDUtil.cpp +++ b/tools/vhacd-util/src/VHACDUtil.cpp @@ -36,15 +36,16 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, FBXGeometry& result) { std::cout << "Reading FBX.....\n"; QByteArray fbxContents = fbx.readAll(); - + FBXGeometry* geom; if (filename.toLower().endsWith(".obj")) { - result = OBJReader().readOBJ(fbxContents, QVariantHash()); + geom = OBJReader().readOBJ(fbxContents, QVariantHash()); } else if (filename.toLower().endsWith(".fbx")) { - result = readFBX(fbxContents, QVariantHash(), filename); + geom = readFBX(fbxContents, QVariantHash(), filename); } else { qDebug() << "unknown file extension"; return false; } + result = *geom; reSortFBXGeometryMeshes(result); From 9f501d4d72ccb0274798e0786905bd237ccb5ec0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 20 Aug 2015 16:55:19 -0700 Subject: [PATCH 097/102] first cut at attempting to hide menu in full screen --- interface/src/Application.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a28435e258..0bc4f9b943 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4985,6 +4985,12 @@ void Application::setFullscreen(const QScreen* target) { #endif _window->windowHandle()->setScreen((QScreen*)target); _window->showFullScreen(); + + // also hide the QMainWindow's menuBar + QMenuBar* menuBar = _window->menuBar(); + if (menuBar) { + menuBar->setVisible(false); + } } void Application::unsetFullscreen(const QScreen* avoid) { @@ -5015,6 +5021,12 @@ void Application::unsetFullscreen(const QScreen* avoid) { #else _window->setGeometry(targetGeometry); #endif + + // also show the QMainWindow's menuBar + QMenuBar* menuBar = _window->menuBar(); + if (menuBar) { + menuBar->setVisible(true); + } } From 06b2a88fb6f730c7fd157f9543671c2c39efc373 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 20 Aug 2015 19:11:15 -0700 Subject: [PATCH 098/102] toggle menu near top of window --- interface/src/Application.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0bc4f9b943..a088c42f87 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1744,6 +1744,27 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { return; } +#if 1 //ndef Q_OS_MAC + // If in full screen, and our main windows menu bar is hidden, and we're close to the top of the QMainWindow + // then show the menubar. + if (_window->isFullScreen()) { + QMenuBar* menuBar = _window->menuBar(); + if (menuBar) { + static const int MENU_TOGGLE_AREA = 10; + if (!menuBar->isVisible()) { + if (event->pos().y() <= MENU_TOGGLE_AREA) { + menuBar->setVisible(true); + } + } else { + if (event->pos().y() > MENU_TOGGLE_AREA) { + menuBar->setVisible(false); + } + } + } + } +#endif + + _entities.mouseMoveEvent(event, deviceID); _controllerScriptingInterface.emitMouseMoveEvent(event, deviceID); // send events to any registered scripts @@ -4986,11 +5007,13 @@ void Application::setFullscreen(const QScreen* target) { _window->windowHandle()->setScreen((QScreen*)target); _window->showFullScreen(); +#ifndef Q_OS_MAC // also hide the QMainWindow's menuBar QMenuBar* menuBar = _window->menuBar(); if (menuBar) { menuBar->setVisible(false); } +#endif } void Application::unsetFullscreen(const QScreen* avoid) { @@ -5022,11 +5045,13 @@ void Application::unsetFullscreen(const QScreen* avoid) { _window->setGeometry(targetGeometry); #endif +#ifndef Q_OS_MAC // also show the QMainWindow's menuBar QMenuBar* menuBar = _window->menuBar(); if (menuBar) { menuBar->setVisible(true); } +#endif } From bd29fb247497856f688f699780904eef1958c41f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 20 Aug 2015 19:31:51 -0700 Subject: [PATCH 099/102] fix ifdef --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a088c42f87..b9bafbab1a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1744,7 +1744,7 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { return; } -#if 1 //ndef Q_OS_MAC +#ifndef Q_OS_MAC // If in full screen, and our main windows menu bar is hidden, and we're close to the top of the QMainWindow // then show the menubar. if (_window->isFullScreen()) { From ef4ad3107e1c95f58208e470948070050412b35d Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 20 Aug 2015 22:11:11 -0700 Subject: [PATCH 100/102] First pass, grenade toy. Needs art. --- examples/toys/grenade.js | 197 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 examples/toys/grenade.js diff --git a/examples/toys/grenade.js b/examples/toys/grenade.js new file mode 100644 index 0000000000..545bfbb982 --- /dev/null +++ b/examples/toys/grenade.js @@ -0,0 +1,197 @@ +// +// Grenade.js +// examples +// +// Created by Philip Rosedale on August 20, 2015 +// Copyright 2015 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 +// + +HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; + +var grenadeURL = HIFI_PUBLIC_BUCKET + "models/props/grenade/grenade.fbx"; +var fuseSoundURL = HIFI_PUBLIC_BUCKET + "sounds/burningFuse.wav"; +var boomSoundURL = HIFI_PUBLIC_BUCKET + "sounds/explosion.wav"; + +var AudioRotationOffset = Quat.fromPitchYawRollDegrees(0, -90, 0); +var audioOptions = { + volume: 0.5, + loop: true +} + +var injector = null; + +var fuseSound = SoundCache.getSound(fuseSoundURL, audioOptions.isStereo); +var boomSound = SoundCache.getSound(boomSoundURL, audioOptions.isStereo); + +var grenade = null; +var particles = null; +var properties = null; +var originalPosition = null; +var isGrenade = false; +var isBurning = false; + +var animationSettings = JSON.stringify({ + running: true, + loop: true + }); +var explodeAnimationSettings = JSON.stringify({ + running: true, + loop: false + }); + +var GRAVITY = -9.8; +var TIME_TO_EXPLODE = 2500; +var DISTANCE_IN_FRONT_OF_ME = 1.0; + +function makeGrenade() { + var position = Vec3.sum(MyAvatar.position, + Vec3.multiplyQbyV(MyAvatar.orientation, + { x: 0, y: 0.0, z: -DISTANCE_IN_FRONT_OF_ME })); + var rotation = Quat.multiply(MyAvatar.orientation, + Quat.fromPitchYawRollDegrees(0, -90, 0)); + grenade = Entities.addEntity({ + type: "Model", + position: position, + rotation: rotation, + dimensions: { x: 0.09, + y: 0.20, + z: 0.09 }, + collisionsWillMove: true, + modelURL: grenadeURL, + shapeType: "box" + }); + + properties = Entities.getEntityProperties(grenade); + audioOptions.position = position; + audioOptions.orientation = rotation; + originalPosition = position; +} + +function update() { + if (!grenade) { + makeGrenade(); + } else { + var newProperties = Entities.getEntityProperties(grenade); + if (!isBurning) { + // If moved, start fuse + var FUSE_START_MOVE = 0.01; + if (Vec3.length(Vec3.subtract(newProperties.position, originalPosition)) > FUSE_START_MOVE) { + isBurning = true; + // Create fuse particles + particles = Entities.addEntity({ + type: "ParticleEffect", + animationSettings: animationSettings, + position: newProperties.position, + textures: 'https://raw.githubusercontent.com/ericrius1/SantasLair/santa/assets/smokeparticle.png', + emitRate: 100, + emitStrength: 2.0, + emitDirection: { x: 0.0, y: 1.0, z: 0.0 }, + color: { red: 200, green: 0, blue: 0 }, + lifespan: 10.0, + visible: true, + locked: false + + }); + // Start fuse sound + injector = Audio.playSound(fuseSound, audioOptions); + // Start explosion timer + Script.setTimeout(boom, TIME_TO_EXPLODE); + originalPosition = newProperties.position; + // Add gravity + Entities.editEntity(grenade, { gravity: {x: 0, y: GRAVITY, z: 0 }}); + } + } + + if (newProperties.type === "Model") { + if (newProperties.position != properties.position) { + audioOptions.position = newProperties.position; + } + if (newProperties.orientation != properties.orientation) { + audioOptions.orientation = newProperties.orientation; + } + + properties = newProperties; + // Update sound location if playing + if (injector) { + injector.options = audioOptions; + } + if (particles) { + Entities.editEntity(particles, { position: newProperties.position }); + } + } else { + grenade = null; + Script.update.disconnect(update); + Script.scriptEnding.connect(scriptEnding); + scriptEnding(); + Script.stop(); + } + } +} +function boom() { + injector.stop(); + isBurning = false; + var audioOptions = { + position: properties.position, + volume: 0.75, + loop: false + } + Audio.playSound(boomSound, audioOptions); + Entities.addEntity({ + type: "ParticleEffect", + animationSettings: explodeAnimationSettings, + position: properties.position, + textures: 'https://raw.githubusercontent.com/ericrius1/SantasLair/santa/assets/smokeparticle.png', + emitRate: 200, + emitStrength: 3.0, + emitDirection: { x: 0.0, y: 1.0, z: 0.0 }, + color: { red: 255, green: 255, blue: 0 }, + lifespan: 2.0, + visible: true, + lifetime: 2, + locked: false + + }); + var BLAST_RADIUS = 20.0; + var LIFT_DEPTH = 2.0; + var epicenter = properties.position; + epicenter.y -= LIFT_DEPTH; + blowShitUp(epicenter, BLAST_RADIUS); + deleteStuff(); +} + +function blowShitUp(position, radius) { + var stuff = Entities.findEntities(position, radius); + var numMoveable = 0; + var STRENGTH = 3.5; + for (var i = 0; i < stuff.length; i++) { + var properties = Entities.getEntityProperties(stuff[i]); + if (properties.collisionsWillMove) { + var diff = Vec3.subtract(properties.position, position); + var distance = Vec3.length(diff); + var velocity = Vec3.sum(properties.velocity, Vec3.multiply(STRENGTH * 1.0 / distance, Vec3.normalize(diff))); + Entities.editEntity(stuff[i], { velocity: velocity }); + } + } +} + +function scriptEnding() { + deleteStuff(); +} + +function deleteStuff() { + if (grenade != null) { + Entities.deleteEntity(grenade); + grenade = null; + } + if (particles != null) { + Entities.deleteEntity(particles); + particles = null; + } +} + +Script.update.connect(update); +Script.scriptEnding.connect(scriptEnding); + From 7284e3aa3c42e4b188672531411e5f7d3d512f46 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 20 Aug 2015 22:20:51 -0700 Subject: [PATCH 101/102] added a little bit of spin, too. --- examples/toys/grenade.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/toys/grenade.js b/examples/toys/grenade.js index 545bfbb982..b2dfebb888 100644 --- a/examples/toys/grenade.js +++ b/examples/toys/grenade.js @@ -166,13 +166,17 @@ function blowShitUp(position, radius) { var stuff = Entities.findEntities(position, radius); var numMoveable = 0; var STRENGTH = 3.5; + var SPIN_RATE = 20.0; for (var i = 0; i < stuff.length; i++) { var properties = Entities.getEntityProperties(stuff[i]); if (properties.collisionsWillMove) { var diff = Vec3.subtract(properties.position, position); var distance = Vec3.length(diff); var velocity = Vec3.sum(properties.velocity, Vec3.multiply(STRENGTH * 1.0 / distance, Vec3.normalize(diff))); - Entities.editEntity(stuff[i], { velocity: velocity }); + var angularVelocity = { x: Math.random() * SPIN_RATE, y: Math.random() * SPIN_RATE, z: Math.random() * SPIN_RATE }; + angularVelocity = Vec3.multiply( 1.0 / distance, angularVelocity); + Entities.editEntity(stuff[i], { velocity: velocity, + angularVelocity: angularVelocity }); } } } From cee570d2b26fb787e0f04dc26ed5ec692e949144 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 20 Aug 2015 23:06:05 -0700 Subject: [PATCH 102/102] First pass at basketball, just appears in front of you with some reasonable values --- examples/toys/basketball.js | 82 +++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 examples/toys/basketball.js diff --git a/examples/toys/basketball.js b/examples/toys/basketball.js new file mode 100644 index 0000000000..d30dce6e72 --- /dev/null +++ b/examples/toys/basketball.js @@ -0,0 +1,82 @@ +// +// basketball.js +// examples +// +// Created by Philip Rosedale on August 20, 2015 +// Copyright 2015 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 +// + +HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; + +var basketballURL = HIFI_PUBLIC_BUCKET + "models/content/basketball2.fbx"; +var collisionSoundURL = HIFI_PUBLIC_BUCKET + "sounds/basketball/basketball.wav"; + + +var basketball = null; +var originalPosition = null; +var hasMoved = false; + +var GRAVITY = -9.8; +var DISTANCE_IN_FRONT_OF_ME = 1.0; +var START_MOVE = 0.01; +var DIAMETER = 0.30; + +function makeBasketball() { + var position = Vec3.sum(MyAvatar.position, + Vec3.multiplyQbyV(MyAvatar.orientation, + { x: 0, y: 0.0, z: -DISTANCE_IN_FRONT_OF_ME })); + var rotation = Quat.multiply(MyAvatar.orientation, + Quat.fromPitchYawRollDegrees(0, -90, 0)); + basketball = Entities.addEntity({ + type: "Model", + position: position, + rotation: rotation, + dimensions: { x: DIAMETER, + y: DIAMETER, + z: DIAMETER }, + collisionsWillMove: true, + collisionSoundURL: collisionSoundURL, + modelURL: basketballURL, + restitution: 1.0, + linearDamping: 0.00001, + shapeType: "sphere" + }); + originalPosition = position; +} + +function update() { + if (!basketball) { + makeBasketball(); + } else { + var newProperties = Entities.getEntityProperties(basketball); + var moved = Vec3.length(Vec3.subtract(originalPosition, newProperties.position)); + if (!hasMoved && (moved > START_MOVE)) { + hasMoved = true; + Entities.editEntity(basketball, { gravity: {x: 0, y: GRAVITY, z: 0 }}); + } + var MAX_DISTANCE = 10.0; + var distance = Vec3.length(Vec3.subtract(MyAvatar.position, newProperties.position)); + if (distance > MAX_DISTANCE) { + deleteStuff(); + } + } +} + +function scriptEnding() { + deleteStuff(); +} + +function deleteStuff() { + if (basketball != null) { + Entities.deleteEntity(basketball); + basketball = null; + hasMoved = false; + } +} + +Script.update.connect(update); +Script.scriptEnding.connect(scriptEnding); +