From 79119749467034f974dae5efca169359a4946002 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 12 Mar 2015 16:58:37 +0100 Subject: [PATCH 01/13] Added findEntities for AAbox --- libraries/entities/src/EntityTree.cpp | 29 +++++++++++++++++++++++++++ libraries/entities/src/EntityTree.h | 9 ++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index e952618c9f..b5f767af19 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -526,6 +526,35 @@ void EntityTree::findEntities(const AACube& cube, QVector& foundEnt foundEntities.swap(args._foundEntities); } +class FindEntitiesInBoxArgs { +public: + FindEntitiesInBoxArgs(const AABox& box) + : _box(box), _foundEntities() { + } + + AABox _box; + QVector _foundEntities; +}; + +bool EntityTree::findInBoxOperation(OctreeElement* element, void* extraData) { + FindEntitiesInBoxArgs* args = static_cast(extraData); + if (element->getAACube().touches(args->_box)) { + EntityTreeElement* entityTreeElement = static_cast(element); + entityTreeElement->getEntities(args->_box, args->_foundEntities); + return true; + } + return false; +} + +// NOTE: assumes caller has handled locking +void EntityTree::findEntities(const AABox& box, QVector& foundEntities) { + FindEntitiesInBoxArgs args(box); + // NOTE: This should use recursion, since this is a spatial operation + recurseTreeWithOperation(findInBoxOperation, &args); + // swap the two lists of entity pointers instead of copy + foundEntities.swap(args._foundEntities); +} + EntityItem* EntityTree::findEntityByID(const QUuid& id) { EntityItemID entityID(id); return findEntityByEntityItemID(entityID); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 226bfa873a..d6bb77c888 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -111,12 +111,18 @@ public: /// \param foundEntities[out] vector of const EntityItem* /// \remark Side effect: any initial contents in foundEntities will be lost void findEntities(const glm::vec3& center, float radius, QVector& foundEntities); - + /// finds all entities that touch a cube /// \param cube the query cube in world-frame (meters) /// \param foundEntities[out] vector of non-const EntityItem* /// \remark Side effect: any initial contents in entities will be lost void findEntities(const AACube& cube, QVector& foundEntities); + + /// finds all entities that touch a box + /// \param box the query box in world-frame (meters) + /// \param foundEntities[out] vector of non-const EntityItem* + /// \remark Side effect: any initial contents in entities will be lost + void findEntities(const AABox& box, QVector& foundEntities); void addNewlyCreatedHook(NewlyCreatedEntityHook* hook); void removeNewlyCreatedHook(NewlyCreatedEntityHook* hook); @@ -172,6 +178,7 @@ private: static bool findNearPointOperation(OctreeElement* element, void* extraData); static bool findInSphereOperation(OctreeElement* element, void* extraData); static bool findInCubeOperation(OctreeElement* element, void* extraData); + static bool findInBoxOperation(OctreeElement* element, void* extraData); static bool sendEntitiesOperation(OctreeElement* element, void* extraData); void notifyNewlyCreatedEntity(const EntityItem& newEntity, const SharedNodePointer& senderNode); From 29300e0ae01d99122a332d0d54ba147c77b05bbc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 12 Mar 2015 16:59:32 +0100 Subject: [PATCH 02/13] Added findEntitiesInBox to JS API --- .../entities/src/EntityScriptingInterface.cpp | 17 +++++++++++++++++ .../entities/src/EntityScriptingInterface.h | 6 +++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 5ef0db57ec..ad8ef4a20a 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -208,7 +208,24 @@ QVector EntityScriptingInterface::findEntities(const glm::vec3& ce QVector entities; _entityTree->findEntities(center, radius, entities); _entityTree->unlock(); + + foreach (const EntityItem* entity, entities) { + EntityItemID thisEntityItemID(entity->getID(), UNKNOWN_ENTITY_TOKEN, true); + result << thisEntityItemID; + } + } + return result; +} +QVector EntityScriptingInterface::findEntitiesInBox(const glm::vec3& corner, const glm::vec3& dimensions) const { + QVector result; + if (_entityTree) { + _entityTree->lockForRead(); + AABox box(corner, dimensions); + QVector entities; + _entityTree->findEntities(box, entities); + _entityTree->unlock(); + foreach (const EntityItem* entity, entities) { EntityItemID thisEntityItemID(entity->getID(), UNKNOWN_ENTITY_TOKEN, true); result << thisEntityItemID; diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index bac018f2ae..7e0c510f21 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -87,10 +87,14 @@ public slots: /// will return a EntityItemID.isKnownID = false if no models are in the radius /// this function will not find any models in script engine contexts which don't have access to models Q_INVOKABLE EntityItemID findClosestEntity(const glm::vec3& center, float radius) const; - + /// finds models within the search sphere specified by the center point and radius /// this function will not find any models in script engine contexts which don't have access to models Q_INVOKABLE QVector findEntities(const glm::vec3& center, float radius) const; + + /// finds models within the search sphere specified by the center point and radius + /// this function will not find any models in script engine contexts which don't have access to models + Q_INVOKABLE QVector findEntitiesInBox(const glm::vec3& corner, const glm::vec3& dimensions) const; /// If the scripting context has visible entities, this will determine a ray intersection, the results /// may be inaccurate if the engine is unable to access the visible entities, in which case result.accurate From 55a88e60764cca1066d05e4386163beec0cfd423 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 13 Mar 2015 16:24:33 +0100 Subject: [PATCH 03/13] Allow selection of all entities inside box in editEntities --- examples/editEntities.js | 49 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/examples/editEntities.js b/examples/editEntities.js index c236336266..27d1ec0af8 100644 --- a/examples/editEntities.js +++ b/examples/editEntities.js @@ -720,6 +720,10 @@ function setupModelMenus() { afterItem: "Allow Selecting of Large Models", isCheckable: true, isChecked: true }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Lights", shortcutKey: "CTRL+SHIFT+META+L", afterItem: "Allow Selecting of Small Models", isCheckable: true }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Select All Entities In Box", shortcutKey: "CTRL+SHIFT+META+A", + afterItem: "Allow Selecting of Lights" }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Select All Entities Touching Box", shortcutKey: "CTRL+SHIFT+META+T", + afterItem: "Select All Entities In Box" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Models", isSeparator: true, beforeItem: "Settings" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Export Entities", shortcutKey: "CTRL+META+E", afterItem: "Models" }); @@ -747,6 +751,8 @@ function cleanupModelMenus() { Menu.removeMenuItem("Edit", "Allow Selecting of Large Models"); Menu.removeMenuItem("Edit", "Allow Selecting of Small Models"); Menu.removeMenuItem("Edit", "Allow Selecting of Lights"); + Menu.removeMenuItem("Edit", "Select All Entities In Box"); + Menu.removeMenuItem("Edit", "Select All Entities Touching Box"); Menu.removeSeparator("File", "Models"); Menu.removeMenuItem("File", "Export Entities"); @@ -779,6 +785,45 @@ Script.update.connect(function (deltaTime) { selectionDisplay.checkMove(); }); +function insideBox(center, dimensions, point) { + return (Math.abs(point.x - center.x) <= (dimensions.x / 2.0)) + && (Math.abs(point.y - center.y) <= (dimensions.y / 2.0)) + && (Math.abs(point.z - center.z) <= (dimensions.z / 2.0)); +} + +function selectAllEtitiesInCurrentSelectionBox(keepIfTouching) { + if (selectionManager.hasSelection()) { + // Get all entities touching the bounding box of the current selection + var boundingBoxCorner = Vec3.subtract(selectionManager.worldPosition, + Vec3.multiply(selectionManager.worldDimensions, 0.5)); + var entities = Entities.findEntitiesInBox(boundingBoxCorner, selectionManager.worldDimensions); + + if (!keepIfTouching) { + var isValid; + if (selectionManager.localPosition === null) { + isValid = function(position) { + return insideBox(selectionManager.worldPosition, selectionManager.worldDimensions, position); + } + } else { + isValid = function(position) { + var localPosition = Vec3.multiplyQbyV(Quat.inverse(selectionManager.localRotation), + Vec3.subtract(position, + selectionManager.localPosition)); + return insideBox({ x: 0, y: 0, z: 0 }, selectionManager.localDimensions, localPosition); + } + } + for (var i = 0; i < entities.length; ++i) { + var properties = Entities.getEntityProperties(entities[i]); + if (!isValid(properties.position)) { + entities.splice(i, 1); + --i; + } + } + } + selectionManager.setSelections(entities); + } +} + function deleteSelectedEntities() { if (SelectionManager.hasSelection()) { print(" Delete Entities"); @@ -837,6 +882,10 @@ function handeMenuEvent(menuItem) { } } else if (menuItem == "Entity List...") { entityListTool.toggleVisible(); + } else if (menuItem == "Select All Entities In Box") { + selectAllEtitiesInCurrentSelectionBox(false); + } else if (menuItem == "Select All Entities Touching Box") { + selectAllEtitiesInCurrentSelectionBox(true); } tooltip.show(false); } From f49ed0951ee8694cf95e8ae94e3c8832b79b034a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 13 Mar 2015 12:04:43 -0700 Subject: [PATCH 04/13] Fix clickable areas --- examples/users.js | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/examples/users.js b/examples/users.js index d9da6c89ae..9604f1c248 100644 --- a/examples/users.js +++ b/examples/users.js @@ -106,6 +106,7 @@ var usersWindow = (function () { var displayText = "", myUsername, user, + userText, i; myUsername = GlobalServices.username; @@ -113,12 +114,13 @@ var usersWindow = (function () { for (i = 0; i < usersOnline.length; i += 1) { user = usersOnline[i]; if (user.username !== myUsername && user.online) { - usersOnline[i].usernameWidth = Overlays.textSize(windowPane2D, user.username).width; - linesOfUsers.push(i); - displayText += "\n" + user.username; + userText = user.username; if (user.location.root) { - displayText += " @ " + user.location.root.name; + userText += " @ " + user.location.root.name; } + usersOnline[i].textWidth = Overlays.textSize(windowPane2D, userText).width; + linesOfUsers.push(i); + displayText += "\n" + userText; } } @@ -253,7 +255,7 @@ var usersWindow = (function () { } if (0 <= lineClicked && lineClicked < linesOfUsers.length - && overlayX <= usersOnline[linesOfUsers[lineClicked]].usernameWidth) { + && 0 <= overlayX && overlayX <= usersOnline[linesOfUsers[lineClicked]].textWidth) { //print("Go to " + usersOnline[linesOfUsers[lineClicked]].username); location.goToUser(usersOnline[linesOfUsers[lineClicked]].username); } @@ -262,7 +264,7 @@ var usersWindow = (function () { visibilityChanged = false; for (i = 0; i < visibilityControls2D.length; i += 1) { // Don't need to test radioOverlay if it us under textOverlay. - if (clickedOverlay === visibilityControls2D[i].textOverlay) { + if (clickedOverlay === visibilityControls2D[i].textOverlay && event.x <= visibilityControls2D[i].optionWidth) { GlobalServices.findableBy = VISIBILITY_VALUES[i]; visibilityChanged = true; } @@ -286,7 +288,8 @@ var usersWindow = (function () { } function setUp() { - var textSizeOverlay; + var textSizeOverlay, + optionText; textSizeOverlay = Overlays.addOverlay("text", { font: WINDOW_FONT_2D, visible: false }); windowTextHeight = Math.floor(Overlays.textSize(textSizeOverlay, "1").height); @@ -351,6 +354,7 @@ var usersWindow = (function () { myVisibility = ""; } + optionText = "everyone"; visibilityControls2D = [{ radioOverlay: Overlays.addOverlay("image", { // Create first so that it is under textOverlay. x: WINDOW_MARGIN_2D, @@ -377,24 +381,34 @@ var usersWindow = (function () { color: WINDOW_HEADING_COLOR_2D, alpha: WINDOW_FOREGROUND_ALPHA_2D, backgroundAlpha: 0.0, - text: "everyone", + text: optionText, font: WINDOW_FONT_2D, visible: isVisible }), selected: myVisibility === VISIBILITY_VALUES[0] - } ]; + }]; + visibilityControls2D[0].optionWidth = WINDOW_MARGIN_2D + VISIBILITY_RADIO_SPACE + + Overlays.textSize(visibilityControls2D[0].textOverlay, optionText).width; + + optionText = "my friends"; visibilityControls2D[1] = { radioOverlay: Overlays.cloneOverlay(visibilityControls2D[0].radioOverlay), textOverlay: Overlays.cloneOverlay(visibilityControls2D[0].textOverlay), selected: myVisibility === VISIBILITY_VALUES[1] }; - Overlays.editOverlay(visibilityControls2D[1].textOverlay, { text: "my friends" }); + Overlays.editOverlay(visibilityControls2D[1].textOverlay, { text: optionText }); + visibilityControls2D[1].optionWidth = WINDOW_MARGIN_2D + VISIBILITY_RADIO_SPACE + + Overlays.textSize(visibilityControls2D[1].textOverlay, optionText).width; + + optionText = "no one"; visibilityControls2D[2] = { radioOverlay: Overlays.cloneOverlay(visibilityControls2D[0].radioOverlay), textOverlay: Overlays.cloneOverlay(visibilityControls2D[0].textOverlay), selected: myVisibility === VISIBILITY_VALUES[2] }; - Overlays.editOverlay(visibilityControls2D[2].textOverlay, { text: "no one" }); + Overlays.editOverlay(visibilityControls2D[2].textOverlay, { text: optionText }); + visibilityControls2D[2].optionWidth = WINDOW_MARGIN_2D + VISIBILITY_RADIO_SPACE + + Overlays.textSize(visibilityControls2D[2].textOverlay, optionText).width; updateVisibilityControls(); From 67b2d0c8ab2641bcc0e98719488d562a8d302cfd Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 13 Mar 2015 12:18:49 -0700 Subject: [PATCH 05/13] Trim text to fit in window --- examples/users.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/examples/users.js b/examples/users.js index 9604f1c248..dec141127e 100644 --- a/examples/users.js +++ b/examples/users.js @@ -107,6 +107,8 @@ var usersWindow = (function () { myUsername, user, userText, + textWidth, + maxTextWidth, i; myUsername = GlobalServices.username; @@ -118,7 +120,21 @@ var usersWindow = (function () { if (user.location.root) { userText += " @ " + user.location.root.name; } - usersOnline[i].textWidth = Overlays.textSize(windowPane2D, userText).width; + textWidth = Overlays.textSize(windowPane2D, userText).width; + + maxTextWidth = WINDOW_WIDTH_2D - 2 * WINDOW_MARGIN_2D; + if (textWidth > maxTextWidth) { + // Trim and append "..." to fit window width + maxTextWidth = maxTextWidth - Overlays.textSize(windowPane2D, "...").width; + while (textWidth > maxTextWidth) { + userText = userText.slice(0, -1); + textWidth = Overlays.textSize(windowPane2D, userText).width; + } + userText += "..."; + textWidth = Overlays.textSize(windowPane2D, userText).width; + } + + usersOnline[i].textWidth = textWidth; linesOfUsers.push(i); displayText += "\n" + userText; } From 76f474bff1e2472afc0b138e0c9e08af6a977a5b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 13 Mar 2015 14:48:33 -0700 Subject: [PATCH 06/13] Add hourglass image to loading svo overlay --- examples/edit.js | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index e7c8c897ac..ba918a3dd1 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -95,12 +95,24 @@ var isActive = false; var placingEntityID = null; -IMPORTING_SVO_OVERLAY_WIDTH = 130; +IMPORTING_SVO_OVERLAY_WIDTH = 144; IMPORTING_SVO_OVERLAY_HEIGHT = 30; -IMPORTING_SVO_OVERLAY_MARGIN = 6; -var importingSVOOverlay = Overlays.addOverlay("text", { +IMPORTING_SVO_OVERLAY_MARGIN = 5; +IMPORTING_SVO_OVERLAY_LEFT_MARGIN = 34; +var importingSVOImageOverlay = Overlays.addOverlay("image", { + imageURL: HIFI_PUBLIC_BUCKET + "images/hourglass.svg", + width: 20, + height: 20, + alpha: 1.0, + color: { red: 255, green: 255, blue: 255 }, + x: Window.innerWidth - IMPORTING_SVO_OVERLAY_WIDTH, + y: Window.innerHeight - IMPORTING_SVO_OVERLAY_HEIGHT, + visible: false, +}); +var importingSVOTextOverlay = Overlays.addOverlay("text", { font: { size: 14 }, text: "Importing SVO...", + leftMargin: IMPORTING_SVO_OVERLAY_LEFT_MARGIN, x: Window.innerWidth - IMPORTING_SVO_OVERLAY_WIDTH - IMPORTING_SVO_OVERLAY_MARGIN, y: Window.innerHeight - IMPORTING_SVO_OVERLAY_HEIGHT - IMPORTING_SVO_OVERLAY_MARGIN, width: IMPORTING_SVO_OVERLAY_WIDTH, @@ -769,7 +781,8 @@ Script.scriptEnding.connect(function() { selectionDisplay.cleanup(); Entities.setLightsArePickable(originalLightsArePickable); - Overlays.deleteOverlay(importingSVOOverlay); + Overlays.deleteOverlay(importingSVOImageOverlay); + Overlays.deleteOverlay(importingSVOTextOverlay); }); // Do some stuff regularly, like check for placement of various overlays @@ -842,7 +855,8 @@ function handeMenuEvent(menuItem) { } function importSVO(importURL) { - Overlays.editOverlay(importingSVOOverlay, { visible: true }); + Overlays.editOverlay(importingSVOTextOverlay, { visible: true }); + Overlays.editOverlay(importingSVOImageOverlay, { visible: true }); var success = Clipboard.importEntities(importURL); @@ -865,7 +879,8 @@ function importSVO(importURL) { Window.alert("There was an error importing the entity file."); } - Overlays.editOverlay(importingSVOOverlay, { visible: false }); + Overlays.editOverlay(importingSVOTextOverlay, { visible: false }); + Overlays.editOverlay(importingSVOImageOverlay, { visible: false }); } Window.svoImportRequested.connect(importSVO); From b15fd2ef944bfa12fe2c440474bb17bababad8a5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 15 Mar 2015 08:08:39 -0700 Subject: [PATCH 07/13] compatibility and other fixes for obj reader --- libraries/fbx/src/OBJReader.cpp | 272 +++++++++++++++++++++++++++----- libraries/fbx/src/OBJReader.h | 1 + 2 files changed, 233 insertions(+), 40 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 4f0f1246d2..b98ea961f9 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -31,6 +31,7 @@ public: }; int nextToken(); const QByteArray& getDatum() const { return _datum; } + bool isNextTokenFloat(); void skipLine() { _device->readLine(); } void pushBackToken(int token) { _pushedBackToken = token; } void ungetChar(char ch) { _device->ungetChar(ch); } @@ -91,14 +92,32 @@ int OBJTokenizer::nextToken() { return NO_TOKEN; } +bool OBJTokenizer::isNextTokenFloat() { + if (nextToken() != OBJTokenizer::DATUM_TOKEN) { + return false; + } + QByteArray token = getDatum(); + pushBackToken(OBJTokenizer::DATUM_TOKEN); + bool ok; + token.toFloat(&ok); + return ok; +} -bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping, FBXGeometry &geometry) { +bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping, + FBXGeometry &geometry, QVector& faceNormals, QVector& faceNormalIndexes) { FBXMesh &mesh = geometry.meshes[0]; mesh.parts.append(FBXMeshPart()); FBXMeshPart &meshPart = mesh.parts.last(); bool sawG = false; bool result = true; + meshPart.diffuseColor = glm::vec3(1, 1, 1); + meshPart.specularColor = glm::vec3(1, 1, 1); + meshPart.emissiveColor = glm::vec3(0, 0, 0); + meshPart.emissiveParams = glm::vec2(0, 1); + meshPart.shininess = 40; + meshPart.opacity = 1; + meshPart.materialID = QString("dontknow") + QString::number(mesh.parts.count()); meshPart.opacity = 1.0; meshPart._material = model::MaterialPointer(new model::Material()); @@ -131,11 +150,27 @@ bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping, FBXGeom break; } float x = std::stof(tokenizer.getDatum().data()); - // notice the order of z and y -- in OBJ files, up is the 3rd value + + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { + break; + } + float y = std::stof(tokenizer.getDatum().data()); + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } float z = std::stof(tokenizer.getDatum().data()); + + while (tokenizer.isNextTokenFloat()) { + // the spec(s) get(s) vague here. might be w, might be a color... chop it off. + tokenizer.nextToken(); + } + mesh.vertices.append(glm::vec3(x, y, z)); + } else if (token == "vn") { + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { + break; + } + float x = std::stof(tokenizer.getDatum().data()); if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } @@ -143,35 +178,74 @@ bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping, FBXGeom if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } - // the spec gets vague here. might be w, might be a color... chop it off. - tokenizer.skipLine(); - mesh.vertices.append(glm::vec3(x, y, z)); - mesh.colors.append(glm::vec3(1, 1, 1)); + float z = std::stof(tokenizer.getDatum().data()); + + while (tokenizer.isNextTokenFloat()) { + // the spec gets vague here. might be w + tokenizer.nextToken(); + } + faceNormals.append(glm::vec3(x, y, z)); } else if (token == "f") { // a face can have 3 or more vertices QVector indices; + QVector normalIndices; while (true) { - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { goto done; } - try { - int vertexIndex = std::stoi(tokenizer.getDatum().data()); - // negative indexes count backward from the current end of the vertex list - vertexIndex = (vertexIndex >= 0 ? vertexIndex : mesh.vertices.count() + vertexIndex + 1); - // obj index is 1 based - assert(vertexIndex >= 1); - indices.append(vertexIndex - 1); + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { + if (indices.count() == 0) { + goto done; + } + break; } - catch(const std::exception& e) { - // wasn't a number, but it back. + // faces can be: + // vertex-index + // vertex-index/texture-index + // vertex-index/texture-index/surface-normal-index + + QByteArray token = tokenizer.getDatum(); + QList parts = token.split('/'); + assert(parts.count() >= 1); + assert(parts.count() <= 3); + QByteArray vertIndexBA = parts[ 0 ]; + + bool ok; + int vertexIndex = vertIndexBA.toInt(&ok); + if (!ok) { + // it wasn't #/#/#, put it back and exit this loop. tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN); break; } + + // if (parts.count() > 1) { + // QByteArray textureIndexBA = parts[ 1 ]; + // } + + if (parts.count() > 2) { + QByteArray normalIndexBA = parts[ 2 ]; + bool ok; + int normalIndex = normalIndexBA.toInt(&ok); + if (ok) { + normalIndices.append(normalIndex - 1); + } + } + + // negative indexes count backward from the current end of the vertex list + vertexIndex = (vertexIndex >= 0 ? vertexIndex : mesh.vertices.count() + vertexIndex + 1); + // obj index is 1 based + assert(vertexIndex >= 1); + indices.append(vertexIndex - 1); } if (indices.count() == 3) { - // flip these around (because of the y/z swap above) so our triangles face outward meshPart.triangleIndices.append(indices[0]); - meshPart.triangleIndices.append(indices[2]); meshPart.triangleIndices.append(indices[1]); + meshPart.triangleIndices.append(indices[2]); + if (normalIndices.count() == 3) { + faceNormalIndexes.append(normalIndices[0]); + faceNormalIndexes.append(normalIndices[1]); + faceNormalIndexes.append(normalIndices[2]); + } else { + // hmm. + } } else if (indices.count() == 4) { meshPart.quadIndices << indices; } else { @@ -205,6 +279,10 @@ FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping) { FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { FBXGeometry geometry; OBJTokenizer tokenizer(device); + QVector faceNormalIndexes; + QVector faceNormals; + + faceNormalIndexes.clear(); geometry.meshExtents.reset(); geometry.meshes.append(FBXMesh()); @@ -216,7 +294,7 @@ FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { // add a new meshPart to the geometry's single mesh. bool success = true; while (success) { - success = parseOBJGroup(tokenizer, mapping, geometry); + success = parseOBJGroup(tokenizer, mapping, geometry, faceNormals, faceNormalIndexes); } FBXMesh &mesh = geometry.meshes[0]; @@ -235,25 +313,41 @@ FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { geometry.joints[0].boneRadius = 0; geometry.joints[0].translation = glm::vec3(0, 0, 0); // geometry.joints[0].preTransform = ; - geometry.joints[0].preRotation = glm::quat(0, 0, 0, 1); - geometry.joints[0].rotation = glm::quat(0, 0, 0, 1); - geometry.joints[0].postRotation = glm::quat(0, 0, 0, 1); + geometry.joints[0].preRotation = glm::quat(1, 0, 0, 0); + geometry.joints[0].rotation = glm::quat(1, 0, 0, 0); + geometry.joints[0].postRotation = glm::quat(1, 0, 0, 0); // geometry.joints[0].postTransform = ; // geometry.joints[0].transform = ; geometry.joints[0].rotationMin = glm::vec3(0, 0, 0); geometry.joints[0].rotationMax = glm::vec3(0, 0, 0); - geometry.joints[0].inverseDefaultRotation = glm::quat(0, 0, 0, 1); - geometry.joints[0].inverseBindRotation = glm::quat(0, 0, 0, 1); + geometry.joints[0].inverseDefaultRotation = glm::quat(1, 0, 0, 0); + geometry.joints[0].inverseBindRotation = glm::quat(1, 0, 0, 0); // geometry.joints[0].bindTransform = ; geometry.joints[0].name = "OBJ"; geometry.joints[0].shapePosition = glm::vec3(0, 0, 0); - geometry.joints[0].shapeRotation = glm::quat(0, 0, 0, 1); + geometry.joints[0].shapeRotation = glm::quat(1, 0, 0, 0); geometry.joints[0].shapeType = SPHERE_SHAPE; - geometry.joints[0].isSkeletonJoint = false; + geometry.joints[0].isSkeletonJoint = true; + + geometry.jointIndices["x"] = 1; + + FBXCluster cluster; + cluster.jointIndex = 0; + cluster.inverseBindMatrix = glm::mat4(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); + mesh.clusters.append(cluster); + + // The OBJ format has normals for faces. The FBXGeometry structure has normals for points. + // run through all the faces, look-up (or determine) a normal and set the normal for the points + // that make up each face. + QVector pointNormalsSums; + QVector pointNormalsCounts; - // add bogus normal data for this mesh mesh.normals.fill(glm::vec3(0,0,0), mesh.vertices.count()); - mesh.tangents.fill(glm::vec3(0,0,0), mesh.vertices.count()); + pointNormalsSums.fill(glm::vec3(0,0,0), mesh.vertices.count()); + pointNormalsCounts.fill(0, mesh.vertices.count()); foreach (FBXMeshPart meshPart, mesh.parts) { int triCount = meshPart.triangleIndices.count() / 3; @@ -262,21 +356,45 @@ FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { int p1Index = meshPart.triangleIndices[i*3+1]; int p2Index = meshPart.triangleIndices[i*3+2]; - glm::vec3 p0 = mesh.vertices[p0Index]; - glm::vec3 p1 = mesh.vertices[p1Index]; - glm::vec3 p2 = mesh.vertices[p2Index]; + assert(p0Index < mesh.vertices.count()); + assert(p1Index < mesh.vertices.count()); + assert(p2Index < mesh.vertices.count()); - glm::vec3 n = glm::cross(p1 - p0, p2 - p0); - glm::vec3 t = glm::cross(p2 - p0, n); + glm::vec3 n0, n1, n2; + if (i < faceNormalIndexes.count()) { + int n0Index = faceNormalIndexes[i*3]; + int n1Index = faceNormalIndexes[i*3+1]; + int n2Index = faceNormalIndexes[i*3+2]; + n0 = faceNormals[n0Index]; + n1 = faceNormals[n1Index]; + n2 = faceNormals[n2Index]; + } else { + // We didn't read normals, add bogus normal data for this face + glm::vec3 p0 = mesh.vertices[p0Index]; + glm::vec3 p1 = mesh.vertices[p1Index]; + glm::vec3 p2 = mesh.vertices[p2Index]; + n0 = glm::cross(p1 - p0, p2 - p0); + n1 = n0; + n2 = n0; + } - mesh.normals[p0Index] = n; - mesh.normals[p1Index] = n; - mesh.normals[p2Index] = n; - - mesh.tangents[p0Index] = t; - mesh.tangents[p1Index] = t; - mesh.tangents[p2Index] = t; + // we sum up the normal for each point and then divide by the count to get an average + pointNormalsSums[p0Index] += n0; + pointNormalsSums[p1Index] += n1; + pointNormalsSums[p2Index] += n2; + pointNormalsCounts[p0Index]++; + pointNormalsCounts[p1Index]++; + pointNormalsCounts[p2Index]++; } + + int vertCount = mesh.vertices.count(); + for (int i = 0; i < vertCount; i++) { + if (pointNormalsCounts[i] > 0) { + mesh.normals[i] = glm::normalize(pointNormalsSums[i] / (float)(pointNormalsCounts[i])); + } + } + + // XXX do same normal calculation for quadCount } } catch(const std::exception& e) { @@ -285,3 +403,77 @@ FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { return geometry; } + + + +void fbxDebugDump(const FBXGeometry& fbxgeo) { + qDebug() << "---------------- fbxGeometry ----------------"; + qDebug() << " hasSkeletonJoints =" << fbxgeo.hasSkeletonJoints; + qDebug() << " offset =" << fbxgeo.offset; + qDebug() << " attachments.count() = " << fbxgeo.attachments.count(); + qDebug() << " meshes.count() =" << fbxgeo.meshes.count(); + foreach (FBXMesh mesh, fbxgeo.meshes) { + qDebug() << " vertices.count() =" << mesh.vertices.count(); + qDebug() << " normals.count() =" << mesh.normals.count(); + if (mesh.normals.count() == mesh.vertices.count()) { + for (int i = 0; i < mesh.normals.count(); i++) { + qDebug() << " " << mesh.vertices[ i ] << mesh.normals[ i ]; + } + } + qDebug() << " tangents.count() =" << mesh.tangents.count(); + qDebug() << " colors.count() =" << mesh.colors.count(); + qDebug() << " texCoords.count() =" << mesh.texCoords.count(); + qDebug() << " texCoords1.count() =" << mesh.texCoords1.count(); + qDebug() << " clusterIndices.count() =" << mesh.clusterIndices.count(); + qDebug() << " clusterWeights.count() =" << mesh.clusterWeights.count(); + qDebug() << " meshExtents =" << mesh.meshExtents; + qDebug() << " modelTransform =" << mesh.modelTransform; + qDebug() << " parts.count() =" << mesh.parts.count(); + foreach (FBXMeshPart meshPart, mesh.parts) { + qDebug() << " quadIndices.count() =" << meshPart.quadIndices.count(); + qDebug() << " triangleIndices.count() =" << meshPart.triangleIndices.count(); + qDebug() << " diffuseColor =" << meshPart.diffuseColor; + qDebug() << " specularColor =" << meshPart.specularColor; + qDebug() << " emissiveColor =" << meshPart.emissiveColor; + qDebug() << " emissiveParams =" << meshPart.emissiveParams; + qDebug() << " shininess =" << meshPart.shininess; + qDebug() << " opacity =" << meshPart.opacity; + qDebug() << " materialID =" << meshPart.materialID; + } + qDebug() << " clusters.count() =" << mesh.clusters.count(); + foreach (FBXCluster cluster, mesh.clusters) { + qDebug() << " jointIndex =" << cluster.jointIndex; + qDebug() << " inverseBindMatrix =" << cluster.inverseBindMatrix; + } + } + + qDebug() << " jointIndices =" << fbxgeo.jointIndices; + qDebug() << " joints.count() =" << fbxgeo.joints.count(); + + foreach (FBXJoint joint, fbxgeo.joints) { + qDebug() << " isFree =" << joint.isFree; + qDebug() << " freeLineage" << joint.freeLineage; + qDebug() << " parentIndex" << joint.parentIndex; + qDebug() << " distanceToParent" << joint.distanceToParent; + qDebug() << " boneRadius" << joint.boneRadius; + qDebug() << " translation" << joint.translation; + qDebug() << " preTransform" << joint.preTransform; + qDebug() << " preRotation" << joint.preRotation; + qDebug() << " rotation" << joint.rotation; + qDebug() << " postRotation" << joint.postRotation; + qDebug() << " postTransform" << joint.postTransform; + qDebug() << " transform" << joint.transform; + qDebug() << " rotationMin" << joint.rotationMin; + qDebug() << " rotationMax" << joint.rotationMax; + qDebug() << " inverseDefaultRotation" << joint.inverseDefaultRotation; + qDebug() << " inverseBindRotation" << joint.inverseBindRotation; + qDebug() << " bindTransform" << joint.bindTransform; + qDebug() << " name" << joint.name; + qDebug() << " shapePosition" << joint.shapePosition; + qDebug() << " shapeRotation" << joint.shapeRotation; + qDebug() << " shapeType" << joint.shapeType; + qDebug() << " isSkeletonJoint" << joint.isSkeletonJoint; + } + + qDebug() << "\n"; +} diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h index 2ff55a9a61..8c7aa1aba6 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJReader.h @@ -4,3 +4,4 @@ FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping); FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping); +void fbxDebugDump(const FBXGeometry& fbxgeo); From d074cec13525d7ba1f473961c5fc9da985f6328f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 15 Mar 2015 08:14:25 -0700 Subject: [PATCH 08/13] fix obj writer in vhacd util --- tools/vhacd/src/VHACDUtilApp.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tools/vhacd/src/VHACDUtilApp.cpp b/tools/vhacd/src/VHACDUtilApp.cpp index 958a91dbfe..b4c141acae 100644 --- a/tools/vhacd/src/VHACDUtilApp.cpp +++ b/tools/vhacd/src/VHACDUtilApp.cpp @@ -50,15 +50,13 @@ bool writeOBJ(QString outFileName, QVector>& for (unsigned int i = 0; i < hull.m_nPoints; i++) { out << "v "; out << formatFloat(hull.m_points[i*3]) << " "; - // swap y and z because up is 3rd value in OBJ - out << formatFloat(hull.m_points[i*3+2]) << " "; - out << formatFloat(hull.m_points[i*3+1]) << "\n"; + out << formatFloat(hull.m_points[i*3+1]) << " "; + out << formatFloat(hull.m_points[i*3+2]) << "\n"; } for (unsigned int i = 0; i < hull.m_nTriangles; i++) { out << "f "; - // change order to flip normal (due to swapping y and z, above) - out << hull.m_triangles[i*3+1] + 1 + pointStartOffset << " "; out << hull.m_triangles[i*3] + 1 + pointStartOffset << " "; + out << hull.m_triangles[i*3+1] + 1 + pointStartOffset << " "; out << hull.m_triangles[i*3+2] + 1 + pointStartOffset << "\n"; } out << "\n"; From af10c2274b463289efffecac40a7ccde0c48ff0b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 15 Mar 2015 08:24:49 -0700 Subject: [PATCH 09/13] remove stray carriage returns --- libraries/gpu/src/gpu/Batch.h | 114 +++++++++++++++++----------------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 54a6339ae3..84358b7ae1 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -25,14 +25,14 @@ #if defined(NSIGHT_FOUND) #include "nvToolsExt.h" - class ProfileRange { - public: - ProfileRange(const char *name) { - nvtxRangePush(name); - } - ~ProfileRange() { - nvtxRangePop(); - } + class ProfileRange { + public: + ProfileRange(const char *name) { + nvtxRangePush(name); + } + ~ProfileRange() { + nvtxRangePop(); + } }; #define PROFILE_RANGE(name) ProfileRange profileRangeThis(name); @@ -114,17 +114,17 @@ public: // For now, instead of calling the raw glCall, use the equivalent call on the batch so the call is beeing recorded // THe implementation of these functions is in GLBackend.cpp - void _glEnable(GLenum cap); - void _glDisable(GLenum cap); - + void _glEnable(GLenum cap); + void _glDisable(GLenum cap); + void _glEnableClientState(GLenum array); void _glDisableClientState(GLenum array); void _glCullFace(GLenum mode); void _glAlphaFunc(GLenum func, GLclampf ref); - void _glDepthFunc(GLenum func); - void _glDepthMask(GLboolean flag); + void _glDepthFunc(GLenum func); + void _glDepthMask(GLboolean flag); void _glDepthRange(GLclampd zNear, GLclampd zFar); void _glBindBuffer(GLenum target, GLuint buffer); @@ -138,14 +138,14 @@ public: void _glUniform1f(GLint location, GLfloat v0); void _glUniform2f(GLint location, GLfloat v0, GLfloat v1); void _glUniform4fv(GLint location, GLsizei count, const GLfloat* value); - void _glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void _glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); - void _glDrawArrays(GLenum mode, GLint first, GLsizei count); + void _glDrawArrays(GLenum mode, GLint first, GLsizei count); void _glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); - - void _glColorPointer(GLint size, GLenum type, GLsizei stride, const void *pointer); - void _glNormalPointer(GLenum type, GLsizei stride, const void *pointer); - void _glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const void *pointer); + + void _glColorPointer(GLint size, GLenum type, GLsizei stride, const void *pointer); + void _glNormalPointer(GLenum type, GLsizei stride, const void *pointer); + void _glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const void *pointer); void _glVertexPointer(GLint size, GLenum type, GLsizei stride, const void *pointer); void _glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); @@ -175,44 +175,44 @@ public: // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long // term strategy is to get rid of any GL calls in favor of the HIFI GPU API - COMMAND_glEnable, - COMMAND_glDisable, - - COMMAND_glEnableClientState, - COMMAND_glDisableClientState, - - COMMAND_glCullFace, - COMMAND_glAlphaFunc, - - COMMAND_glDepthFunc, - COMMAND_glDepthMask, - COMMAND_glDepthRange, - - COMMAND_glBindBuffer, - - COMMAND_glBindTexture, - COMMAND_glActiveTexture, - - COMMAND_glDrawBuffers, - - COMMAND_glUseProgram, - COMMAND_glUniform1f, - COMMAND_glUniform2f, - COMMAND_glUniform4fv, - COMMAND_glUniformMatrix4fv, - - COMMAND_glDrawArrays, - COMMAND_glDrawRangeElements, - - COMMAND_glColorPointer, - COMMAND_glNormalPointer, - COMMAND_glTexCoordPointer, - COMMAND_glVertexPointer, - - COMMAND_glVertexAttribPointer, - COMMAND_glEnableVertexAttribArray, - COMMAND_glDisableVertexAttribArray, - + COMMAND_glEnable, + COMMAND_glDisable, + + COMMAND_glEnableClientState, + COMMAND_glDisableClientState, + + COMMAND_glCullFace, + COMMAND_glAlphaFunc, + + COMMAND_glDepthFunc, + COMMAND_glDepthMask, + COMMAND_glDepthRange, + + COMMAND_glBindBuffer, + + COMMAND_glBindTexture, + COMMAND_glActiveTexture, + + COMMAND_glDrawBuffers, + + COMMAND_glUseProgram, + COMMAND_glUniform1f, + COMMAND_glUniform2f, + COMMAND_glUniform4fv, + COMMAND_glUniformMatrix4fv, + + COMMAND_glDrawArrays, + COMMAND_glDrawRangeElements, + + COMMAND_glColorPointer, + COMMAND_glNormalPointer, + COMMAND_glTexCoordPointer, + COMMAND_glVertexPointer, + + COMMAND_glVertexAttribPointer, + COMMAND_glEnableVertexAttribArray, + COMMAND_glDisableVertexAttribArray, + COMMAND_glColor4f, NUM_COMMANDS, From bd85179d8251c77ecd15c61ce3a3de77fb589cf3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 15 Mar 2015 08:24:59 -0700 Subject: [PATCH 10/13] suppress a compiler warning --- libraries/entities/src/LightEntityItem.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index 62a44c7e21..c7a4ef79d7 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -111,6 +111,8 @@ int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY(PROP_EXPONENT, float, _exponent); READ_ENTITY_PROPERTY(PROP_CUTOFF, float, _cutoff); + + (void) ignoredAttenuation; // suppress compiler warning } else { READ_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, bool, _isSpotlight); READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color); From c6167f689348e2812da4e3388699cb4db043ff25 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 16 Mar 2015 14:35:17 +0100 Subject: [PATCH 11/13] CR --- libraries/entities/src/EntityScriptingInterface.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index f87ea2cd29..2585b5d33e 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -204,8 +204,7 @@ EntityItemID EntityScriptingInterface::findClosestEntity(const glm::vec3& center const EntityItem* closestEntity = _entityTree->findClosestEntity(center, radius); _entityTree->unlock(); if (closestEntity) { - result.id = closestEntity->getID(); - result.isKnownID = true; + result = closestEntity->getEntityItemID(); } } return result; @@ -229,8 +228,7 @@ QVector EntityScriptingInterface::findEntities(const glm::vec3& ce _entityTree->unlock(); foreach (const EntityItem* entity, entities) { - EntityItemID thisEntityItemID(entity->getID(), UNKNOWN_ENTITY_TOKEN, true); - result << thisEntityItemID; + result << entity->getEntityItemID(); } } return result; @@ -246,8 +244,7 @@ QVector EntityScriptingInterface::findEntitiesInBox(const glm::vec _entityTree->unlock(); foreach (const EntityItem* entity, entities) { - EntityItemID thisEntityItemID(entity->getID(), UNKNOWN_ENTITY_TOKEN, true); - result << thisEntityItemID; + result << entity->getEntityItemID(); } } return result; From c421adaf5882eb8f4833457369c7e6f8b72542f0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 16 Mar 2015 16:27:33 +0100 Subject: [PATCH 12/13] Fix unresolve merge conflict --- examples/edit.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index ae2833be01..72938e5ed4 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -933,15 +933,12 @@ function handeMenuEvent(menuItem) { } } else if (menuItem == "Entity List...") { entityListTool.toggleVisible(); -<<<<<<< HEAD } else if (menuItem == "Select All Entities In Box") { selectAllEtitiesInCurrentSelectionBox(false); } else if (menuItem == "Select All Entities Touching Box") { selectAllEtitiesInCurrentSelectionBox(true); -======= } else if (menuItem == MENU_SHOW_LIGHTS_IN_EDIT_MODE) { lightOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_IN_EDIT_MODE)); ->>>>>>> dfd39ca1e14bb2198b12374b6bc863b3c27f673c } tooltip.show(false); } From a2bc34ced9b5e547fe39d0188e79b2f3f0ab66e4 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 16 Mar 2015 10:03:55 -0700 Subject: [PATCH 13/13] fix attempt to avoid normalizing a zero length vector, other adjustments to respond to code review --- libraries/fbx/src/OBJReader.cpp | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index b98ea961f9..0aaf8772a2 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -307,25 +307,14 @@ FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { geometry.joints.resize(1); geometry.joints[0].isFree = false; - // geometry.joints[0].freeLineage; geometry.joints[0].parentIndex = -1; geometry.joints[0].distanceToParent = 0; geometry.joints[0].boneRadius = 0; geometry.joints[0].translation = glm::vec3(0, 0, 0); - // geometry.joints[0].preTransform = ; - geometry.joints[0].preRotation = glm::quat(1, 0, 0, 0); - geometry.joints[0].rotation = glm::quat(1, 0, 0, 0); - geometry.joints[0].postRotation = glm::quat(1, 0, 0, 0); - // geometry.joints[0].postTransform = ; - // geometry.joints[0].transform = ; geometry.joints[0].rotationMin = glm::vec3(0, 0, 0); geometry.joints[0].rotationMax = glm::vec3(0, 0, 0); - geometry.joints[0].inverseDefaultRotation = glm::quat(1, 0, 0, 0); - geometry.joints[0].inverseBindRotation = glm::quat(1, 0, 0, 0); - // geometry.joints[0].bindTransform = ; geometry.joints[0].name = "OBJ"; geometry.joints[0].shapePosition = glm::vec3(0, 0, 0); - geometry.joints[0].shapeRotation = glm::quat(1, 0, 0, 0); geometry.joints[0].shapeType = SPHERE_SHAPE; geometry.joints[0].isSkeletonJoint = true; @@ -343,11 +332,9 @@ FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { // run through all the faces, look-up (or determine) a normal and set the normal for the points // that make up each face. QVector pointNormalsSums; - QVector pointNormalsCounts; mesh.normals.fill(glm::vec3(0,0,0), mesh.vertices.count()); pointNormalsSums.fill(glm::vec3(0,0,0), mesh.vertices.count()); - pointNormalsCounts.fill(0, mesh.vertices.count()); foreach (FBXMeshPart meshPart, mesh.parts) { int triCount = meshPart.triangleIndices.count() / 3; @@ -382,15 +369,13 @@ FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { pointNormalsSums[p0Index] += n0; pointNormalsSums[p1Index] += n1; pointNormalsSums[p2Index] += n2; - pointNormalsCounts[p0Index]++; - pointNormalsCounts[p1Index]++; - pointNormalsCounts[p2Index]++; } int vertCount = mesh.vertices.count(); for (int i = 0; i < vertCount; i++) { - if (pointNormalsCounts[i] > 0) { - mesh.normals[i] = glm::normalize(pointNormalsSums[i] / (float)(pointNormalsCounts[i])); + float length = glm::length(pointNormalsSums[i]); + if (length > FLT_EPSILON) { + mesh.normals[i] = glm::normalize(pointNormalsSums[i]); } }