From 7f33762aab74f937b76c08f8788ec7622865809f Mon Sep 17 00:00:00 2001 From: stojce Date: Thu, 6 Mar 2014 01:49:27 +0100 Subject: [PATCH 01/44] fixed invalid define guard --- interface/src/starfield/Controller.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/starfield/Controller.h b/interface/src/starfield/Controller.h index c5ade48442..5403d2fb75 100755 --- a/interface/src/starfield/Controller.h +++ b/interface/src/starfield/Controller.h @@ -8,7 +8,7 @@ // #ifndef __interface__starfield__Controller__ -#define __interface__starfield__Confroller__ +#define __interface__starfield__Controller__ #include From 438b07290785f1617fa471563b5ef138f4140512 Mon Sep 17 00:00:00 2001 From: stojce Date: Thu, 6 Mar 2014 02:29:12 +0100 Subject: [PATCH 02/44] editVoxels - importing voxels --- examples/editVoxels.js | 92 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 86 insertions(+), 6 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 9a014639f0..24ae2a7330 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -26,6 +26,10 @@ var PIXELS_PER_EXTRUDE_VOXEL = 16; var WHEEL_PIXELS_PER_SCALE_CHANGE = 100; var MAX_VOXEL_SCALE = 1.0; var MIN_VOXEL_SCALE = 1.0 / Math.pow(2.0, 8.0); +var WHITE_COLOR = { red: 255, green: 255, blue: 255 }; + +var MAX_PASTE_VOXEL_SCALE = 256; +var MIN_PASTE_VOXEL_SCALE = .256; var zFightingSizeAdjust = 0.002; // used to adjust preview voxels to prevent z fighting var previewLineWidth = 1.5; @@ -199,6 +203,8 @@ var voxelToolAt = 0; var recolorToolAt = 1; var eyedropperToolAt = 2; +var pasteModeColor = { red: 132, green: 61, blue: 255 }; + var voxelTool = Overlays.addOverlay("image", { x: 0, y: 0, width: toolWidth, height: toolHeight, subImage: { x: 0, y: toolHeight, width: toolWidth, height: toolHeight }, @@ -262,7 +268,7 @@ var thumb = Overlays.addOverlay("image", { visible: false }); -var pointerVoxelScale = 0; // this is the voxel scale used for click to add or delete +var pointerVoxelScale = Math.floor(MAX_VOXEL_SCALE + MIN_VOXEL_SCALE) / 2; // this is the voxel scale used for click to add or delete var pointerVoxelScaleSet = false; // if voxel scale has not yet been set, we use the intersection size var pointerVoxelScaleSteps = 8; // the number of slider position steps @@ -308,6 +314,23 @@ function setAudioPosition() { audioOptions.position = Vec3.sum(camera, forwardVector); } +function getNewPasteVoxel(pickRay) { + + var voxelSize = MIN_PASTE_VOXEL_SCALE + (MAX_PASTE_VOXEL_SCALE - MIN_PASTE_VOXEL_SCALE) * pointerVoxelScale - 1; + var distance = 1 + 30 * voxelSize / MAX_PASTE_VOXEL_SCALE; + var origin = { x: pickRay.direction.x * NEW_VOXEL_DISTANCE_FROM_CAMERA + voxelSize, y: pickRay.direction.y, z: pickRay.direction.z }; + + origin.x += pickRay.origin.x; + origin.y += pickRay.origin.y; + origin.z += pickRay.origin.z; + + origin.x -= voxelSize / 2; + origin.y -= voxelSize / 2; + origin.z -= voxelSize / 2; + + return {origin: origin, voxelSize: voxelSize}; +} + function getNewVoxelPosition() { var camera = Camera.getPosition(); var forwardVector = Quat.getFront(MyAvatar.orientation); @@ -337,6 +360,7 @@ var trackAsOrbitOrPan = false; var voxelToolSelected = true; var recolorToolSelected = false; var eyedropperToolSelected = false; +var pasteMode = false; function playRandomAddSound(audioOptions) { if (Math.random() < 0.33) { @@ -523,6 +547,38 @@ function showPreviewVoxel() { function showPreviewLines() { var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY); + + if (pasteMode) { // free voxel pasting + + Overlays.editOverlay(voxelPreview, { visible: false }); + Overlays.editOverlay(linePreviewLeft, { visible: false }); + + var pasteVoxel = getNewPasteVoxel(pickRay); + + // X axis + Overlays.editOverlay(linePreviewBottom, { + position: pasteVoxel.origin, + end: {x: pasteVoxel.origin.x + pasteVoxel.voxelSize, y: pasteVoxel.origin.y, z: pasteVoxel.origin.z }, + visible: true + }); + + // Y axis + Overlays.editOverlay(linePreviewRight, { + position: pasteVoxel.origin, + end: {x: pasteVoxel.origin.x, y: pasteVoxel.origin.y + pasteVoxel.voxelSize, z: pasteVoxel.origin.z }, + visible: true + }); + + // Z axis + Overlays.editOverlay(linePreviewTop, { + position: pasteVoxel.origin, + end: {x: pasteVoxel.origin.x, y: pasteVoxel.origin.y, z: pasteVoxel.origin.z - pasteVoxel.voxelSize }, + visible: true + }); + + return; + } + var intersection = Voxels.findRayIntersection(pickRay); if (intersection.intersects) { @@ -617,6 +673,8 @@ function trackKeyReleaseEvent(event) { if (editToolsOn) { if (event.text == "ESC") { pointerVoxelScaleSet = false; + pasteMode = false; + moveTools(); } if (event.text == "-") { thumbX -= thumbDeltaPerStep; @@ -821,6 +879,15 @@ function mousePressEvent(event) { var pickRay = Camera.computePickRay(event.x, event.y); var intersection = Voxels.findRayIntersection(pickRay); audioOptions.position = Vec3.sum(pickRay.origin, pickRay.direction); + + if (pasteMode) { + var pasteVoxel = getNewPasteVoxel(pickRay); + Clipboard.pasteVoxel(pasteVoxel.origin.x, pasteVoxel.origin.y, pasteVoxel.origin.z, pasteVoxel.voxelSize); + pasteMode = false; + moveTools(); + return; + } + if (intersection.intersects) { // if the user hasn't updated the if (!pointerVoxelScaleSet) { @@ -974,21 +1041,28 @@ function cleanupMenus() { function menuItemEvent(menuItem) { // handle clipboard items - if (selectToolSelected) { + if (editToolsOn) { + var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY); var intersection = Voxels.findRayIntersection(pickRay); selectedVoxel = calculateVoxelFromIntersection(intersection,"select"); if (menuItem == "Copy") { print("copying..."); Clipboard.copyVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + pasteMode = true; + moveTools(); } if (menuItem == "Cut") { print("cutting..."); Clipboard.cutVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + pasteMode = true; + moveTools(); } if (menuItem == "Paste") { print("pasting..."); Clipboard.pasteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + pasteMode = false; + moveTools(); } if (menuItem == "Delete") { print("deleting..."); @@ -1002,6 +1076,8 @@ function menuItemEvent(menuItem) { if (menuItem == "Import Voxels") { print("import"); Clipboard.importVoxels(); + pasteMode = true; + moveTools(); } if (menuItem == "Nudge") { print("nudge"); @@ -1156,19 +1232,23 @@ function moveTools() { recolorToolOffset = 1, eyedropperToolOffset = 1; - if (trackAsRecolor || recolorToolSelected) { + var voxelToolColor = WHITE_COLOR; + + if (recolorToolSelected) { recolorToolOffset = 2; - } else if (trackAsEyedropper || eyedropperToolSelected) { + } else if (eyedropperToolSelected) { eyedropperToolOffset = 2; - } else if (trackAsOrbitOrPan) { - // nothing gets selected in this case... } else { + if (pasteMode) { + voxelToolColor = pasteModeColor; + } voxelToolOffset = 2; } Overlays.editOverlay(voxelTool, { subImage: { x: 0, y: toolHeight * voxelToolOffset, width: toolWidth, height: toolHeight }, x: toolsX, y: toolsY + ((toolHeight + toolVerticalSpacing) * voxelToolAt), width: toolWidth, height: toolHeight, + color: voxelToolColor, visible: editToolsOn }); From dbef17db597bac9b735c52717492be7af28e60d8 Mon Sep 17 00:00:00 2001 From: stojce Date: Thu, 6 Mar 2014 22:42:34 +0100 Subject: [PATCH 03/44] code style --- examples/editVoxels.js | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index c4694df5f8..8197f4f801 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -316,19 +316,18 @@ function setAudioPosition() { function getNewPasteVoxel(pickRay) { - var voxelSize = MIN_PASTE_VOXEL_SCALE + (MAX_PASTE_VOXEL_SCALE - MIN_PASTE_VOXEL_SCALE) * pointerVoxelScale - 1; - var distance = 1 + 30 * voxelSize / MAX_PASTE_VOXEL_SCALE; - var origin = { x: pickRay.direction.x * NEW_VOXEL_DISTANCE_FROM_CAMERA + voxelSize, y: pickRay.direction.y, z: pickRay.direction.z }; + var voxelSize = MIN_PASTE_VOXEL_SCALE + (MAX_PASTE_VOXEL_SCALE - MIN_PASTE_VOXEL_SCALE) * pointerVoxelScale - 1; + var origin = { x: pickRay.direction.x, y: pickRay.direction.y, z: pickRay.direction.z }; - origin.x += pickRay.origin.x; - origin.y += pickRay.origin.y; - origin.z += pickRay.origin.z; + origin.x += pickRay.origin.x; + origin.y += pickRay.origin.y; + origin.z += pickRay.origin.z; + + origin.x -= voxelSize / 2; + origin.y -= voxelSize / 2; + origin.z += voxelSize / 2; - origin.x -= voxelSize / 2; - origin.y -= voxelSize / 2; - origin.z -= voxelSize / 2; - - return {origin: origin, voxelSize: voxelSize}; + return {origin: origin, voxelSize: voxelSize}; } function getNewVoxelPosition() { From dcaef45f2e2749f94390644d18da71cd493e3905 Mon Sep 17 00:00:00 2001 From: Clement Date: Tue, 11 Mar 2014 16:01:21 -0700 Subject: [PATCH 04/44] More work on editVoxel.js --- examples/addVoxelOnMouseClickExample.js | 20 +- examples/editVoxels.js | 344 ++++++++++++------ interface/src/Application.cpp | 14 +- interface/src/Application.h | 5 +- interface/src/ClipboardScriptingInterface.cpp | 14 +- interface/src/ClipboardScriptingInterface.h | 5 +- interface/src/VoxelSystem.cpp | 2 - interface/src/ui/LocalVoxelsOverlay.cpp | 4 +- interface/src/ui/Volume3DOverlay.cpp | 3 + 9 files changed, 273 insertions(+), 138 deletions(-) diff --git a/examples/addVoxelOnMouseClickExample.js b/examples/addVoxelOnMouseClickExample.js index 244a017ae4..4450a16c22 100644 --- a/examples/addVoxelOnMouseClickExample.js +++ b/examples/addVoxelOnMouseClickExample.js @@ -15,16 +15,16 @@ function mousePressEvent(event) { var pickRay = Camera.computePickRay(event.x, event.y); var intersection = Voxels.findRayIntersection(pickRay); if (intersection.intersects) { - + // Note: due to the current C++ "click on voxel" behavior, these values may be the animated color for the voxel - print("clicked on voxel.red/green/blue=" + intersection.voxel.red + ", " + print("clicked on voxel.red/green/blue=" + intersection.voxel.red + ", " + intersection.voxel.green + ", " + intersection.voxel.blue); - print("clicked on voxel.x/y/z/s=" + intersection.voxel.x + ", " + print("clicked on voxel.x/y/z/s=" + intersection.voxel.x + ", " + intersection.voxel.y + ", " + intersection.voxel.z+ ": " + intersection.voxel.s); print("clicked on face=" + intersection.face); print("clicked on distance=" + intersection.distance); - - var newVoxel = { + + var newVoxel = { x: intersection.voxel.x, y: intersection.voxel.y, z: intersection.voxel.z, @@ -32,7 +32,7 @@ function mousePressEvent(event) { red: 255, green: 0, blue: 255 }; - + if (intersection.face == "MIN_X_FACE") { newVoxel.x -= newVoxel.s; } else if (intersection.face == "MAX_X_FACE") { @@ -46,11 +46,11 @@ function mousePressEvent(event) { } else if (intersection.face == "MAX_Z_FACE") { newVoxel.z += newVoxel.s; } - - print("Voxels.setVoxel("+newVoxel.x + ", " - + newVoxel.y + ", " + newVoxel.z + ", " + newVoxel.s + ", " + + print("Voxels.setVoxel("+newVoxel.x + ", " + + newVoxel.y + ", " + newVoxel.z + ", " + newVoxel.s + ", " + newVoxel.red + ", " + newVoxel.green + ", " + newVoxel.blue + ")" ); - + Voxels.setVoxel(newVoxel.x, newVoxel.y, newVoxel.z, newVoxel.s, newVoxel.red, newVoxel.green, newVoxel.blue); } } diff --git a/examples/editVoxels.js b/examples/editVoxels.js index c4abfd7fff..960840b680 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -8,10 +8,10 @@ // Captures mouse clicks and edits voxels accordingly. // // click = create a new voxel on this face, same color as old (default color picker state) -// right click or control + click = delete this voxel +// right click or control + click = delete this voxel // shift + click = recolor this voxel // 1 - 8 = pick new color from palette -// 9 = create a new voxel in front of the camera +// 9 = create a new voxel in front of the camera // // Click and drag to create more new voxels in the same direction // @@ -36,19 +36,19 @@ var previewLineWidth = 1.5; var oldMode = Camera.getMode(); -var isAdding = false; -var isExtruding = false; +var isAdding = false; +var isExtruding = false; var isOrbiting = false; var isOrbitingFromTouch = false; var isPanning = false; var isPanningFromTouch = false; var touchPointsToOrbit = 2; // you can change these, but be mindful that on some track pads 2 touch points = right click+drag -var touchPointsToPan = 3; +var touchPointsToPan = 3; var orbitAzimuth = 0.0; var orbitAltitude = 0.0; var orbitCenter = { x: 0, y: 0, z: 0 }; var orbitPosition = { x: 0, y: 0, z: 0 }; -var torsoToEyeVector = { x: 0, y: 0, z: 0 }; +var torsoToEyeVector = { x: 0, y: 0, z: 0 }; var orbitRadius = 0.0; var extrudeDirection = { x: 0, y: 0, z: 0 }; var extrudeScale = 0.0; @@ -60,7 +60,7 @@ var wheelPixelsMoved = 0; var mouseX = 0; -var mouseY = 0; +var mouseY = 0; // Create a table of the different colors you can choose var colors = new Array(); @@ -76,7 +76,7 @@ colors[8] = { red: 31, green: 64, blue: 64 }; var numColors = 9; var whichColor = -1; // Starting color is 'Copy' mode -// Create sounds for adding, deleting, recoloring voxels +// Create sounds for adding, deleting, recoloring voxels var addSound1 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+create+2.raw"); var addSound2 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+create+3.raw"); var addSound3 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+create+4.raw"); @@ -93,7 +93,7 @@ var editToolsOn = true; // starts out off // previewAsVoxel - by default, we will preview adds/deletes/recolors as just 4 lines on the intersecting face. But if you // the preview to show a full voxel then set this to true and the voxel will be displayed for voxel editing -var previewAsVoxel = false; +var previewAsVoxel = true; var voxelPreview = Overlays.addOverlay("cube", { position: { x: 0, y: 0, z: 0}, @@ -104,7 +104,7 @@ var voxelPreview = Overlays.addOverlay("cube", { visible: false, lineWidth: 4 }); - + var linePreviewTop = Overlays.addOverlay("line3d", { position: { x: 0, y: 0, z: 0}, end: { x: 0, y: 0, z: 0}, @@ -228,7 +228,7 @@ var eyedropperTool = Overlays.addOverlay("image", { visible: false, alpha: 0.9 }); - + // This will create a couple of image overlays that make a "slider", we will demonstrate how to trap mouse messages to // move the slider @@ -277,6 +277,88 @@ var pointerVoxelScaleMin = Math.pow(2, (1-pointerVoxelScaleOriginStep)); var pointerVoxelScaleMax = Math.pow(2, (pointerVoxelScaleSteps-pointerVoxelScaleOriginStep)); var thumbDeltaPerStep = thumbExtents / (pointerVoxelScaleSteps - 1); + + +///////////////////////////////////// IMPORT MODULE /////////////////////////////// +// Move the following code to a separate file when include will be available. +var importTree; +var importPreview; +var isImporting; +var importPosition; +var importScale; + +function initImport() { + importPreview = Overlays.addOverlay("localvoxels", { + name: "import", + position: { x: 0, y: 0, z: 0}, + scale: 0, + visible: false + }); + isImporting = false; + importPosition = { x: 0, y: 0, z: 0 }; + importScale = 0; +} + +function importVoxels() { + if (Clipboard.importVoxels() == 0) { + isImporting = true; + if (importScale <= 0) { + importScale = 1; + } + } else { + isImporting = false; + } + + return isImporting; +} + +function moveImport(position) { + if (0 < position.x && 0 < position.y && 0 < position.z) { + importPosition = position; + Overlays.editOverlay(importPreview, { + position: { x: importPosition.x, y: importPosition.y, z: importPosition.z } + }); + } +} + +function rescaleImport(scale) { + if (0 < scale) { + importScale = scale; + Overlays.editOverlay(importPreview, { + scale: importScale + }); + } +} + +function showImport(doShow) { + Overlays.editOverlay(importPreview, { + visible: doShow + }); +} + +function placeImport() { + if (isImporting) { + Clipboard.pasteVoxel(importPosition.x, importPosition.y, importPosition.z, importScale); + isImporting = false; + } +} + +function cancelImport() { + if (isImporting) { + isImporting = false; + showImport(false); + } +} + +function cleanupImport() { + Overlays.deleteOverlay(importPreview); + isImporting = false; + importPostion = { x: 0, y: 0, z: 0 }; + importScale = 0; +} +/////////////////////////////////// END IMPORT MODULE ///////////////////////////// +initImport(); + if (editToolsOn) { moveTools(); } @@ -301,9 +383,16 @@ function calcScaleFromThumb(newThumbX) { thumbAt = newThumbX - minThumbX; thumbStep = Math.floor((thumbAt/ thumbExtents) * (pointerVoxelScaleSteps-1)) + 1; pointerVoxelScale = Math.pow(2, (thumbStep-pointerVoxelScaleOriginStep)); + + // if importing, rescale import ... + if (isImporting) { + var importScale = (pointerVoxelScale / MAX_VOXEL_SCALE) * MAX_PASTE_VOXEL_SCALE; + rescaleImport(importScale); + } + // now reset the display accordingly... calcThumbFromScale(pointerVoxelScale); - + // if the user moved the thumb, then they are fixing the voxel scale pointerVoxelScaleSet = true; } @@ -322,7 +411,7 @@ function getNewPasteVoxel(pickRay) { origin.x += pickRay.origin.x; origin.y += pickRay.origin.y; origin.z += pickRay.origin.z; - + origin.x -= voxelSize / 2; origin.y -= voxelSize / 2; origin.z += voxelSize / 2; @@ -330,7 +419,7 @@ function getNewPasteVoxel(pickRay) { return {origin: origin, voxelSize: voxelSize}; } -function getNewVoxelPosition() { +function getNewVoxelPosition() { var camera = Camera.getPosition(); var forwardVector = Quat.getFront(MyAvatar.orientation); var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, NEW_VOXEL_DISTANCE_FROM_CAMERA)); @@ -377,27 +466,27 @@ function calculateVoxelFromIntersection(intersection, operation) { var wantDebug = false; if (wantDebug) { - print(">>>>> calculateVoxelFromIntersection().... intersection voxel.red/green/blue=" + intersection.voxel.red + ", " + print(">>>>> calculateVoxelFromIntersection().... intersection voxel.red/green/blue=" + intersection.voxel.red + ", " + intersection.voxel.green + ", " + intersection.voxel.blue); - print(" intersection voxel.x/y/z/s=" + intersection.voxel.x + ", " + print(" intersection voxel.x/y/z/s=" + intersection.voxel.x + ", " + intersection.voxel.y + ", " + intersection.voxel.z+ ": " + intersection.voxel.s); print(" intersection face=" + intersection.face); print(" intersection distance=" + intersection.distance); - print(" intersection intersection.x/y/z=" + intersection.intersection.x + ", " + print(" intersection intersection.x/y/z=" + intersection.intersection.x + ", " + intersection.intersection.y + ", " + intersection.intersection.z); } - + var voxelSize; if (pointerVoxelScaleSet) { - voxelSize = pointerVoxelScale; + voxelSize = pointerVoxelScale; } else { - voxelSize = intersection.voxel.s; + voxelSize = intersection.voxel.s; } var x; var y; var z; - + // if our "target voxel size" is larger than the voxel we intersected with, then we need to find the closest // ancestor voxel of our target size that contains our intersected voxel. if (voxelSize > intersection.voxel.s) { @@ -438,7 +527,7 @@ function calculateVoxelFromIntersection(intersection, operation) { if (wantAddAdjust) { resultVoxel.x -= voxelSize; } - + resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z + zFightingSizeAdjust }; resultVoxel.bottomRight = {x: highlightAt.x, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z + voxelSize - zFightingSizeAdjust }; resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z + zFightingSizeAdjust }; @@ -462,7 +551,7 @@ function calculateVoxelFromIntersection(intersection, operation) { if (wantAddAdjust) { resultVoxel.y -= voxelSize; } - + resultVoxel.topRight = {x: highlightAt.x + zFightingSizeAdjust , y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust }; resultVoxel.topLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust }; resultVoxel.bottomRight = {x: highlightAt.x + zFightingSizeAdjust , y: highlightAt.y, z: highlightAt.z + voxelSize - zFightingSizeAdjust }; @@ -474,7 +563,7 @@ function calculateVoxelFromIntersection(intersection, operation) { if (wantAddAdjust) { resultVoxel.y += voxelSize; } - + resultVoxel.bottomRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust }; resultVoxel.bottomLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust}; resultVoxel.topRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + voxelSize - zFightingSizeAdjust}; @@ -486,7 +575,7 @@ function calculateVoxelFromIntersection(intersection, operation) { if (wantAddAdjust) { resultVoxel.z -= voxelSize; } - + resultVoxel.bottomRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z }; resultVoxel.bottomLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z}; resultVoxel.topRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z }; @@ -505,7 +594,7 @@ function calculateVoxelFromIntersection(intersection, operation) { resultVoxel.topRight = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z}; } - + return resultVoxel; } @@ -515,7 +604,7 @@ function showPreviewVoxel() { var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY); var intersection = Voxels.findRayIntersection(pickRay); - // if the user hasn't updated the + // if the user hasn't updated the if (!pointerVoxelScaleSet) { calcThumbFromScale(intersection.voxel.s); } @@ -548,41 +637,41 @@ function showPreviewLines() { var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY); if (pasteMode) { // free voxel pasting - + Overlays.editOverlay(voxelPreview, { visible: false }); Overlays.editOverlay(linePreviewLeft, { visible: false }); var pasteVoxel = getNewPasteVoxel(pickRay); // X axis - Overlays.editOverlay(linePreviewBottom, { - position: pasteVoxel.origin, - end: {x: pasteVoxel.origin.x + pasteVoxel.voxelSize, y: pasteVoxel.origin.y, z: pasteVoxel.origin.z }, - visible: true + Overlays.editOverlay(linePreviewBottom, { + position: pasteVoxel.origin, + end: {x: pasteVoxel.origin.x + pasteVoxel.voxelSize, y: pasteVoxel.origin.y, z: pasteVoxel.origin.z }, + visible: true }); // Y axis - Overlays.editOverlay(linePreviewRight, { - position: pasteVoxel.origin, - end: {x: pasteVoxel.origin.x, y: pasteVoxel.origin.y + pasteVoxel.voxelSize, z: pasteVoxel.origin.z }, - visible: true + Overlays.editOverlay(linePreviewRight, { + position: pasteVoxel.origin, + end: {x: pasteVoxel.origin.x, y: pasteVoxel.origin.y + pasteVoxel.voxelSize, z: pasteVoxel.origin.z }, + visible: true }); // Z axis - Overlays.editOverlay(linePreviewTop, { - position: pasteVoxel.origin, - end: {x: pasteVoxel.origin.x, y: pasteVoxel.origin.y, z: pasteVoxel.origin.z - pasteVoxel.voxelSize }, - visible: true + Overlays.editOverlay(linePreviewTop, { + position: pasteVoxel.origin, + end: {x: pasteVoxel.origin.x, y: pasteVoxel.origin.y, z: pasteVoxel.origin.z - pasteVoxel.voxelSize }, + visible: true }); return; } var intersection = Voxels.findRayIntersection(pickRay); - + if (intersection.intersects) { - // if the user hasn't updated the + // if the user hasn't updated the if (!pointerVoxelScaleSet) { calcThumbFromScale(intersection.voxel.s); } @@ -699,14 +788,14 @@ function trackKeyReleaseEvent(event) { trackAsOrbitOrPan = false; moveTools(); } - + // on F1 toggle the preview mode between cubes and lines if (event.text == "F1") { previewAsVoxel = !previewAsVoxel; } showPreviewGuides(); - } + } } function startOrbitMode(event) { @@ -715,7 +804,7 @@ function startOrbitMode(event) { var pickRay = Camera.computePickRay(event.x, event.y); var intersection = Voxels.findRayIntersection(pickRay); - // start orbit camera! + // start orbit camera! var cameraPosition = Camera.getPosition(); torsoToEyeVector = Vec3.subtract(cameraPosition, MyAvatar.position); torsoToEyeVector.x = 0.0; @@ -724,12 +813,12 @@ function startOrbitMode(event) { Camera.setMode("independent"); Camera.keepLookingAt(intersection.intersection); // get position for initial azimuth, elevation - orbitCenter = intersection.intersection; + orbitCenter = intersection.intersection; var orbitVector = Vec3.subtract(cameraPosition, orbitCenter); - orbitRadius = Vec3.length(orbitVector); + orbitRadius = Vec3.length(orbitVector); orbitAzimuth = Math.atan2(orbitVector.z, orbitVector.x); orbitAltitude = Math.asin(orbitVector.y / Vec3.length(orbitVector)); - + //print("startOrbitMode..."); } @@ -737,17 +826,17 @@ function handleOrbitingMove(event) { var cameraOrientation = Camera.getOrientation(); var origEulers = Quat.safeEulerAngles(cameraOrientation); var newEulers = fixEulerAngles(Quat.safeEulerAngles(cameraOrientation)); - var dx = event.x - mouseX; + var dx = event.x - mouseX; var dy = event.y - mouseY; orbitAzimuth += dx / ORBIT_RATE_AZIMUTH; orbitAltitude += dy / ORBIT_RATE_ALTITUDE; - var orbitVector = { x:(Math.cos(orbitAltitude) * Math.cos(orbitAzimuth)) * orbitRadius, + var orbitVector = { x:(Math.cos(orbitAltitude) * Math.cos(orbitAzimuth)) * orbitRadius, y:Math.sin(orbitAltitude) * orbitRadius, - z:(Math.cos(orbitAltitude) * Math.sin(orbitAzimuth)) * orbitRadius }; + z:(Math.cos(orbitAltitude) * Math.sin(orbitAzimuth)) * orbitRadius }; orbitPosition = Vec3.sum(orbitCenter, orbitVector); Camera.setPosition(orbitPosition); - mouseX = event.x; + mouseX = event.x; mouseY = event.y; //print("handleOrbitingMove..."); } @@ -763,7 +852,7 @@ function endOrbitMode(event) { } function startPanMode(event, intersection) { - // start pan camera! + // start pan camera! print("handle PAN mode!!!"); } @@ -781,14 +870,14 @@ function mousePressEvent(event) { // if our tools are off, then don't do anything if (!editToolsOn) { - return; + return; } - - // Normally, if we're panning or orbiting from touch, ignore these... because our touch takes precedence. - // but In the case of a button="RIGHT" click, we may get some touch messages first, and we actually want to + + // Normally, if we're panning or orbiting from touch, ignore these... because our touch takes precedence. + // but In the case of a button="RIGHT" click, we may get some touch messages first, and we actually want to // cancel any touch mode, and then let the right-click through if (isOrbitingFromTouch || isPanningFromTouch) { - + // if the user is holding the ALT key AND they are clicking the RIGHT button (or on multi-touch doing a two // finger touch, then we want to let the new panning behavior take over. // if it's any other case we still want to bail @@ -805,15 +894,15 @@ function mousePressEvent(event) { } // let things fall through } else { - return; + return; } } - + // no clicking on overlays while in panning mode if (!trackAsOrbitOrPan) { var clickedOnSomething = false; var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); - + // If the user clicked on the thumb, handle the slider logic if (clickedOverlay == thumb) { @@ -870,7 +959,7 @@ function mousePressEvent(event) { return; // no further processing } } - + // TODO: does any of this stuff need to execute if we're panning or orbiting? trackMouseEvent(event); // used by preview support mouseX = event.x; @@ -879,6 +968,15 @@ function mousePressEvent(event) { var intersection = Voxels.findRayIntersection(pickRay); audioOptions.position = Vec3.sum(pickRay.origin, pickRay.direction); + if (isImporting) { + print("placing import..."); + placeImport(); + showImport(false); + pasteMode = false; + moveTools(); + return; + } + if (pasteMode) { var pasteVoxel = getNewPasteVoxel(pickRay); Clipboard.pasteVoxel(pasteVoxel.origin.x, pasteVoxel.origin.y, pasteVoxel.origin.z, pasteVoxel.voxelSize); @@ -888,11 +986,11 @@ function mousePressEvent(event) { } if (intersection.intersects) { - // if the user hasn't updated the + // if the user hasn't updated the if (!pointerVoxelScaleSet) { calcThumbFromScale(intersection.voxel.s); } - + // Note: touch and mouse events can cross paths, so we want to ignore any mouse events that would // start a pan or orbit if we're already doing a pan or orbit via touch... if ((event.isAlt || trackAsOrbitOrPan) && !(isOrbitingFromTouch || isPanningFromTouch)) { @@ -916,14 +1014,14 @@ function mousePressEvent(event) { colors[whichColor].blue = intersection.voxel.blue; moveTools(); } - + } else if (recolorToolSelected || trackAsRecolor) { // Recolor Voxel voxelDetails = calculateVoxelFromIntersection(intersection,"recolor"); // doing this erase then set will make sure we only recolor just the target voxel Voxels.eraseVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s); - Voxels.setVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s, + Voxels.setVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s, colors[whichColor].red, colors[whichColor].green, colors[whichColor].blue); Audio.playSound(changeColorSound, audioOptions); Overlays.editOverlay(voxelPreview, { visible: false }); @@ -931,17 +1029,17 @@ function mousePressEvent(event) { // Add voxel on face if (whichColor == -1) { // Copy mode - use clicked voxel color - newColor = { + newColor = { red: intersection.voxel.red, green: intersection.voxel.green, blue: intersection.voxel.blue }; } else { - newColor = { + newColor = { red: colors[whichColor].red, green: colors[whichColor].green, blue: colors[whichColor].blue }; } - + voxelDetails = calculateVoxelFromIntersection(intersection,"add"); Voxels.eraseVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s); Voxels.setVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s, @@ -951,11 +1049,11 @@ function mousePressEvent(event) { lastVoxelScale = voxelDetails.s; playRandomAddSound(audioOptions); - + Overlays.editOverlay(voxelPreview, { visible: false }); dragStart = { x: event.x, y: event.y }; isAdding = true; - } + } } } @@ -974,14 +1072,14 @@ function keyPressEvent(event) { Audio.playSound(clickSound, audioOptions); moveTools(); } else if (event.text == "0") { - // Create a brand new 1 meter voxel in front of your avatar - var color = whichColor; + // Create a brand new 1 meter voxel in front of your avatar + var color = whichColor; if (color == -1) color = 0; var newPosition = getNewVoxelPosition(); - var newVoxel = { + var newVoxel = { x: newPosition.x, y: newPosition.y , - z: newPosition.z, + z: newPosition.z, s: NEW_VOXEL_SIZE, red: colors[color].red, green: colors[color].green, @@ -992,7 +1090,7 @@ function keyPressEvent(event) { playRandomAddSound(audioOptions); } } - + trackKeyPressEvent(event); // used by preview support } @@ -1051,24 +1149,36 @@ function menuItemEvent(menuItem) { moveTools(); } if (menuItem == "Paste") { - print("pasting..."); - Clipboard.pasteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + if (isImporting) { + print("placing import..."); + placeImport(); + showImport(false); + } else { + print("pasting..."); + Clipboard.pasteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + } pasteMode = false; moveTools(); } if (menuItem == "Delete") { print("deleting..."); - Clipboard.deleteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + if (isImporting) { + cancelImport(); + } else { + Clipboard.deleteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + } } - + if (menuItem == "Export Voxels") { print("export"); Clipboard.exportVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); } if (menuItem == "Import Voxels") { - print("import"); - Clipboard.importVoxels(); - pasteMode = true; + print("importing..."); + if (importVoxels()) { + showImport(true); + pasteMode = true; + } moveTools(); } if (menuItem == "Nudge") { @@ -1083,11 +1193,11 @@ function mouseMoveEvent(event) { return; } - // if we're panning or orbiting from touch, ignore these... because our touch takes precedence. + // if we're panning or orbiting from touch, ignore these... because our touch takes precedence. if (isOrbitingFromTouch || isPanningFromTouch) { - return; + return; } - + // double check that we didn't accidentally miss a pan or orbit click request if (trackAsOrbitOrPan && !isPanning && !isOrbiting) { if (event.isLeftButton && !event.isRightButton) { @@ -1109,7 +1219,7 @@ function mouseMoveEvent(event) { thumbX = maxThumbX; } calcScaleFromThumb(thumbX); - + } else if (isOrbiting) { handleOrbitingMove(event); } else if (isPanning) { @@ -1118,8 +1228,8 @@ function mouseMoveEvent(event) { // Watch the drag direction to tell which way to 'extrude' this voxel if (!isExtruding) { var pickRay = Camera.computePickRay(event.x, event.y); - var lastVoxelDistance = { x: pickRay.origin.x - lastVoxelPosition.x, - y: pickRay.origin.y - lastVoxelPosition.y, + var lastVoxelDistance = { x: pickRay.origin.x - lastVoxelPosition.x, + y: pickRay.origin.y - lastVoxelPosition.y, z: pickRay.origin.z - lastVoxelPosition.z }; var distance = Vec3.length(lastVoxelDistance); var mouseSpot = { x: pickRay.direction.x * distance, y: pickRay.direction.y * distance, z: pickRay.direction.z * distance }; @@ -1138,22 +1248,22 @@ function mouseMoveEvent(event) { else if (dy < -lastVoxelScale) extrudeDirection.y = -extrudeScale; else if (dz > lastVoxelScale) extrudeDirection.z = extrudeScale; else if (dz < -lastVoxelScale) extrudeDirection.z = -extrudeScale; - else isExtruding = false; + else isExtruding = false; } else { // We have got an extrusion direction, now look for mouse move beyond threshold to add new voxel - var dx = event.x - mouseX; + var dx = event.x - mouseX; var dy = event.y - mouseY; if (Math.sqrt(dx*dx + dy*dy) > PIXELS_PER_EXTRUDE_VOXEL) { lastVoxelPosition = Vec3.sum(lastVoxelPosition, extrudeDirection); Voxels.eraseVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s); - Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, + Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, extrudeScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); mouseX = event.x; mouseY = event.y; } } } - + // update the add voxel/delete voxel overlay preview trackMouseEvent(event); } @@ -1161,13 +1271,13 @@ function mouseMoveEvent(event) { function mouseReleaseEvent(event) { // if our tools are off, then don't do anything if (!editToolsOn) { - return; + return; } if (isMovingSlider) { isMovingSlider = false; } - + if (isOrbiting) { endOrbitMode(event); isOrbiting = false; @@ -1178,7 +1288,7 @@ function mouseReleaseEvent(event) { isPanning = false; } isAdding = false; - isExtruding = false; + isExtruding = false; } function moveTools() { @@ -1206,7 +1316,7 @@ function moveTools() { if (s == (numColors - 1)) { extraWidth = swatchExtraPadding; } - + Overlays.editOverlay(swatches[s], { x: swatchX, y: swatchesY, @@ -1270,16 +1380,16 @@ function touchBeginEvent(event) { if (!editToolsOn) { return; } - + // if we're already in the middle of orbiting or panning, then ignore these multi-touch events... if (isOrbiting || isPanning) { return; - } - + } + if (event.isAlt || trackAsOrbitOrPan) { if (event.touchPoints == touchPointsToOrbit) { // we need to double check that we didn't start an orbit, because the touch events will sometimes - // come in as 2 then 3 touches... + // come in as 2 then 3 touches... if (isPanningFromTouch) { print("touchBeginEvent... calling endPanMode()"); endPanMode(event); @@ -1289,7 +1399,7 @@ function touchBeginEvent(event) { isOrbitingFromTouch = true; } else if (event.touchPoints == touchPointsToPan) { // we need to double check that we didn't start an orbit, because the touch events will sometimes - // come in as 2 then 3 touches... + // come in as 2 then 3 touches... if (isOrbitingFromTouch) { endOrbitMode(event); isOrbitingFromTouch = false; @@ -1308,11 +1418,11 @@ function touchUpdateEvent(event) { // if we're already in the middle of orbiting or panning, then ignore these multi-touch events... if (isOrbiting || isPanning) { return; - } - + } + if (isOrbitingFromTouch) { // we need to double check that we didn't start an orbit, because the touch events will sometimes - // come in as 2 then 3 touches... + // come in as 2 then 3 touches... if (event.touchPoints == touchPointsToPan) { //print("we now have touchPointsToPan touches... switch to pan..."); endOrbitMode(event); @@ -1326,7 +1436,7 @@ function touchUpdateEvent(event) { if (isPanningFromTouch) { //print("touchUpdateEvent... isPanningFromTouch... event.touchPoints=" + event.touchPoints); // we need to double check that we didn't start an orbit, because the touch events will sometimes - // come in as 2 then 3 touches... + // come in as 2 then 3 touches... if (event.touchPoints == touchPointsToOrbit) { //print("we now have touchPointsToOrbit touches... switch to orbit..."); //print("touchUpdateEvent... calling endPanMode()"); @@ -1349,8 +1459,8 @@ function touchEndEvent(event) { // if we're already in the middle of orbiting or panning, then ignore these multi-touch events... if (isOrbiting || isPanning) { return; - } - + } + if (isOrbitingFromTouch) { endOrbitMode(event); isOrbitingFromTouch = false; @@ -1368,10 +1478,10 @@ var lastFingerDeleteVoxel = { x: -1, y: -1, z: -1}; // off of the build-able are function checkControllers() { var controllersPerPalm = 2; // palm and finger for (var palm = 0; palm < 2; palm++) { - var palmController = palm * controllersPerPalm; - var fingerTipController = palmController + 1; + var palmController = palm * controllersPerPalm; + var fingerTipController = palmController + 1; var fingerTipPosition = Controller.getSpatialControlPosition(fingerTipController); - + var BUTTON_COUNT = 6; var BUTTON_BASE = palm * BUTTON_COUNT; var BUTTON_1 = BUTTON_BASE + 1; @@ -1389,7 +1499,7 @@ function checkControllers() { Voxels.eraseVoxel(fingerTipPosition.x, fingerTipPosition.y, fingerTipPosition.z, FINGERTIP_VOXEL_SIZE); Voxels.setVoxel(fingerTipPosition.x, fingerTipPosition.y, fingerTipPosition.z, FINGERTIP_VOXEL_SIZE, newColor.red, newColor.green, newColor.blue); - + lastFingerAddVoxel = fingerTipPosition; } } else if (Controller.isButtonPressed(BUTTON_2)) { @@ -1407,7 +1517,7 @@ function update(deltaTime) { windowDimensions = newWindowDimensions; moveTools(); } - + if (editToolsOn) { checkControllers(); } @@ -1425,7 +1535,7 @@ function wheelEvent(event) { pointerVoxelScale /= 2.0; if (pointerVoxelScale < MIN_VOXEL_SCALE) { pointerVoxelScale = MIN_VOXEL_SCALE; - } + } } else { pointerVoxelScale *= 2.0; if (pointerVoxelScale > MAX_VOXEL_SCALE) { @@ -1435,6 +1545,11 @@ function wheelEvent(event) { calcThumbFromScale(pointerVoxelScale); trackMouseEvent(event); wheelPixelsMoved = 0; + + if (isImporting) { + var importScale = (pointerVoxelScale / MAX_VOXEL_SCALE) * MAX_PASTE_VOXEL_SCALE; + rescaleImport(importScale); + } } } @@ -1467,6 +1582,7 @@ function scriptEnding() { Overlays.deleteOverlay(thumb); Controller.releaseKeyEvents({ text: "+" }); Controller.releaseKeyEvents({ text: "-" }); + cleanupImport(); cleanupMenus(); } Script.scriptEnding.connect(scriptEnding); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 032e849f0a..771f02750d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -140,9 +140,9 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _fps(120.0f), _justStarted(true), _voxelImporter(NULL), + _sharedVoxelSystem(TREE_SCALE, DEFAULT_MAX_VOXELS_PER_SYSTEM, &_clipboard), _wantToKillLocalVoxels(false), _audioScope(256, 200, true), - _myAvatar(), _mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)), _mouseX(0), _mouseY(0), @@ -1387,6 +1387,8 @@ void Application::exportVoxels(const VoxelDetail& sourceVoxel) { } void Application::importVoxels() { + int result = 1; + if (!_voxelImporter) { _voxelImporter = new VoxelImporter(_window); _voxelImporter->loadSettings(_settings); @@ -1394,6 +1396,7 @@ void Application::importVoxels() { if (!_voxelImporter->exec()) { qDebug() << "[DEBUG] Import succeeded." << endl; + result = 0; } else { qDebug() << "[DEBUG] Import failed." << endl; if (_sharedVoxelSystem.getTree() == _voxelImporter->getVoxelTree()) { @@ -1404,6 +1407,8 @@ void Application::importVoxels() { // restore the main window's active state _window->activateWindow(); + + emit importDone(result); } void Application::cutVoxels(const VoxelDetail& sourceVoxel) { @@ -1495,10 +1500,9 @@ void Application::init() { // Cleanup of the original shared tree _sharedVoxelSystem.init(); - VoxelTree* tmpTree = _sharedVoxelSystem.getTree(); - _sharedVoxelSystem.changeTree(&_clipboard); - delete tmpTree; - + + _voxelImporter = new VoxelImporter(_window); + _environment.init(); _glowEffect.init(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 234f264447..c6fc7140eb 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -225,6 +225,9 @@ signals: /// Fired when we're rendering in-world interface elements; allows external parties to hook in. void renderingInWorldInterface(); + /// Fired when the import window is closed with a return code. + void importDone(int); + public slots: void domainChanged(const QString& domainHostname); void updateWindowTitle(); @@ -351,13 +354,13 @@ private: glm::vec3 _gravity; // Frame Rate Measurement + int _frameCount; float _fps; timeval _applicationStartupTime; timeval _timerStart, _timerEnd; timeval _lastTimeUpdated; bool _justStarted; - Stars _stars; BuckyBalls _buckyBalls; diff --git a/interface/src/ClipboardScriptingInterface.cpp b/interface/src/ClipboardScriptingInterface.cpp index d9a8f04d90..e8a02b041b 100644 --- a/interface/src/ClipboardScriptingInterface.cpp +++ b/interface/src/ClipboardScriptingInterface.cpp @@ -9,6 +9,7 @@ #include "ClipboardScriptingInterface.h" ClipboardScriptingInterface::ClipboardScriptingInterface() { + connect(this, SIGNAL(readyToImport()), Application::getInstance(), SLOT(importVoxels())); } void ClipboardScriptingInterface::cutVoxel(const VoxelDetail& sourceVoxel) { @@ -70,12 +71,17 @@ void ClipboardScriptingInterface::exportVoxel(float x, float y, float z, float s z / (float)TREE_SCALE, s / (float)TREE_SCALE }; - QMetaObject::invokeMethod(Application::getInstance(), "exportVoxels", - Q_ARG(const VoxelDetail&, sourceVoxel)); + Application::getInstance()->exportVoxels(sourceVoxel); } -void ClipboardScriptingInterface::importVoxels() { - QMetaObject::invokeMethod(Application::getInstance(), "importVoxels"); +bool ClipboardScriptingInterface::importVoxels() { + qDebug() << "[DEBUG] Importing ... "; + QEventLoop loop; + connect(Application::getInstance(), SIGNAL(importDone(int)), &loop, SLOT(quit())); + emit readyToImport(); + int returnCode = loop.exec(); + + return returnCode; } void ClipboardScriptingInterface::nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec) { diff --git a/interface/src/ClipboardScriptingInterface.h b/interface/src/ClipboardScriptingInterface.h index 99747f56f6..78e72d6de0 100644 --- a/interface/src/ClipboardScriptingInterface.h +++ b/interface/src/ClipboardScriptingInterface.h @@ -18,6 +18,9 @@ class ClipboardScriptingInterface : public QObject { public: ClipboardScriptingInterface(); +signals: + void readyToImport(); + public slots: void cutVoxel(const VoxelDetail& sourceVoxel); void cutVoxel(float x, float y, float z, float s); @@ -34,7 +37,7 @@ public slots: void exportVoxel(const VoxelDetail& sourceVoxel); void exportVoxel(float x, float y, float z, float s); - void importVoxels(); + bool importVoxels(); void nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec); void nudgeVoxel(float x, float y, float z, float s, const glm::vec3& nudgeVec); diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index aa628bac7b..a8bdeb1114 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -1177,8 +1177,6 @@ void VoxelSystem::init() { } void VoxelSystem::changeTree(VoxelTree* newTree) { - disconnect(_tree, 0, this, 0); - _tree = newTree; _tree->setDirtyBit(); diff --git a/interface/src/ui/LocalVoxelsOverlay.cpp b/interface/src/ui/LocalVoxelsOverlay.cpp index 01a885dedc..248a5b6733 100644 --- a/interface/src/ui/LocalVoxelsOverlay.cpp +++ b/interface/src/ui/LocalVoxelsOverlay.cpp @@ -40,9 +40,11 @@ void LocalVoxelsOverlay::update(float deltatime) { _voxelSystem->init(); } - if (_voxelCount != _tree->getOctreeElementsCount()) { + if (_visible && _voxelCount != _tree->getOctreeElementsCount()) { _voxelCount = _tree->getOctreeElementsCount(); + _tree->lockForWrite(); _voxelSystem->forceRedrawEntireTree(); + _tree->unlock(); } } diff --git a/interface/src/ui/Volume3DOverlay.cpp b/interface/src/ui/Volume3DOverlay.cpp index dbc1582cc5..a4e6c76a12 100644 --- a/interface/src/ui/Volume3DOverlay.cpp +++ b/interface/src/ui/Volume3DOverlay.cpp @@ -31,6 +31,9 @@ void Volume3DOverlay::setProperties(const QScriptValue& properties) { if (properties.property("size").isValid()) { setSize(properties.property("size").toVariant().toFloat()); } + if (properties.property("scale").isValid()) { + setSize(properties.property("scale").toVariant().toFloat()); + } if (properties.property("isSolid").isValid()) { setIsSolid(properties.property("isSolid").toVariant().toBool()); From 6fcb802a9439ed2835c2cf4e3ce710ae551b1299 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 11 Mar 2014 18:01:38 -0700 Subject: [PATCH 05/44] Added preview deplacement + fixed locking issue --- examples/addVoxelOnMouseClickExample.js | 20 +++++++++--------- examples/editVoxels.js | 27 +++++++++++++++++-------- interface/src/ui/LocalVoxelsOverlay.cpp | 4 ++-- 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/examples/addVoxelOnMouseClickExample.js b/examples/addVoxelOnMouseClickExample.js index 4450a16c22..244a017ae4 100644 --- a/examples/addVoxelOnMouseClickExample.js +++ b/examples/addVoxelOnMouseClickExample.js @@ -15,16 +15,16 @@ function mousePressEvent(event) { var pickRay = Camera.computePickRay(event.x, event.y); var intersection = Voxels.findRayIntersection(pickRay); if (intersection.intersects) { - + // Note: due to the current C++ "click on voxel" behavior, these values may be the animated color for the voxel - print("clicked on voxel.red/green/blue=" + intersection.voxel.red + ", " + print("clicked on voxel.red/green/blue=" + intersection.voxel.red + ", " + intersection.voxel.green + ", " + intersection.voxel.blue); - print("clicked on voxel.x/y/z/s=" + intersection.voxel.x + ", " + print("clicked on voxel.x/y/z/s=" + intersection.voxel.x + ", " + intersection.voxel.y + ", " + intersection.voxel.z+ ": " + intersection.voxel.s); print("clicked on face=" + intersection.face); print("clicked on distance=" + intersection.distance); - - var newVoxel = { + + var newVoxel = { x: intersection.voxel.x, y: intersection.voxel.y, z: intersection.voxel.z, @@ -32,7 +32,7 @@ function mousePressEvent(event) { red: 255, green: 0, blue: 255 }; - + if (intersection.face == "MIN_X_FACE") { newVoxel.x -= newVoxel.s; } else if (intersection.face == "MAX_X_FACE") { @@ -46,11 +46,11 @@ function mousePressEvent(event) { } else if (intersection.face == "MAX_Z_FACE") { newVoxel.z += newVoxel.s; } - - print("Voxels.setVoxel("+newVoxel.x + ", " - + newVoxel.y + ", " + newVoxel.z + ", " + newVoxel.s + ", " + + print("Voxels.setVoxel("+newVoxel.x + ", " + + newVoxel.y + ", " + newVoxel.z + ", " + newVoxel.s + ", " + newVoxel.red + ", " + newVoxel.green + ", " + newVoxel.blue + ")" ); - + Voxels.setVoxel(newVoxel.x, newVoxel.y, newVoxel.z, newVoxel.s, newVoxel.red, newVoxel.green, newVoxel.blue); } } diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 960840b680..d78efdaad3 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -972,7 +972,6 @@ function mousePressEvent(event) { print("placing import..."); placeImport(); showImport(false); - pasteMode = false; moveTools(); return; } @@ -1177,7 +1176,6 @@ function menuItemEvent(menuItem) { print("importing..."); if (importVoxels()) { showImport(true); - pasteMode = true; } moveTools(); } @@ -1512,14 +1510,27 @@ function checkControllers() { } function update(deltaTime) { - var newWindowDimensions = Controller.getViewportDimensions(); - if (newWindowDimensions.x != windowDimensions.x || newWindowDimensions.y != windowDimensions.y) { - windowDimensions = newWindowDimensions; - moveTools(); - } - if (editToolsOn) { + var newWindowDimensions = Controller.getViewportDimensions(); + if (newWindowDimensions.x != windowDimensions.x || newWindowDimensions.y != windowDimensions.y) { + windowDimensions = newWindowDimensions; + moveTools(); + } + checkControllers(); + + // Move Import Preview + if (isImporting) { + var position = MyAvatar.position; + var forwardVector = Quat.getFront(MyAvatar.orientation); + var targetPosition = Vec3.sum(position, Vec3.multiply(forwardVector, importScale)); + var newPosition = { + x: Math.floor(targetPosition.x / importScale) * importScale, + y: Math.floor(targetPosition.y / importScale) * importScale, + z: Math.floor(targetPosition.z / importScale) * importScale + } + moveImport(newPosition); + } } } diff --git a/interface/src/ui/LocalVoxelsOverlay.cpp b/interface/src/ui/LocalVoxelsOverlay.cpp index 248a5b6733..fde03b85cb 100644 --- a/interface/src/ui/LocalVoxelsOverlay.cpp +++ b/interface/src/ui/LocalVoxelsOverlay.cpp @@ -40,12 +40,12 @@ void LocalVoxelsOverlay::update(float deltatime) { _voxelSystem->init(); } + _tree->lockForWrite(); if (_visible && _voxelCount != _tree->getOctreeElementsCount()) { _voxelCount = _tree->getOctreeElementsCount(); - _tree->lockForWrite(); _voxelSystem->forceRedrawEntireTree(); - _tree->unlock(); } + _tree->unlock(); } void LocalVoxelsOverlay::render() { From 03d7fb147c6913945d0e0f6bda999d93c1e016e2 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 11 Mar 2014 18:15:04 -0700 Subject: [PATCH 06/44] Fixed spaces added everywhere --- examples/editVoxels.js | 184 ++++++++++++++++++++--------------------- 1 file changed, 92 insertions(+), 92 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index d78efdaad3..b5702dff47 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -8,10 +8,10 @@ // Captures mouse clicks and edits voxels accordingly. // // click = create a new voxel on this face, same color as old (default color picker state) -// right click or control + click = delete this voxel +// right click or control + click = delete this voxel // shift + click = recolor this voxel // 1 - 8 = pick new color from palette -// 9 = create a new voxel in front of the camera +// 9 = create a new voxel in front of the camera // // Click and drag to create more new voxels in the same direction // @@ -36,19 +36,19 @@ var previewLineWidth = 1.5; var oldMode = Camera.getMode(); -var isAdding = false; -var isExtruding = false; +var isAdding = false; +var isExtruding = false; var isOrbiting = false; var isOrbitingFromTouch = false; var isPanning = false; var isPanningFromTouch = false; var touchPointsToOrbit = 2; // you can change these, but be mindful that on some track pads 2 touch points = right click+drag -var touchPointsToPan = 3; +var touchPointsToPan = 3; var orbitAzimuth = 0.0; var orbitAltitude = 0.0; var orbitCenter = { x: 0, y: 0, z: 0 }; var orbitPosition = { x: 0, y: 0, z: 0 }; -var torsoToEyeVector = { x: 0, y: 0, z: 0 }; +var torsoToEyeVector = { x: 0, y: 0, z: 0 }; var orbitRadius = 0.0; var extrudeDirection = { x: 0, y: 0, z: 0 }; var extrudeScale = 0.0; @@ -60,7 +60,7 @@ var wheelPixelsMoved = 0; var mouseX = 0; -var mouseY = 0; +var mouseY = 0; // Create a table of the different colors you can choose var colors = new Array(); @@ -76,7 +76,7 @@ colors[8] = { red: 31, green: 64, blue: 64 }; var numColors = 9; var whichColor = -1; // Starting color is 'Copy' mode -// Create sounds for adding, deleting, recoloring voxels +// Create sounds for adding, deleting, recoloring voxels var addSound1 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+create+2.raw"); var addSound2 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+create+3.raw"); var addSound3 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+create+4.raw"); @@ -93,7 +93,7 @@ var editToolsOn = true; // starts out off // previewAsVoxel - by default, we will preview adds/deletes/recolors as just 4 lines on the intersecting face. But if you // the preview to show a full voxel then set this to true and the voxel will be displayed for voxel editing -var previewAsVoxel = true; +var previewAsVoxel = false; var voxelPreview = Overlays.addOverlay("cube", { position: { x: 0, y: 0, z: 0}, @@ -104,7 +104,7 @@ var voxelPreview = Overlays.addOverlay("cube", { visible: false, lineWidth: 4 }); - + var linePreviewTop = Overlays.addOverlay("line3d", { position: { x: 0, y: 0, z: 0}, end: { x: 0, y: 0, z: 0}, @@ -228,7 +228,7 @@ var eyedropperTool = Overlays.addOverlay("image", { visible: false, alpha: 0.9 }); - + // This will create a couple of image overlays that make a "slider", we will demonstrate how to trap mouse messages to // move the slider @@ -392,7 +392,7 @@ function calcScaleFromThumb(newThumbX) { // now reset the display accordingly... calcThumbFromScale(pointerVoxelScale); - + // if the user moved the thumb, then they are fixing the voxel scale pointerVoxelScaleSet = true; } @@ -466,27 +466,27 @@ function calculateVoxelFromIntersection(intersection, operation) { var wantDebug = false; if (wantDebug) { - print(">>>>> calculateVoxelFromIntersection().... intersection voxel.red/green/blue=" + intersection.voxel.red + ", " + print(">>>>> calculateVoxelFromIntersection().... intersection voxel.red/green/blue=" + intersection.voxel.red + ", " + intersection.voxel.green + ", " + intersection.voxel.blue); - print(" intersection voxel.x/y/z/s=" + intersection.voxel.x + ", " + print(" intersection voxel.x/y/z/s=" + intersection.voxel.x + ", " + intersection.voxel.y + ", " + intersection.voxel.z+ ": " + intersection.voxel.s); print(" intersection face=" + intersection.face); print(" intersection distance=" + intersection.distance); - print(" intersection intersection.x/y/z=" + intersection.intersection.x + ", " + print(" intersection intersection.x/y/z=" + intersection.intersection.x + ", " + intersection.intersection.y + ", " + intersection.intersection.z); } - + var voxelSize; if (pointerVoxelScaleSet) { - voxelSize = pointerVoxelScale; + voxelSize = pointerVoxelScale; } else { - voxelSize = intersection.voxel.s; + voxelSize = intersection.voxel.s; } var x; var y; var z; - + // if our "target voxel size" is larger than the voxel we intersected with, then we need to find the closest // ancestor voxel of our target size that contains our intersected voxel. if (voxelSize > intersection.voxel.s) { @@ -527,7 +527,7 @@ function calculateVoxelFromIntersection(intersection, operation) { if (wantAddAdjust) { resultVoxel.x -= voxelSize; } - + resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z + zFightingSizeAdjust }; resultVoxel.bottomRight = {x: highlightAt.x, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z + voxelSize - zFightingSizeAdjust }; resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z + zFightingSizeAdjust }; @@ -551,7 +551,7 @@ function calculateVoxelFromIntersection(intersection, operation) { if (wantAddAdjust) { resultVoxel.y -= voxelSize; } - + resultVoxel.topRight = {x: highlightAt.x + zFightingSizeAdjust , y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust }; resultVoxel.topLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust }; resultVoxel.bottomRight = {x: highlightAt.x + zFightingSizeAdjust , y: highlightAt.y, z: highlightAt.z + voxelSize - zFightingSizeAdjust }; @@ -563,7 +563,7 @@ function calculateVoxelFromIntersection(intersection, operation) { if (wantAddAdjust) { resultVoxel.y += voxelSize; } - + resultVoxel.bottomRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust }; resultVoxel.bottomLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust}; resultVoxel.topRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + voxelSize - zFightingSizeAdjust}; @@ -575,7 +575,7 @@ function calculateVoxelFromIntersection(intersection, operation) { if (wantAddAdjust) { resultVoxel.z -= voxelSize; } - + resultVoxel.bottomRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z }; resultVoxel.bottomLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z}; resultVoxel.topRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z }; @@ -594,7 +594,7 @@ function calculateVoxelFromIntersection(intersection, operation) { resultVoxel.topRight = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z}; } - + return resultVoxel; } @@ -604,7 +604,7 @@ function showPreviewVoxel() { var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY); var intersection = Voxels.findRayIntersection(pickRay); - // if the user hasn't updated the + // if the user hasn't updated the if (!pointerVoxelScaleSet) { calcThumbFromScale(intersection.voxel.s); } @@ -668,10 +668,10 @@ function showPreviewLines() { } var intersection = Voxels.findRayIntersection(pickRay); - + if (intersection.intersects) { - // if the user hasn't updated the + // if the user hasn't updated the if (!pointerVoxelScaleSet) { calcThumbFromScale(intersection.voxel.s); } @@ -788,14 +788,14 @@ function trackKeyReleaseEvent(event) { trackAsOrbitOrPan = false; moveTools(); } - + // on F1 toggle the preview mode between cubes and lines if (event.text == "F1") { previewAsVoxel = !previewAsVoxel; } showPreviewGuides(); - } + } } function startOrbitMode(event) { @@ -804,7 +804,7 @@ function startOrbitMode(event) { var pickRay = Camera.computePickRay(event.x, event.y); var intersection = Voxels.findRayIntersection(pickRay); - // start orbit camera! + // start orbit camera! var cameraPosition = Camera.getPosition(); torsoToEyeVector = Vec3.subtract(cameraPosition, MyAvatar.position); torsoToEyeVector.x = 0.0; @@ -813,12 +813,12 @@ function startOrbitMode(event) { Camera.setMode("independent"); Camera.keepLookingAt(intersection.intersection); // get position for initial azimuth, elevation - orbitCenter = intersection.intersection; + orbitCenter = intersection.intersection; var orbitVector = Vec3.subtract(cameraPosition, orbitCenter); - orbitRadius = Vec3.length(orbitVector); + orbitRadius = Vec3.length(orbitVector); orbitAzimuth = Math.atan2(orbitVector.z, orbitVector.x); orbitAltitude = Math.asin(orbitVector.y / Vec3.length(orbitVector)); - + //print("startOrbitMode..."); } @@ -826,17 +826,17 @@ function handleOrbitingMove(event) { var cameraOrientation = Camera.getOrientation(); var origEulers = Quat.safeEulerAngles(cameraOrientation); var newEulers = fixEulerAngles(Quat.safeEulerAngles(cameraOrientation)); - var dx = event.x - mouseX; + var dx = event.x - mouseX; var dy = event.y - mouseY; orbitAzimuth += dx / ORBIT_RATE_AZIMUTH; orbitAltitude += dy / ORBIT_RATE_ALTITUDE; - var orbitVector = { x:(Math.cos(orbitAltitude) * Math.cos(orbitAzimuth)) * orbitRadius, + var orbitVector = { x:(Math.cos(orbitAltitude) * Math.cos(orbitAzimuth)) * orbitRadius, y:Math.sin(orbitAltitude) * orbitRadius, - z:(Math.cos(orbitAltitude) * Math.sin(orbitAzimuth)) * orbitRadius }; + z:(Math.cos(orbitAltitude) * Math.sin(orbitAzimuth)) * orbitRadius }; orbitPosition = Vec3.sum(orbitCenter, orbitVector); Camera.setPosition(orbitPosition); - mouseX = event.x; + mouseX = event.x; mouseY = event.y; //print("handleOrbitingMove..."); } @@ -852,7 +852,7 @@ function endOrbitMode(event) { } function startPanMode(event, intersection) { - // start pan camera! + // start pan camera! print("handle PAN mode!!!"); } @@ -870,14 +870,14 @@ function mousePressEvent(event) { // if our tools are off, then don't do anything if (!editToolsOn) { - return; + return; } - - // Normally, if we're panning or orbiting from touch, ignore these... because our touch takes precedence. - // but In the case of a button="RIGHT" click, we may get some touch messages first, and we actually want to + + // Normally, if we're panning or orbiting from touch, ignore these... because our touch takes precedence. + // but In the case of a button="RIGHT" click, we may get some touch messages first, and we actually want to // cancel any touch mode, and then let the right-click through if (isOrbitingFromTouch || isPanningFromTouch) { - + // if the user is holding the ALT key AND they are clicking the RIGHT button (or on multi-touch doing a two // finger touch, then we want to let the new panning behavior take over. // if it's any other case we still want to bail @@ -894,15 +894,15 @@ function mousePressEvent(event) { } // let things fall through } else { - return; + return; } } - + // no clicking on overlays while in panning mode if (!trackAsOrbitOrPan) { var clickedOnSomething = false; var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); - + // If the user clicked on the thumb, handle the slider logic if (clickedOverlay == thumb) { @@ -959,7 +959,7 @@ function mousePressEvent(event) { return; // no further processing } } - + // TODO: does any of this stuff need to execute if we're panning or orbiting? trackMouseEvent(event); // used by preview support mouseX = event.x; @@ -985,11 +985,11 @@ function mousePressEvent(event) { } if (intersection.intersects) { - // if the user hasn't updated the + // if the user hasn't updated the if (!pointerVoxelScaleSet) { calcThumbFromScale(intersection.voxel.s); } - + // Note: touch and mouse events can cross paths, so we want to ignore any mouse events that would // start a pan or orbit if we're already doing a pan or orbit via touch... if ((event.isAlt || trackAsOrbitOrPan) && !(isOrbitingFromTouch || isPanningFromTouch)) { @@ -1013,14 +1013,14 @@ function mousePressEvent(event) { colors[whichColor].blue = intersection.voxel.blue; moveTools(); } - + } else if (recolorToolSelected || trackAsRecolor) { // Recolor Voxel voxelDetails = calculateVoxelFromIntersection(intersection,"recolor"); // doing this erase then set will make sure we only recolor just the target voxel Voxels.eraseVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s); - Voxels.setVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s, + Voxels.setVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s, colors[whichColor].red, colors[whichColor].green, colors[whichColor].blue); Audio.playSound(changeColorSound, audioOptions); Overlays.editOverlay(voxelPreview, { visible: false }); @@ -1028,17 +1028,17 @@ function mousePressEvent(event) { // Add voxel on face if (whichColor == -1) { // Copy mode - use clicked voxel color - newColor = { + newColor = { red: intersection.voxel.red, green: intersection.voxel.green, blue: intersection.voxel.blue }; } else { - newColor = { + newColor = { red: colors[whichColor].red, green: colors[whichColor].green, blue: colors[whichColor].blue }; } - + voxelDetails = calculateVoxelFromIntersection(intersection,"add"); Voxels.eraseVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s); Voxels.setVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s, @@ -1048,11 +1048,11 @@ function mousePressEvent(event) { lastVoxelScale = voxelDetails.s; playRandomAddSound(audioOptions); - + Overlays.editOverlay(voxelPreview, { visible: false }); dragStart = { x: event.x, y: event.y }; isAdding = true; - } + } } } @@ -1071,14 +1071,14 @@ function keyPressEvent(event) { Audio.playSound(clickSound, audioOptions); moveTools(); } else if (event.text == "0") { - // Create a brand new 1 meter voxel in front of your avatar - var color = whichColor; + // Create a brand new 1 meter voxel in front of your avatar + var color = whichColor; if (color == -1) color = 0; var newPosition = getNewVoxelPosition(); - var newVoxel = { + var newVoxel = { x: newPosition.x, y: newPosition.y , - z: newPosition.z, + z: newPosition.z, s: NEW_VOXEL_SIZE, red: colors[color].red, green: colors[color].green, @@ -1089,7 +1089,7 @@ function keyPressEvent(event) { playRandomAddSound(audioOptions); } } - + trackKeyPressEvent(event); // used by preview support } @@ -1167,7 +1167,7 @@ function menuItemEvent(menuItem) { Clipboard.deleteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); } } - + if (menuItem == "Export Voxels") { print("export"); Clipboard.exportVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); @@ -1191,11 +1191,11 @@ function mouseMoveEvent(event) { return; } - // if we're panning or orbiting from touch, ignore these... because our touch takes precedence. + // if we're panning or orbiting from touch, ignore these... because our touch takes precedence. if (isOrbitingFromTouch || isPanningFromTouch) { - return; + return; } - + // double check that we didn't accidentally miss a pan or orbit click request if (trackAsOrbitOrPan && !isPanning && !isOrbiting) { if (event.isLeftButton && !event.isRightButton) { @@ -1217,7 +1217,7 @@ function mouseMoveEvent(event) { thumbX = maxThumbX; } calcScaleFromThumb(thumbX); - + } else if (isOrbiting) { handleOrbitingMove(event); } else if (isPanning) { @@ -1226,8 +1226,8 @@ function mouseMoveEvent(event) { // Watch the drag direction to tell which way to 'extrude' this voxel if (!isExtruding) { var pickRay = Camera.computePickRay(event.x, event.y); - var lastVoxelDistance = { x: pickRay.origin.x - lastVoxelPosition.x, - y: pickRay.origin.y - lastVoxelPosition.y, + var lastVoxelDistance = { x: pickRay.origin.x - lastVoxelPosition.x, + y: pickRay.origin.y - lastVoxelPosition.y, z: pickRay.origin.z - lastVoxelPosition.z }; var distance = Vec3.length(lastVoxelDistance); var mouseSpot = { x: pickRay.direction.x * distance, y: pickRay.direction.y * distance, z: pickRay.direction.z * distance }; @@ -1246,22 +1246,22 @@ function mouseMoveEvent(event) { else if (dy < -lastVoxelScale) extrudeDirection.y = -extrudeScale; else if (dz > lastVoxelScale) extrudeDirection.z = extrudeScale; else if (dz < -lastVoxelScale) extrudeDirection.z = -extrudeScale; - else isExtruding = false; + else isExtruding = false; } else { // We have got an extrusion direction, now look for mouse move beyond threshold to add new voxel - var dx = event.x - mouseX; + var dx = event.x - mouseX; var dy = event.y - mouseY; if (Math.sqrt(dx*dx + dy*dy) > PIXELS_PER_EXTRUDE_VOXEL) { lastVoxelPosition = Vec3.sum(lastVoxelPosition, extrudeDirection); Voxels.eraseVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s); - Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, + Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, extrudeScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); mouseX = event.x; mouseY = event.y; } } } - + // update the add voxel/delete voxel overlay preview trackMouseEvent(event); } @@ -1269,13 +1269,13 @@ function mouseMoveEvent(event) { function mouseReleaseEvent(event) { // if our tools are off, then don't do anything if (!editToolsOn) { - return; + return; } if (isMovingSlider) { isMovingSlider = false; } - + if (isOrbiting) { endOrbitMode(event); isOrbiting = false; @@ -1286,7 +1286,7 @@ function mouseReleaseEvent(event) { isPanning = false; } isAdding = false; - isExtruding = false; + isExtruding = false; } function moveTools() { @@ -1314,7 +1314,7 @@ function moveTools() { if (s == (numColors - 1)) { extraWidth = swatchExtraPadding; } - + Overlays.editOverlay(swatches[s], { x: swatchX, y: swatchesY, @@ -1378,16 +1378,16 @@ function touchBeginEvent(event) { if (!editToolsOn) { return; } - + // if we're already in the middle of orbiting or panning, then ignore these multi-touch events... if (isOrbiting || isPanning) { return; - } - + } + if (event.isAlt || trackAsOrbitOrPan) { if (event.touchPoints == touchPointsToOrbit) { // we need to double check that we didn't start an orbit, because the touch events will sometimes - // come in as 2 then 3 touches... + // come in as 2 then 3 touches... if (isPanningFromTouch) { print("touchBeginEvent... calling endPanMode()"); endPanMode(event); @@ -1397,7 +1397,7 @@ function touchBeginEvent(event) { isOrbitingFromTouch = true; } else if (event.touchPoints == touchPointsToPan) { // we need to double check that we didn't start an orbit, because the touch events will sometimes - // come in as 2 then 3 touches... + // come in as 2 then 3 touches... if (isOrbitingFromTouch) { endOrbitMode(event); isOrbitingFromTouch = false; @@ -1416,11 +1416,11 @@ function touchUpdateEvent(event) { // if we're already in the middle of orbiting or panning, then ignore these multi-touch events... if (isOrbiting || isPanning) { return; - } - + } + if (isOrbitingFromTouch) { // we need to double check that we didn't start an orbit, because the touch events will sometimes - // come in as 2 then 3 touches... + // come in as 2 then 3 touches... if (event.touchPoints == touchPointsToPan) { //print("we now have touchPointsToPan touches... switch to pan..."); endOrbitMode(event); @@ -1434,7 +1434,7 @@ function touchUpdateEvent(event) { if (isPanningFromTouch) { //print("touchUpdateEvent... isPanningFromTouch... event.touchPoints=" + event.touchPoints); // we need to double check that we didn't start an orbit, because the touch events will sometimes - // come in as 2 then 3 touches... + // come in as 2 then 3 touches... if (event.touchPoints == touchPointsToOrbit) { //print("we now have touchPointsToOrbit touches... switch to orbit..."); //print("touchUpdateEvent... calling endPanMode()"); @@ -1457,8 +1457,8 @@ function touchEndEvent(event) { // if we're already in the middle of orbiting or panning, then ignore these multi-touch events... if (isOrbiting || isPanning) { return; - } - + } + if (isOrbitingFromTouch) { endOrbitMode(event); isOrbitingFromTouch = false; @@ -1476,10 +1476,10 @@ var lastFingerDeleteVoxel = { x: -1, y: -1, z: -1}; // off of the build-able are function checkControllers() { var controllersPerPalm = 2; // palm and finger for (var palm = 0; palm < 2; palm++) { - var palmController = palm * controllersPerPalm; - var fingerTipController = palmController + 1; + var palmController = palm * controllersPerPalm; + var fingerTipController = palmController + 1; var fingerTipPosition = Controller.getSpatialControlPosition(fingerTipController); - + var BUTTON_COUNT = 6; var BUTTON_BASE = palm * BUTTON_COUNT; var BUTTON_1 = BUTTON_BASE + 1; @@ -1497,7 +1497,7 @@ function checkControllers() { Voxels.eraseVoxel(fingerTipPosition.x, fingerTipPosition.y, fingerTipPosition.z, FINGERTIP_VOXEL_SIZE); Voxels.setVoxel(fingerTipPosition.x, fingerTipPosition.y, fingerTipPosition.z, FINGERTIP_VOXEL_SIZE, newColor.red, newColor.green, newColor.blue); - + lastFingerAddVoxel = fingerTipPosition; } } else if (Controller.isButtonPressed(BUTTON_2)) { @@ -1546,7 +1546,7 @@ function wheelEvent(event) { pointerVoxelScale /= 2.0; if (pointerVoxelScale < MIN_VOXEL_SCALE) { pointerVoxelScale = MIN_VOXEL_SCALE; - } + } } else { pointerVoxelScale *= 2.0; if (pointerVoxelScale > MAX_VOXEL_SCALE) { From 1c4051b288081ee12007f90eaecf89c5fd018f1d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 12 Mar 2014 10:35:22 -0700 Subject: [PATCH 07/44] Added importBoundaries --- examples/editVoxels.js | 40 ++++++++++++++++++++++++++++----------- interface/interface_en.ts | 4 ++-- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index b5702dff47..956b6f1d1d 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -283,17 +283,25 @@ var thumbDeltaPerStep = thumbExtents / (pointerVoxelScaleSteps - 1); // Move the following code to a separate file when include will be available. var importTree; var importPreview; +var importBoundaries; var isImporting; var importPosition; var importScale; function initImport() { importPreview = Overlays.addOverlay("localvoxels", { - name: "import", - position: { x: 0, y: 0, z: 0}, - scale: 0, - visible: false - }); + name: "import", + position: { x: 0, y: 0, z: 0}, + scale: 1, + visible: false + }); + importBoundaries = Overlays.addOverlay("cube", { + position: { x: 0, y: 0, z: 0 }, + scale: 1, + color: { red: 128, blue: 128, green: 128 }, + solid: false, + visible: false + }) isImporting = false; importPosition = { x: 0, y: 0, z: 0 }; importScale = 0; @@ -316,8 +324,11 @@ function moveImport(position) { if (0 < position.x && 0 < position.y && 0 < position.z) { importPosition = position; Overlays.editOverlay(importPreview, { - position: { x: importPosition.x, y: importPosition.y, z: importPosition.z } - }); + position: { x: importPosition.x, y: importPosition.y, z: importPosition.z } + }); + Overlays.editOverlay(importBoundaries, { + position: { x: importPosition.x, y: importPosition.y, z: importPosition.z } + }); } } @@ -325,15 +336,21 @@ function rescaleImport(scale) { if (0 < scale) { importScale = scale; Overlays.editOverlay(importPreview, { - scale: importScale - }); + scale: importScale + }); + Overlays.editOverlay(importBoundaries, { + scale: importScale + }); } } function showImport(doShow) { Overlays.editOverlay(importPreview, { - visible: doShow - }); + visible: doShow + }); + Overlays.editOverlay(importBoundaries, { + visible: doShow + }); } function placeImport() { @@ -352,6 +369,7 @@ function cancelImport() { function cleanupImport() { Overlays.deleteOverlay(importPreview); + Overlays.deleteOverlay(importBoundaries); isImporting = false; importPostion = { x: 0, y: 0, z: 0 }; importScale = 0; diff --git a/interface/interface_en.ts b/interface/interface_en.ts index a8f78cd36e..76a5d47101 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -14,12 +14,12 @@ - + Open Script - + JavaScript Files (*.js) From 855f6fcf598c1eae6a866bff69fd78f9d1b4923d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 12 Mar 2014 11:46:41 -0700 Subject: [PATCH 08/44] Moved Avatar upload to file Menu --- interface/src/Menu.cpp | 6 ++++-- interface/src/Menu.h | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index f0d4d8c133..26747aad86 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -129,7 +129,10 @@ Menu::Menu() : this, SLOT(goTo())); - + addDisabledActionAndSeparator(fileMenu, "Upload/Browse"); + addActionToQMenuAndActionHash(fileMenu, MenuOption::UploaderAvatarHead, 0, Application::getInstance(), SLOT(uploadFST())); + addActionToQMenuAndActionHash(fileMenu, MenuOption::UploaderAvatarSkeleton, 0, Application::getInstance(), SLOT(uploadFST())); + addDisabledActionAndSeparator(fileMenu, "Settings"); addActionToQMenuAndActionHash(fileMenu, MenuOption::SettingsImport, 0, this, SLOT(importSettings())); addActionToQMenuAndActionHash(fileMenu, MenuOption::SettingsExport, 0, this, SLOT(exportSettings())); @@ -161,7 +164,6 @@ Menu::Menu() : QMenu* toolsMenu = addMenu("Tools"); addActionToQMenuAndActionHash(toolsMenu, MenuOption::MetavoxelEditor, 0, this, SLOT(showMetavoxelEditor())); - addActionToQMenuAndActionHash(toolsMenu, MenuOption::FstUploader, 0, Application::getInstance(), SLOT(uploadFST())); _chatAction = addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 380fe2d3b7..1e5ada9e84 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -242,7 +242,6 @@ namespace MenuOption { const QString FirstPerson = "First Person"; const QString FrameTimer = "Show Timer"; const QString FrustumRenderMode = "Render Mode"; - const QString FstUploader = "Upload .fst file"; const QString Fullscreen = "Fullscreen"; const QString FullscreenMirror = "Fullscreen Mirror"; const QString GlowMode = "Cycle Glow Mode"; @@ -291,6 +290,8 @@ namespace MenuOption { const QString StopAllScripts = "Stop All Scripts"; const QString TestPing = "Test Ping"; const QString TransmitterDrive = "Transmitter Drive"; + const QString UploaderAvatarHead = "Upload Avatar Head"; + const QString UploaderAvatarSkeleton = "Upload Avatar Skeleton"; const QString Quit = "Quit"; const QString Voxels = "Voxels"; const QString VoxelMode = "Cycle Voxel Mode"; From b9ee60ba41107635d4cdc370b0d62e7d3c7fbd35 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 12 Mar 2014 11:47:47 -0700 Subject: [PATCH 09/44] FstReader not a member anymore --- interface/src/Application.cpp | 6 +++++- interface/src/Application.h | 3 --- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 13e3d36fad..8e64ba4d04 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -62,6 +62,7 @@ #include #include #include +#include #include "Application.h" #include "ClipboardScriptingInterface.h" @@ -3432,7 +3433,10 @@ void Application::reloadAllScripts() { } void Application::uploadFST() { - _fstReader.zip(); + FstReader reader; + if(reader.zip()) { + reader.send(); + } } void Application::removeScriptName(const QString& fileNameString) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 70b7347654..5b1f2e8c03 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -28,7 +28,6 @@ #include #include #include -#include #include "Audio.h" #include "BandwidthMeter.h" @@ -472,8 +471,6 @@ private: TouchEvent _lastTouchEvent; Overlays _overlays; - - FstReader _fstReader; }; #endif /* defined(__interface__Application__) */ From 3aa534d47c3a99d40626fa425b25708f5336ac56 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 12 Mar 2014 11:48:41 -0700 Subject: [PATCH 10/44] Added the send method --- libraries/shared/src/FstReader.cpp | 80 +++++++++++++++--------------- libraries/shared/src/FstReader.h | 17 +++++-- 2 files changed, 54 insertions(+), 43 deletions(-) diff --git a/libraries/shared/src/FstReader.cpp b/libraries/shared/src/FstReader.cpp index fa2aebb2fe..d94f036af0 100644 --- a/libraries/shared/src/FstReader.cpp +++ b/libraries/shared/src/FstReader.cpp @@ -17,7 +17,6 @@ #include "FstReader.h" FstReader::FstReader() { - } @@ -37,8 +36,7 @@ bool FstReader::zip() { qDebug() << "Reading FST file : " << QFileInfo(fst).filePath(); - QTemporaryDir tempRootDir(_zipDir.path() + "/" + QFileInfo(fst).baseName()); - QDir rootDir(tempRootDir.path()); + QDir rootDir(_zipDir.path()); // Let's read through the FST file QTextStream stream(&fst); @@ -50,56 +48,66 @@ bool FstReader::zip() { } // according to what is read, we modify the command - if (line.first() == filenameField) { - QFileInfo fbx(QFileInfo(fst).path() + "/" + line.at(1)); + if (line.first() == nameField) { + _modelName = line[1]; + } else if (line.first() == filenameField) { + QFileInfo fbx(QFileInfo(fst).path() + "/" + line[1]); if (!fbx.exists() || !fbx.isFile()) { // Check existence qDebug() << "[ERROR] FBX file " << fbx.absoluteFilePath() << " doesn't exist."; return false; - } else if (fbx.size() > MAX_FBX_SIZE) { // Check size - qDebug() << "[ERROR] FBX file " << fbx.absoluteFilePath() << " too big, over " << MAX_FBX_SIZE << " MB."; - return false; } else { // Compress and copy - compressFile(fbx.filePath(), - rootDir.path() + "/" + line.at(1)); + _fbxFile = rootDir.path() + "/" + line[1]; + _totalSize += fbx.size(); + compressFile(fbx.filePath(), _fbxFile); } } else if (line.first() == texdirField) { // Check existence - QFileInfo texdir(QFileInfo(fst).path() + "/" + line.at(1)); + QFileInfo texdir(QFileInfo(fst).path() + "/" + line[1]); if (!texdir.exists() || !texdir.isDir()) { qDebug() << "[ERROR] Texture directory " << texdir.absolutePath() << " doesn't exist."; return false; } - QDir newTexdir(rootDir.canonicalPath() + "/" + line.at(1)); - if (!newTexdir.exists() && !rootDir.mkpath(line.at(1))) { // Create texdir - qDebug() << "[ERROR] Couldn't create " << line.at(1) << "."; - return false; - } - if (!addTextures(texdir, newTexdir)) { // Recursive compress and copy + if (!addTextures(texdir)) { // Recursive compress and copy return false; } } else if (line.first() == lodField) { - QFileInfo lod(QFileInfo(fst).path() + "/" + line.at(1)); + QFileInfo lod(QFileInfo(fst).path() + "/" + line[1]); if (!lod.exists() || !lod.isFile()) { // Check existence qDebug() << "[ERROR] FBX file " << lod.absoluteFilePath() << " doesn't exist."; - return false; - } else if (lod.size() > MAX_FBX_SIZE) { // Check size - qDebug() << "[ERROR] FBX file " << lod.absoluteFilePath() << " too big, over " << MAX_FBX_SIZE << " MB.";\ - return false; + //return false; } else { // Compress and copy - compressFile(lod.filePath(), rootDir.path() + "/" + line.at(1)); + _lodFiles.push_back(rootDir.path() + "/" + line[1]); + _totalSize += lod.size(); + compressFile(lod.filePath(), _lodFiles.back()); } } } // Compress and copy the fst - compressFile(fst.fileName(), - rootDir.path() + "/" + QFileInfo(fst).fileName()); - - tempRootDir.setAutoRemove(false); + _fstFile = rootDir.path() + "/" + QFileInfo(fst).fileName(); + _totalSize += QFileInfo(fst).size(); + compressFile(fst.fileName(), _fstFile); return true; } -bool FstReader::addTextures(QFileInfo& texdir, QDir newTexdir) { +bool FstReader::send() { + QString command = QString("curl -F \"model_name=%1\"").arg(_modelName); + + command += QString(" -F \"fst=@%1\" -F \"fbx=@%2\"").arg(_fstFile, _fbxFile); + for (int i = 0; i < _lodFiles.size(); ++i) { + command += QString(" -F \"lod%1=@%2\"").arg(i).arg(_lodFiles[i]); + } + for (int i = 0; i < _textureFiles.size(); ++i) { + command += QString(" -F \"lod%1=@%2\"").arg(i).arg(_textureFiles[i]); + } + command += " http://localhost:3000/api/v1/models/?access_token\\=017894b7312316a2b5025613fcc58c13bc701da9b797cca34b60aae9d1c53acb --trace-ascii /dev/stdout"; + + qDebug() << "[DEBUG] " << command; + + return true; +} + +bool FstReader::addTextures(QFileInfo& texdir) { QStringList filter; filter << "*.png" << "*.tiff" << "*.jpg" << "*.jpeg"; @@ -110,19 +118,11 @@ bool FstReader::addTextures(QFileInfo& texdir, QDir newTexdir) { QDir::NoSymLinks); foreach (QFileInfo info, list) { if (info.isFile()) { - if (info.size() > MAX_TEXTURE_SIZE) { - qDebug() << "[ERROR] Texture " << info.absoluteFilePath() - << "too big, file over " << MAX_TEXTURE_SIZE << " Bytes."; - return false; - } - compressFile(info.canonicalFilePath(), newTexdir.path() + "/" + info.fileName()); + _textureFiles.push_back(_zipDir.path() + "/" + info.fileName()); + _totalSize += info.size(); + compressFile(info.canonicalFilePath(), _textureFiles.back()); } else if (info.isDir()) { - if (newTexdir.mkdir(info.fileName())) { - qDebug() << "[ERROR] Couldn't create texdir."; - return false; - } - QDir texdirChild(newTexdir.canonicalPath() + "/" + info.fileName()); - if (!addTextures(info, QDir(info.canonicalFilePath()))) { + if (!addTextures(info)) { return false; } } else { diff --git a/libraries/shared/src/FstReader.h b/libraries/shared/src/FstReader.h index 44cd3f95cd..c5816ea415 100644 --- a/libraries/shared/src/FstReader.h +++ b/libraries/shared/src/FstReader.h @@ -14,23 +14,34 @@ #include #include + +static const QString nameField = "name"; static const QString filenameField = "filename"; static const QString texdirField = "texdir"; static const QString lodField = "lod"; -static const int MAX_FBX_SIZE = 1024 * 1024; // 1 MB -static const int MAX_TEXTURE_SIZE = 1024 * 1024; // 1 MB +static const int MAX_SIZE = 1024 * 1024; // 1 MB class FstReader { public: FstReader(); bool zip(); + bool send(); private: QTemporaryDir _zipDir; - bool addTextures(QFileInfo& texdir, QDir newTexdir); + QString _modelName; + QString _fstFile; + QString _fbxFile; + QStringList _lodFiles; + QStringList _textureFiles; + + int _totalSize; + + + bool addTextures(QFileInfo& texdir); bool compressFile(const QString& inFileName, const QString& outFileName); }; From 9402a5852c79e9b1361afbc3337ddb0150ae9600 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 12 Mar 2014 12:20:43 -0700 Subject: [PATCH 11/44] Fixed review comments --- examples/editVoxels.js | 2 +- interface/interface_en.ts | 8 ++++---- interface/src/Application.cpp | 7 ++++--- interface/src/Application.h | 6 ++++-- interface/src/ClipboardScriptingInterface.cpp | 6 +++--- interface/src/ui/LocalVoxelsOverlay.cpp | 5 ++++- interface/src/ui/Volume3DOverlay.cpp | 3 --- 7 files changed, 20 insertions(+), 17 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 956b6f1d1d..31d483d798 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -308,7 +308,7 @@ function initImport() { } function importVoxels() { - if (Clipboard.importVoxels() == 0) { + if (Clipboard.importVoxels()) { isImporting = true; if (importScale <= 0) { importScale = 1; diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 76a5d47101..4aa920945b 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -4,22 +4,22 @@ Application - + Export Voxels - + Sparse Voxel Octree Files (*.svo) - + Open Script - + JavaScript Files (*.js) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 771f02750d..bfcd7770eb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -140,6 +140,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _fps(120.0f), _justStarted(true), _voxelImporter(NULL), + _importSucceded(false), _sharedVoxelSystem(TREE_SCALE, DEFAULT_MAX_VOXELS_PER_SYSTEM, &_clipboard), _wantToKillLocalVoxels(false), _audioScope(256, 200, true), @@ -1387,7 +1388,7 @@ void Application::exportVoxels(const VoxelDetail& sourceVoxel) { } void Application::importVoxels() { - int result = 1; + _importSucceded = false; if (!_voxelImporter) { _voxelImporter = new VoxelImporter(_window); @@ -1396,7 +1397,7 @@ void Application::importVoxels() { if (!_voxelImporter->exec()) { qDebug() << "[DEBUG] Import succeeded." << endl; - result = 0; + _importSucceded = true; } else { qDebug() << "[DEBUG] Import failed." << endl; if (_sharedVoxelSystem.getTree() == _voxelImporter->getVoxelTree()) { @@ -1408,7 +1409,7 @@ void Application::importVoxels() { // restore the main window's active state _window->activateWindow(); - emit importDone(result); + emit importDone(); } void Application::cutVoxels(const VoxelDetail& sourceVoxel) { diff --git a/interface/src/Application.h b/interface/src/Application.h index c6fc7140eb..637a79c422 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -157,6 +157,7 @@ public: VoxelTree* getVoxelTree() { return _voxels.getTree(); } ParticleTreeRenderer* getParticles() { return &_particles; } MetavoxelSystem* getMetavoxels() { return &_metavoxels; } + bool getImportSucceded() { return _importSucceded; } VoxelSystem* getSharedVoxelSystem() { return &_sharedVoxelSystem; } VoxelTree* getClipboard() { return &_clipboard; } Environment* getEnvironment() { return &_environment; } @@ -225,8 +226,8 @@ signals: /// Fired when we're rendering in-world interface elements; allows external parties to hook in. void renderingInWorldInterface(); - /// Fired when the import window is closed with a return code. - void importDone(int); + /// Fired when the import window is closed + void importDone(); public slots: void domainChanged(const QString& domainHostname); @@ -368,6 +369,7 @@ private: VoxelSystem _voxels; VoxelTree _clipboard; // if I copy/paste VoxelImporter* _voxelImporter; + bool _importSucceded; VoxelSystem _sharedVoxelSystem; ViewFrustum _sharedVoxelSystemViewFrustum; diff --git a/interface/src/ClipboardScriptingInterface.cpp b/interface/src/ClipboardScriptingInterface.cpp index e8a02b041b..2ddef524aa 100644 --- a/interface/src/ClipboardScriptingInterface.cpp +++ b/interface/src/ClipboardScriptingInterface.cpp @@ -77,11 +77,11 @@ void ClipboardScriptingInterface::exportVoxel(float x, float y, float z, float s bool ClipboardScriptingInterface::importVoxels() { qDebug() << "[DEBUG] Importing ... "; QEventLoop loop; - connect(Application::getInstance(), SIGNAL(importDone(int)), &loop, SLOT(quit())); + connect(Application::getInstance(), SIGNAL(importDone()), &loop, SLOT(quit())); emit readyToImport(); - int returnCode = loop.exec(); + loop.exec(); - return returnCode; + return Application::getInstance()->getImportSucceded(); } void ClipboardScriptingInterface::nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec) { diff --git a/interface/src/ui/LocalVoxelsOverlay.cpp b/interface/src/ui/LocalVoxelsOverlay.cpp index fde03b85cb..71ae9ec74e 100644 --- a/interface/src/ui/LocalVoxelsOverlay.cpp +++ b/interface/src/ui/LocalVoxelsOverlay.cpp @@ -61,8 +61,11 @@ void LocalVoxelsOverlay::render() { void LocalVoxelsOverlay::setProperties(const QScriptValue &properties) { Volume3DOverlay::setProperties(properties); + if (properties.property("scale").isValid()) { + setSize(properties.property("scale").toVariant().toFloat()); + } + QScriptValue treeName = properties.property("name"); - // if "end" property was not there, check to see if they included aliases: endPoint, or p2 if (treeName.isValid()) { if ((_treeName = treeName.toString()) == DOMAIN_TREE_NAME) { qDebug() << "addOverlay(): Can't create overlay from domain tree"; diff --git a/interface/src/ui/Volume3DOverlay.cpp b/interface/src/ui/Volume3DOverlay.cpp index a4e6c76a12..dbc1582cc5 100644 --- a/interface/src/ui/Volume3DOverlay.cpp +++ b/interface/src/ui/Volume3DOverlay.cpp @@ -31,9 +31,6 @@ void Volume3DOverlay::setProperties(const QScriptValue& properties) { if (properties.property("size").isValid()) { setSize(properties.property("size").toVariant().toFloat()); } - if (properties.property("scale").isValid()) { - setSize(properties.property("scale").toVariant().toFloat()); - } if (properties.property("isSolid").isValid()) { setIsSolid(properties.property("isSolid").toVariant().toBool()); From 5941ad0dd1e791ad03bd5c9a276a72cc16c4d7d3 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 12 Mar 2014 14:08:23 -0700 Subject: [PATCH 12/44] Changed lockForWrite() to lockForRead() --- interface/src/ui/LocalVoxelsOverlay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/LocalVoxelsOverlay.cpp b/interface/src/ui/LocalVoxelsOverlay.cpp index 71ae9ec74e..7eaf9ed5c5 100644 --- a/interface/src/ui/LocalVoxelsOverlay.cpp +++ b/interface/src/ui/LocalVoxelsOverlay.cpp @@ -40,7 +40,7 @@ void LocalVoxelsOverlay::update(float deltatime) { _voxelSystem->init(); } - _tree->lockForWrite(); + _tree->lockForRead(); if (_visible && _voxelCount != _tree->getOctreeElementsCount()) { _voxelCount = _tree->getOctreeElementsCount(); _voxelSystem->forceRedrawEntireTree(); From 9c61f12926719adff0d7305f77461daa52b3faee Mon Sep 17 00:00:00 2001 From: Geenz Date: Wed, 12 Mar 2014 19:10:26 -0400 Subject: [PATCH 13/44] Support for an idle render time step. The basics of this is, if the application has changed its active state then we only call paintGL every N milliseconds. Currently the default time step is 100 milliseconds. --- interface/src/GLCanvas.cpp | 29 +++++++++++++++++++++++++++-- interface/src/GLCanvas.h | 8 ++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 7bc79e56d8..a098af7fbe 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -12,17 +12,21 @@ #include #include -GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer, QGL::NoStencilBuffer)) { +GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer, QGL::NoStencilBuffer)), _throttleRendering(false), _idleRenderInterval(100) { } void GLCanvas::initializeGL() { Application::getInstance()->initializeGL(); setAttribute(Qt::WA_AcceptTouchEvents); setAcceptDrops(true); + connect(Application::getInstance(), &Application::focusChanged, this, &GLCanvas::activeChanged); + connect(&_frameTimer, &QTimer::timeout, this, &GLCanvas::throttleRender); } void GLCanvas::paintGL() { - Application::getInstance()->paintGL(); + if (!_throttleRendering) { + Application::getInstance()->paintGL(); + } } void GLCanvas::resizeGL(int width, int height) { @@ -49,6 +53,27 @@ void GLCanvas::mouseReleaseEvent(QMouseEvent* event) { Application::getInstance()->mouseReleaseEvent(event); } +void GLCanvas::activeChanged() +{ + if (!isActiveWindow()) + { + if (!_throttleRendering) + { + _frameTimer.start(_idleRenderInterval); + _throttleRendering = true; + } + } else { + _frameTimer.stop(); + _throttleRendering = false; + } +} + +void GLCanvas::throttleRender() +{ + _frameTimer.start(_idleRenderInterval); + 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 0f0cb5c7d0..7e4a4d0334 100644 --- a/interface/src/GLCanvas.h +++ b/interface/src/GLCanvas.h @@ -10,6 +10,7 @@ #define __hifi__GLCanvas__ #include +#include /// customized canvas that simply forwards requests/events to the singleton application class GLCanvas : public QGLWidget { @@ -17,6 +18,10 @@ public: GLCanvas(); protected: + QTimer _frameTimer; + bool _throttleRendering; + int _idleRenderInterval; + virtual void initializeGL(); virtual void paintGL(); virtual void resizeGL(int width, int height); @@ -34,6 +39,9 @@ protected: virtual void dragEnterEvent(QDragEnterEvent *event); virtual void dropEvent(QDropEvent* event); + + void activeChanged(); + void throttleRender(); }; #endif /* defined(__hifi__GLCanvas__) */ From 3b653ca542ca3313f3594c02182928e583b43d81 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 12 Mar 2014 17:00:12 -0700 Subject: [PATCH 14/44] add a sendAvatarAudioStream option to Agent for mixer load testing, closes #2291 --- assignment-client/src/Agent.cpp | 28 +++++++++++++++++++- assignment-client/src/Agent.h | 7 +++++ libraries/script-engine/src/ScriptEngine.cpp | 27 +++++++++++++------ libraries/script-engine/src/ScriptEngine.h | 11 ++++++-- 4 files changed, 62 insertions(+), 11 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 13b1f2bdcf..9d4f07043d 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -25,7 +26,8 @@ Agent::Agent(const QByteArray& packet) : ThreadedAssignment(packet), _voxelEditSender(), - _particleEditSender() + _particleEditSender(), + _avatarAudioStream(NULL) { // be the parent of the script engine so it gets moved when we do _scriptEngine.setParent(this); @@ -34,6 +36,30 @@ Agent::Agent(const QByteArray& packet) : _scriptEngine.getParticlesScriptingInterface()->setPacketSender(&_particleEditSender); } +Agent::~Agent() { + delete _avatarAudioStream; +} + +const int SCRIPT_AUDIO_BUFFER_SAMPLES = (SCRIPT_DATA_CALLBACK_USECS * SAMPLE_RATE) / (1000 * 1000); + +void Agent::setSendAvatarAudioStream(bool sendAvatarAudioStream) { + if (sendAvatarAudioStream) { + // the agentAudioStream number of samples is related to the ScriptEngine callback rate + _avatarAudioStream = new int16_t[SCRIPT_AUDIO_BUFFER_SAMPLES]; + + // fill the _audioStream with zeroes to start + memset(_avatarAudioStream, 0, SCRIPT_AUDIO_BUFFER_SAMPLES * sizeof(int16_t)); + + _scriptEngine.setNumAvatarAudioBufferSamples(SCRIPT_AUDIO_BUFFER_SAMPLES); + _scriptEngine.setAvatarAudioBuffer(_avatarAudioStream); + } else { + delete _avatarAudioStream; + _avatarAudioStream = NULL; + + _scriptEngine.setAvatarAudioBuffer(NULL); + } +} + void Agent::readPendingDatagrams() { QByteArray receivedPacket; HifiSockAddr senderSockAddr; diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 1b41636874..a051f42faf 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -28,12 +28,17 @@ class Agent : public ThreadedAssignment { Q_OBJECT Q_PROPERTY(bool isAvatar READ isAvatar WRITE setIsAvatar) + Q_PROPERTY(bool sendAvatarAudioStream READ isSendingAvatarAudioStream WRITE setSendAvatarAudioStream) public: Agent(const QByteArray& packet); + ~Agent(); void setIsAvatar(bool isAvatar) { QMetaObject::invokeMethod(&_scriptEngine, "setIsAvatar", Q_ARG(bool, isAvatar)); } bool isAvatar() const { return _scriptEngine.isAvatar(); } + void setSendAvatarAudioStream(bool sendAvatarAudioStream); + bool isSendingAvatarAudioStream() const { return (bool) _scriptEngine.sendsAvatarAudioStream(); } + public slots: void run(); void readPendingDatagrams(); @@ -45,6 +50,8 @@ private: ParticleTreeHeadlessViewer _particleViewer; VoxelTreeHeadlessViewer _voxelViewer; + + int16_t* _avatarAudioStream; }; #endif /* defined(__hifi__Agent__) */ diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 04916687fb..9a672317ae 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -28,8 +28,6 @@ #include "LocalVoxels.h" #include "ScriptEngine.h" -const unsigned int VISUAL_DATA_CALLBACK_USECS = (1.0 / 60.0) * 1000 * 1000; - int ScriptEngine::_scriptNumber = 1; VoxelsScriptingInterface ScriptEngine::_voxelsScriptingInterface; ParticlesScriptingInterface ScriptEngine::_particlesScriptingInterface; @@ -54,6 +52,7 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems, co _avatarIdentityTimer(NULL), _avatarBillboardTimer(NULL), _timerFunctionMap(), + _avatarAudioBuffer(NULL), _controllerScriptingInterface(controllerScriptingInterface), _avatarData(NULL), _wantMenuItems(wantMenuItems), @@ -77,9 +76,6 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems, co _scriptNumber++; } -ScriptEngine::~ScriptEngine() { -} - void ScriptEngine::setIsAvatar(bool isAvatar) { _isAvatar = isAvatar; @@ -169,8 +165,8 @@ void ScriptEngine::init() { _engine.globalObject().setProperty("TREE_SCALE", treeScaleValue); // let the VoxelPacketSender know how frequently we plan to call it - _voxelsScriptingInterface.getVoxelPacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); - _particlesScriptingInterface.getParticlePacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); + _voxelsScriptingInterface.getVoxelPacketSender()->setProcessCallIntervalHint(SCRIPT_DATA_CALLBACK_USECS); + _particlesScriptingInterface.getParticlePacketSender()->setProcessCallIntervalHint(SCRIPT_DATA_CALLBACK_USECS); } @@ -228,7 +224,7 @@ void ScriptEngine::run() { qint64 lastUpdate = usecTimestampNow(); while (!_isFinished) { - int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * VISUAL_DATA_CALLBACK_USECS) - usecTimestampNow(); + int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - usecTimestampNow(); if (usecToSleep > 0) { usleep(usecToSleep); } @@ -268,6 +264,21 @@ void ScriptEngine::run() { avatarPacket.append(_avatarData->toByteArray()); nodeList->broadcastToNodes(avatarPacket, NodeSet() << NodeType::AvatarMixer); + + if (_avatarAudioBuffer && _numAvatarAudioBufferSamples > 0) { + // if have an avatar audio stream then send it out to our audio-mixer + QByteArray audioPacket = byteArrayWithPopulatedHeader(PacketTypeMicrophoneAudioNoEcho); + QDataStream packetStream(&audioPacket, QIODevice::Append); + + // use the orientation and position of this avatar for the source of this audio + packetStream.writeRawData(reinterpret_cast(&_avatarData->getPosition()), sizeof(glm::vec3)); + glm::quat headOrientation = _avatarData->getHeadOrientation(); + packetStream.writeRawData(reinterpret_cast(&headOrientation), sizeof(glm::quat)); + packetStream.writeRawData(reinterpret_cast(_avatarAudioBuffer), + _numAvatarAudioBufferSamples * sizeof(int16_t)); + + nodeList->broadcastToNodes(audioPacket, NodeSet() << NodeType::AudioMixer); + } } qint64 now = usecTimestampNow(); diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 186524eb7f..9a1d2172dd 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -28,6 +28,8 @@ class ParticlesScriptingInterface; const QString NO_SCRIPT(""); +const unsigned int SCRIPT_DATA_CALLBACK_USECS = roundf((1.0 / 60.0) * 1000 * 1000); + class ScriptEngine : public QObject { Q_OBJECT public: @@ -35,8 +37,6 @@ public: const QString& scriptMenuName = QString(""), AbstractControllerScriptingInterface* controllerScriptingInterface = NULL); - ~ScriptEngine(); - /// Access the VoxelsScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener static VoxelsScriptingInterface* getVoxelsScriptingInterface() { return &_voxelsScriptingInterface; } @@ -56,6 +56,11 @@ public: void setAvatarData(AvatarData* avatarData, const QString& objectName); + void setAvatarAudioBuffer(int16_t* avatarAudioBuffer) { _avatarAudioBuffer = avatarAudioBuffer; } + bool sendsAvatarAudioStream() const { return (bool) _avatarAudioBuffer; } + void setNumAvatarAudioBufferSamples(int numAvatarAudioBufferSamples) + { _numAvatarAudioBufferSamples = numAvatarAudioBufferSamples; } + void init(); void run(); /// runs continuously until Agent.stop() is called void evaluate(); /// initializes the engine, and evaluates the script, but then returns control to caller @@ -86,6 +91,8 @@ protected: QTimer* _avatarIdentityTimer; QTimer* _avatarBillboardTimer; QHash _timerFunctionMap; + int16_t* _avatarAudioBuffer; + int _numAvatarAudioBufferSamples; private: void sendAvatarIdentityPacket(); From bd6c42a68505465fd1e4bc9b068dda4733c399bd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 12 Mar 2014 17:32:52 -0700 Subject: [PATCH 15/44] define roundf for use on Win from ScriptEngine --- libraries/script-engine/src/ScriptEngine.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 9a1d2172dd..7dadc17cc6 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -20,14 +20,20 @@ #include -class ParticlesScriptingInterface; - #include "AbstractControllerScriptingInterface.h" #include "Quat.h" #include "Vec3.h" +class ParticlesScriptingInterface; + const QString NO_SCRIPT(""); +#ifdef Q_OS_WIN32 +inline double roundf(double value) { + return (value > 0.0) ? floor(value + 0.5) : ceil(value - 0.5); +} +#endif + const unsigned int SCRIPT_DATA_CALLBACK_USECS = roundf((1.0 / 60.0) * 1000 * 1000); class ScriptEngine : public QObject { From e27af75ad2b00b8c6eab3b802a0b4850f9bad49c Mon Sep 17 00:00:00 2001 From: Geenz Date: Wed, 12 Mar 2014 20:49:58 -0400 Subject: [PATCH 16/44] Use QApplication::applicationState to detect if we're in the background. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit May want to expand upon this at some point; if we’re hidden we most definitely *do not* want to render anything --- interface/src/GLCanvas.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index a098af7fbe..dc76858e1b 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -53,12 +53,9 @@ void GLCanvas::mouseReleaseEvent(QMouseEvent* event) { Application::getInstance()->mouseReleaseEvent(event); } -void GLCanvas::activeChanged() -{ - if (!isActiveWindow()) - { - if (!_throttleRendering) - { +void GLCanvas::activeChanged() { + if (Application::applicationState() != Qt::ApplicationActive) { + if (!_throttleRendering) { _frameTimer.start(_idleRenderInterval); _throttleRendering = true; } From 54d73d4a6458df8041459b410e7cadd2382ebb5a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 12 Mar 2014 17:50:58 -0700 Subject: [PATCH 17/44] use floor since round is missing on windows --- assignment-client/src/Agent.cpp | 2 +- libraries/script-engine/src/ScriptEngine.h | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 9d4f07043d..46f4d233c2 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -40,7 +40,7 @@ Agent::~Agent() { delete _avatarAudioStream; } -const int SCRIPT_AUDIO_BUFFER_SAMPLES = (SCRIPT_DATA_CALLBACK_USECS * SAMPLE_RATE) / (1000 * 1000); +const int SCRIPT_AUDIO_BUFFER_SAMPLES = floor(((SCRIPT_DATA_CALLBACK_USECS * SAMPLE_RATE) / (1000 * 1000)) + 0.5); void Agent::setSendAvatarAudioStream(bool sendAvatarAudioStream) { if (sendAvatarAudioStream) { diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 7dadc17cc6..606d0aabf4 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -28,13 +28,7 @@ class ParticlesScriptingInterface; const QString NO_SCRIPT(""); -#ifdef Q_OS_WIN32 -inline double roundf(double value) { - return (value > 0.0) ? floor(value + 0.5) : ceil(value - 0.5); -} -#endif - -const unsigned int SCRIPT_DATA_CALLBACK_USECS = roundf((1.0 / 60.0) * 1000 * 1000); +const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0 / 60.0f) * 1000 * 1000) + 0.5); class ScriptEngine : public QObject { Q_OBJECT From 292f37154bab0feaf189fe3eef169119303b0f59 Mon Sep 17 00:00:00 2001 From: Geenz Date: Wed, 12 Mar 2014 21:08:55 -0400 Subject: [PATCH 18/44] Use the applicationStateChanged signal. --- interface/src/GLCanvas.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index dc76858e1b..52fd91130c 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -19,7 +19,7 @@ void GLCanvas::initializeGL() { Application::getInstance()->initializeGL(); setAttribute(Qt::WA_AcceptTouchEvents); setAcceptDrops(true); - connect(Application::getInstance(), &Application::focusChanged, this, &GLCanvas::activeChanged); + connect(Application::getInstance(), &Application::applicationStateChanged, this, &GLCanvas::activeChanged); connect(&_frameTimer, &QTimer::timeout, this, &GLCanvas::throttleRender); } From d580f177a3f93cbbc5158c637e396248be5dd8cc Mon Sep 17 00:00:00 2001 From: Geenz Date: Wed, 12 Mar 2014 21:17:54 -0400 Subject: [PATCH 19/44] Refactor if..else into a switch. Also support the hidden and suspended states. --- interface/src/GLCanvas.cpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 52fd91130c..f2a88fea6d 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -54,14 +54,27 @@ void GLCanvas::mouseReleaseEvent(QMouseEvent* event) { } void GLCanvas::activeChanged() { - if (Application::applicationState() != Qt::ApplicationActive) { - if (!_throttleRendering) { - _frameTimer.start(_idleRenderInterval); - _throttleRendering = true; - } - } else { - _frameTimer.stop(); - _throttleRendering = false; + switch (Application::applicationState()) { + 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) { + _frameTimer.start(_idleRenderInterval); + _throttleRendering = true; + } + break; } } From 727903b216fd82b5b47e710c70d653cf4a08980d Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Thu, 13 Mar 2014 01:55:42 +0200 Subject: [PATCH 20/44] Changed the chat window to a popup with a custom closing button. --- interface/CMakeLists.txt | 7 ++- interface/interface_en.ts | 16 ++--- interface/resources/images/close.svg | 14 +++++ interface/resources/resources.qrc | 5 ++ interface/src/Menu.cpp | 9 +-- interface/src/ui/ChatWindow.cpp | 2 +- interface/ui/chatWindow.ui | 89 ++++++++++++++++++++++------ 7 files changed, 108 insertions(+), 34 deletions(-) create mode 100644 interface/resources/images/close.svg create mode 100644 interface/resources/resources.qrc diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index d049fc0154..1cb0344f86 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -73,8 +73,13 @@ file (GLOB_RECURSE QT_UI_FILES ui/*.ui) # have qt5 wrap them and generate the appropriate header files qt5_wrap_ui(QT_UI_HEADERS "${QT_UI_FILES}") +# grab the resource files in resources +file (GLOB_RECURSE QT_RESOURCE_FILES resources/*.qrc) +# have qt5 wrap them and generate the appropriate source files +qt5_add_resources(QT_RESOURCES "${QT_RESOURCE_FILES}") + # add them to the interface source files -set(INTERFACE_SRCS ${INTERFACE_SRCS} "${QT_UI_HEADERS}") +set(INTERFACE_SRCS ${INTERFACE_SRCS} "${QT_UI_HEADERS}" "${QT_RESOURCES}") set(QM ${TARGET_NAME}_en.qm) set(TS ${TARGET_NAME}_en.ts) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 175a1f4525..72e5ee3d3e 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -4,22 +4,22 @@ Application - + Export Voxels - + Sparse Voxel Octree Files (*.svo) - + Open Script - + JavaScript Files (*.js) @@ -28,19 +28,19 @@ ChatWindow - + Chat - + Connecting to XMPP... - - + + online now: diff --git a/interface/resources/images/close.svg b/interface/resources/images/close.svg new file mode 100644 index 0000000000..8fe4bf4bdb --- /dev/null +++ b/interface/resources/images/close.svg @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/interface/resources/resources.qrc b/interface/resources/resources.qrc new file mode 100644 index 0000000000..372fa8b1d4 --- /dev/null +++ b/interface/resources/resources.qrc @@ -0,0 +1,5 @@ + + + images/close.svg + + diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index f73da0400a..95b94bdcbf 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1039,15 +1039,10 @@ void Menu::showChat() { if (!_chatWindow) { _chatWindow = new ChatWindow(); QMainWindow* mainWindow = Application::getInstance()->getWindow(); - - // the height of the title bar is given by frameGeometry().height() - geometry().height() - // however, frameGeometry() is initialised after showing (Qt queries the OS windowing system) - // on the other hand, moving a window after showing it flickers; so just use some reasonable value - int titleBarHeight = 16; _chatWindow->setGeometry(mainWindow->width() - _chatWindow->width(), - mainWindow->geometry().y() + titleBarHeight, + mainWindow->geometry().y(), _chatWindow->width(), - mainWindow->height() - titleBarHeight); + mainWindow->height()); _chatWindow->show(); } _chatWindow->raise(); diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index 5fc5d56430..3a1c26ee35 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -28,7 +28,7 @@ const int NUM_MESSAGES_TO_TIME_STAMP = 20; const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?))://\\S+)"); ChatWindow::ChatWindow() : - QDialog(Application::getInstance()->getGLWidget(), Qt::Tool), + QDialog(Application::getInstance()->getGLWidget(), Qt::CustomizeWindowHint), ui(new Ui::ChatWindow), numMessagesAfterLastTimeStamp(0) { diff --git a/interface/ui/chatWindow.ui b/interface/ui/chatWindow.ui index d254efb71a..9959c638b2 100644 --- a/interface/ui/chatWindow.ui +++ b/interface/ui/chatWindow.ui @@ -46,20 +46,53 @@ - - - - 0 - 0 - - - - font-weight: bold; color: palette(shadow); margin-bottom: 4px; - - - online now: - - + + + + + + 0 + 0 + + + + font-weight: bold; color: palette(shadow); margin-bottom: 4px; + + + online now: + + + + + + + + 0 + 0 + + + + + 16 + 16 + + + + Qt::NoFocus + + + + + + + :/images/close.svg:/images/close.svg + + + true + + + + @@ -81,7 +114,7 @@ 0 0 358 - 454 + 452 @@ -133,6 +166,9 @@ QAbstractScrollArea::AdjustToContents + + true + @@ -141,6 +177,25 @@ messagePlainTextEdit messagesScrollArea - - + + + + + + closeButton + clicked() + ChatWindow + accept() + + + 342 + 42 + + + 550 + 42 + + + + From 442ca145da90a46620eb3495afc541b2aff382e8 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Thu, 13 Mar 2014 14:07:21 +0200 Subject: [PATCH 21/44] Hid the chat window rather than close it in order to preserve sent messages. --- interface/interface_en.ts | 8 ++++---- interface/src/Menu.cpp | 2 ++ interface/src/ui/ChatWindow.cpp | 7 +++++++ interface/src/ui/ChatWindow.h | 2 ++ interface/ui/chatWindow.ui | 4 ++-- 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 72e5ee3d3e..1d962393d7 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -45,7 +45,7 @@ - + day %n day @@ -53,7 +53,7 @@ - + hour %n hour @@ -61,7 +61,7 @@ - + minute %n minute @@ -76,7 +76,7 @@ - + %1 online now: diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 95b94bdcbf..00ae0a3772 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1043,6 +1043,8 @@ void Menu::showChat() { mainWindow->geometry().y(), _chatWindow->width(), mainWindow->height()); + } + if (!_chatWindow->isVisible()) { _chatWindow->show(); } _chatWindow->raise(); diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index 3a1c26ee35..d4f257c0f7 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -50,6 +50,7 @@ ChatWindow::ChatWindow() : startTimerForTimeStamps(); } else { ui->numOnlineLabel->hide(); + ui->closeButton->hide(); ui->usersWidget->hide(); ui->messagesScrollArea->hide(); ui->messagePlainTextEdit->hide(); @@ -71,6 +72,10 @@ ChatWindow::~ChatWindow() { delete ui; } +void ChatWindow::reject() { + hide(); +} + bool ChatWindow::eventFilter(QObject* sender, QEvent* event) { Q_UNUSED(sender); @@ -136,9 +141,11 @@ void ChatWindow::startTimerForTimeStamps() { void ChatWindow::connected() { ui->connectingToXMPPLabel->hide(); ui->numOnlineLabel->show(); + ui->closeButton->show(); ui->usersWidget->show(); ui->messagesScrollArea->show(); ui->messagePlainTextEdit->show(); + ui->messagePlainTextEdit->setFocus(); #ifdef HAVE_QXMPP const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom(); connect(publicChatRoom, SIGNAL(participantsChanged()), this, SLOT(participantsChanged())); diff --git a/interface/src/ui/ChatWindow.h b/interface/src/ui/ChatWindow.h index 9250da8933..57da4da45d 100644 --- a/interface/src/ui/ChatWindow.h +++ b/interface/src/ui/ChatWindow.h @@ -33,6 +33,8 @@ public: ChatWindow(); ~ChatWindow(); + virtual void reject(); + protected: bool eventFilter(QObject* sender, QEvent* event); diff --git a/interface/ui/chatWindow.ui b/interface/ui/chatWindow.ui index 9959c638b2..ecb4d79c41 100644 --- a/interface/ui/chatWindow.ui +++ b/interface/ui/chatWindow.ui @@ -185,10 +185,10 @@ closeButton clicked() ChatWindow - accept() + hide() - 342 + 390 42 From 2e119fa0fe24152e95472f4928ee187f6c51effc Mon Sep 17 00:00:00 2001 From: Geenz Date: Thu, 13 Mar 2014 11:41:15 -0400 Subject: [PATCH 22/44] Skip rendering when we're minimized. --- interface/src/GLCanvas.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index f2a88fea6d..bf99608c07 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -11,6 +11,7 @@ #include "GLCanvas.h" #include #include +#include GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer, QGL::NoStencilBuffer)), _throttleRendering(false), _idleRenderInterval(100) { } @@ -24,7 +25,7 @@ void GLCanvas::initializeGL() { } void GLCanvas::paintGL() { - if (!_throttleRendering) { + if (!_throttleRendering && !Application::getInstance()->getWindow()->isMinimized()) { Application::getInstance()->paintGL(); } } @@ -78,10 +79,11 @@ void GLCanvas::activeChanged() { } } -void GLCanvas::throttleRender() -{ +void GLCanvas::throttleRender() { _frameTimer.start(_idleRenderInterval); - Application::getInstance()->paintGL(); + if (!Application::getInstance()->getWindow()->isMinimized()) { + Application::getInstance()->paintGL(); + } } int updateTime = 0; From b2a29cb84f282b6eae3b3f4d6ce81509b43c7dec Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 10:56:19 -0700 Subject: [PATCH 23/44] Fixes for Linux build. --- interface/CMakeLists.txt | 6 +----- interface/interface_en.ts | 8 ++++---- interface/src/Application.cpp | 2 -- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 1cb0344f86..f39e7d7e50 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -230,11 +230,7 @@ if (APPLE) RUNTIME DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/install" COMPONENT Runtime ) else (APPLE) - # remove and then copy the resources files beside the executable - add_custom_command(TARGET ${TARGET_NAME} POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E remove_directory - $/resources - ) + # copy the resources files beside the executable add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_directory "${PROJECT_SOURCE_DIR}/resources" diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 1d962393d7..80433032dc 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -4,22 +4,22 @@ Application - + Export Voxels - + Sparse Voxel Octree Files (*.svo) - + Open Script - + JavaScript Files (*.js) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8091e58545..96129e0161 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -121,8 +121,6 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt QString& Application::resourcesPath() { #ifdef Q_OS_MAC static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/../Resources/"; -#elif defined Q_OS_LINUX - static QString staticResourcePath = "resources/"; #else static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/resources/"; #endif From 43feef3ebdd7a871cbd7858f800054d255b37e89 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 12:03:02 -0700 Subject: [PATCH 24/44] Only update the full set of joints when we've received new data from the mixer. Closes #2274. --- interface/src/avatar/Avatar.cpp | 9 ++++++-- interface/src/avatar/Avatar.h | 1 + interface/src/avatar/FaceModel.cpp | 6 +++--- interface/src/avatar/FaceModel.h | 2 +- interface/src/avatar/SkeletonModel.cpp | 4 ++-- interface/src/avatar/SkeletonModel.h | 2 +- interface/src/renderer/Model.cpp | 29 +++++++++++++------------- interface/src/renderer/Model.h | 4 ++-- 8 files changed, 32 insertions(+), 25 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index b7e3d675a5..8333b51aaf 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -56,7 +56,8 @@ Avatar::Avatar() : _owningAvatarMixer(), _collisionFlags(0), _initialized(false), - _shouldRenderBillboard(true) + _shouldRenderBillboard(true), + _modelsDirty(true) { // we may have been created in the network thread, but we live in the main thread moveToThread(Application::getInstance()->thread()); @@ -119,7 +120,8 @@ void Avatar::simulate(float deltaTime) { } glm::vec3 headPosition = _position; if (!_shouldRenderBillboard) { - _skeletonModel.simulate(deltaTime); + _skeletonModel.simulate(deltaTime, _modelsDirty); + _modelsDirty = false; _skeletonModel.getHeadPosition(headPosition); } Head* head = getHead(); @@ -618,6 +620,9 @@ int Avatar::parseData(const QByteArray& packet) { const float MOVE_DISTANCE_THRESHOLD = 0.001f; _moving = glm::distance(oldPosition, _position) > MOVE_DISTANCE_THRESHOLD; + // note that we need to update our models + _modelsDirty = true; + return bytesRead; } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index bba86828cb..b1812a12a9 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -187,6 +187,7 @@ private: bool _initialized; QScopedPointer _billboardTexture; bool _shouldRenderBillboard; + bool _modelsDirty; void renderBody(); void renderBillboard(); diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index eba8f7bf1a..f4ee6859ed 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -18,9 +18,9 @@ FaceModel::FaceModel(Head* owningHead) : { } -void FaceModel::simulate(float deltaTime, bool delayLoad) { +void FaceModel::simulate(float deltaTime) { if (!isActive()) { - Model::simulate(deltaTime, delayLoad); + Model::simulate(deltaTime); return; } Avatar* owningAvatar = static_cast(_owningHead->_owningAvatar); @@ -41,7 +41,7 @@ void FaceModel::simulate(float deltaTime, bool delayLoad) { setPupilDilation(_owningHead->getPupilDilation()); setBlendshapeCoefficients(_owningHead->getBlendshapeCoefficients()); - Model::simulate(deltaTime, delayLoad); + Model::simulate(deltaTime); } bool FaceModel::render(float alpha) { diff --git a/interface/src/avatar/FaceModel.h b/interface/src/avatar/FaceModel.h index 597075dc42..d0f0f6baef 100644 --- a/interface/src/avatar/FaceModel.h +++ b/interface/src/avatar/FaceModel.h @@ -21,7 +21,7 @@ public: FaceModel(Head* owningHead); - void simulate(float deltaTime, bool delayLoad = false); + void simulate(float deltaTime); bool render(float alpha); protected: diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index f405358710..44d1dd6d07 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -18,13 +18,13 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar) : _owningAvatar(owningAvatar) { } -void SkeletonModel::simulate(float deltaTime, bool delayLoad) { +void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { setTranslation(_owningAvatar->getPosition()); setRotation(_owningAvatar->getOrientation() * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f))); const float MODEL_SCALE = 0.0006f; setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getScale() * MODEL_SCALE); - Model::simulate(deltaTime, delayLoad); + Model::simulate(deltaTime, fullUpdate); if (!(isActive() && _owningAvatar->isMyAvatar())) { return; // only simulate for own avatar diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 3d95d805ea..7018e331f0 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -22,7 +22,7 @@ public: SkeletonModel(Avatar* owningAvatar); - void simulate(float deltaTime, bool delayLoad = false); + void simulate(float deltaTime, bool fullUpdate = true); bool render(float alpha); /// \param jointIndex index of hand joint diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 21fdc80858..9951a94dd5 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -156,9 +156,9 @@ void Model::updateShapePositions() { } } -void Model::simulate(float deltaTime, bool delayLoad) { +void Model::simulate(float deltaTime, bool fullUpdate) { // update our LOD - QVector newJointStates = updateGeometry(delayLoad); + QVector newJointStates = updateGeometry(); if (!isActive()) { return; } @@ -183,10 +183,15 @@ void Model::simulate(float deltaTime, bool delayLoad) { model->setURL(attachment.url); _attachments.append(model); } - _resetStates = true; + _resetStates = fullUpdate = true; createCollisionShapes(); } + // exit early if we don't have to perform a full update + if (!(fullUpdate || _resetStates)) { + return; + } + // update the world space transforms for all joints for (int i = 0; i < _jointStates.size(); i++) { updateJointState(i); @@ -868,14 +873,12 @@ void Model::applyCollision(CollisionInfo& collision) { } } -QVector Model::updateGeometry(bool delayLoad) { +QVector Model::updateGeometry() { QVector newJointStates; if (_nextGeometry) { - _nextGeometry = _nextGeometry->getLODOrFallback(_lodDistance, _nextLODHysteresis, delayLoad); - if (!delayLoad) { - _nextGeometry->setLoadPriority(this, -_lodDistance); - _nextGeometry->ensureLoading(); - } + _nextGeometry = _nextGeometry->getLODOrFallback(_lodDistance, _nextLODHysteresis); + _nextGeometry->setLoadPriority(this, -_lodDistance); + _nextGeometry->ensureLoading(); if (_nextGeometry->isLoaded()) { applyNextGeometry(); return newJointStates; @@ -884,7 +887,7 @@ QVector Model::updateGeometry(bool delayLoad) { if (!_geometry) { return newJointStates; } - QSharedPointer geometry = _geometry->getLODOrFallback(_lodDistance, _lodHysteresis, delayLoad); + QSharedPointer geometry = _geometry->getLODOrFallback(_lodDistance, _lodHysteresis); if (_geometry != geometry) { if (!_jointStates.isEmpty()) { // copy the existing joint states @@ -904,10 +907,8 @@ QVector Model::updateGeometry(bool delayLoad) { _dilatedTextures.clear(); _geometry = geometry; } - if (!delayLoad) { - _geometry->setLoadPriority(this, -_lodDistance); - _geometry->ensureLoading(); - } + _geometry->setLoadPriority(this, -_lodDistance); + _geometry->ensureLoading(); return newJointStates; } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index c7aadee8dc..ae38423242 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -57,7 +57,7 @@ public: void clearShapes(); void createCollisionShapes(); void updateShapePositions(); - void simulate(float deltaTime, bool delayLoad = false); + void simulate(float deltaTime, bool fullUpdate = true); bool render(float alpha); /// Sets the URL of the model to render. @@ -256,7 +256,7 @@ protected: private: - QVector updateGeometry(bool delayLoad); + QVector updateGeometry(); void applyNextGeometry(); void deleteGeometry(); void renderMeshes(float alpha, bool translucent); From b4cb1457a27ac51bd64411ad7fcbce93de346c34 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 13:29:18 -0700 Subject: [PATCH 25/44] Do a simple frustum check for rendering the avatar or doing a full joint update. Closes #2071. --- interface/src/avatar/Avatar.cpp | 19 +++++++++++++++++-- interface/src/avatar/Avatar.h | 2 ++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 8333b51aaf..bcf24a7bfb 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -110,6 +110,11 @@ void Avatar::simulate(float deltaTime) { _shouldRenderBillboard = true; } + // simple frustum check + float boundingRadius = getBillboardSize(); + bool inViewFrustum = Application::getInstance()->getViewFrustum()->sphereInFrustum(_position, boundingRadius) != + ViewFrustum::OUTSIDE; + getHand()->simulate(deltaTime, false); _skeletonModel.setLODDistance(getLODDistance()); @@ -119,7 +124,7 @@ void Avatar::simulate(float deltaTime) { _skeletonModel.setJointState(i, data.valid, data.rotation); } glm::vec3 headPosition = _position; - if (!_shouldRenderBillboard) { + if (!_shouldRenderBillboard && inViewFrustum) { _skeletonModel.simulate(deltaTime, _modelsDirty); _modelsDirty = false; _skeletonModel.getHeadPosition(headPosition); @@ -185,6 +190,12 @@ static TextRenderer* textRenderer(TextRendererType type) { } void Avatar::render(bool forShadowMap) { + // simple frustum check + float boundingRadius = getBillboardSize(); + if (Application::getInstance()->getViewFrustum()->sphereInFrustum(_position, boundingRadius) == ViewFrustum::OUTSIDE) { + return; + } + glm::vec3 toTarget = _position - Application::getInstance()->getAvatar()->getPosition(); float lengthToTarget = glm::length(toTarget); @@ -338,7 +349,7 @@ void Avatar::renderBillboard() { glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); // compute the size from the billboard camera parameters and scale - float size = _scale * BILLBOARD_DISTANCE * tanf(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f)); + float size = getBillboardSize(); glScalef(size, size, size); glColor3f(1.0f, 1.0f, 1.0f); @@ -363,6 +374,10 @@ void Avatar::renderBillboard() { glBindTexture(GL_TEXTURE_2D, 0); } +float Avatar::getBillboardSize() const { + return _scale * BILLBOARD_DISTANCE * tanf(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f)); +} + void Avatar::renderDisplayName() { if (_displayName.isEmpty() || _displayNameAlpha == 0.0f) { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index b1812a12a9..2bd7fc89e8 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -191,6 +191,8 @@ private: void renderBody(); void renderBillboard(); + + float getBillboardSize() const; }; #endif From 5b30f932c1e88d1ff6ccdc262477bac0456be384 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 14:09:12 -0700 Subject: [PATCH 26/44] Fix for slight graphical glitches on loading avatars. --- interface/src/avatar/FaceModel.cpp | 5 +- interface/src/renderer/Model.cpp | 361 +++++++++++++++-------------- interface/src/renderer/Model.h | 4 +- 3 files changed, 188 insertions(+), 182 deletions(-) diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index f4ee6859ed..db6c3fe98d 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -19,8 +19,8 @@ FaceModel::FaceModel(Head* owningHead) : } void FaceModel::simulate(float deltaTime) { + QVector newJointStates = updateGeometry(); if (!isActive()) { - Model::simulate(deltaTime); return; } Avatar* owningAvatar = static_cast(_owningHead->_owningAvatar); @@ -36,12 +36,13 @@ void FaceModel::simulate(float deltaTime) { setRotation(neckRotation); const float MODEL_SCALE = 0.0006f; setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningHead->getScale() * MODEL_SCALE); + setOffset(-_geometry->getFBXGeometry().neckPivot); setPupilDilation(_owningHead->getPupilDilation()); setBlendshapeCoefficients(_owningHead->getBlendshapeCoefficients()); - Model::simulate(deltaTime); + Model::simulate(deltaTime, true, newJointStates); } bool FaceModel::render(float alpha) { diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 9951a94dd5..60fae5e596 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -157,146 +157,8 @@ void Model::updateShapePositions() { } void Model::simulate(float deltaTime, bool fullUpdate) { - // update our LOD - QVector newJointStates = updateGeometry(); - if (!isActive()) { - return; - } - - // set up world vertices on first simulate after load - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - if (_jointStates.isEmpty()) { - _jointStates = newJointStates.isEmpty() ? createJointStates(geometry) : newJointStates; - foreach (const FBXMesh& mesh, geometry.meshes) { - MeshState state; - state.clusterMatrices.resize(mesh.clusters.size()); - if (mesh.springiness > 0.0f) { - state.worldSpaceVertices.resize(mesh.vertices.size()); - state.vertexVelocities.resize(mesh.vertices.size()); - state.worldSpaceNormals.resize(mesh.vertices.size()); - } - _meshStates.append(state); - } - foreach (const FBXAttachment& attachment, geometry.attachments) { - Model* model = new Model(this); - model->init(); - model->setURL(attachment.url); - _attachments.append(model); - } - _resetStates = fullUpdate = true; - createCollisionShapes(); - } - - // exit early if we don't have to perform a full update - if (!(fullUpdate || _resetStates)) { - return; - } - - // update the world space transforms for all joints - for (int i = 0; i < _jointStates.size(); i++) { - updateJointState(i); - } - - // update the attachment transforms and simulate them - for (int i = 0; i < _attachments.size(); i++) { - const FBXAttachment& attachment = geometry.attachments.at(i); - Model* model = _attachments.at(i); - - glm::vec3 jointTranslation = _translation; - glm::quat jointRotation = _rotation; - getJointPosition(attachment.jointIndex, jointTranslation); - getJointRotation(attachment.jointIndex, jointRotation); - - model->setTranslation(jointTranslation + jointRotation * attachment.translation * _scale); - model->setRotation(jointRotation * attachment.rotation); - model->setScale(_scale * attachment.scale); - - model->simulate(deltaTime); - } - - for (int i = 0; i < _meshStates.size(); i++) { - MeshState& state = _meshStates[i]; - const FBXMesh& mesh = geometry.meshes.at(i); - for (int j = 0; j < mesh.clusters.size(); j++) { - const FBXCluster& cluster = mesh.clusters.at(j); - state.clusterMatrices[j] = _jointStates[cluster.jointIndex].transform * cluster.inverseBindMatrix; - } - int vertexCount = state.worldSpaceVertices.size(); - if (vertexCount == 0) { - continue; - } - glm::vec3* destVertices = state.worldSpaceVertices.data(); - glm::vec3* destVelocities = state.vertexVelocities.data(); - glm::vec3* destNormals = state.worldSpaceNormals.data(); - - const glm::vec3* sourceVertices = mesh.vertices.constData(); - if (!mesh.blendshapes.isEmpty()) { - _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); - memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3)); - - // blend in each coefficient - for (unsigned int j = 0; j < _blendshapeCoefficients.size(); j++) { - float coefficient = _blendshapeCoefficients[j]; - if (coefficient == 0.0f || j >= (unsigned int)mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) { - continue; - } - const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData(); - for (const int* index = mesh.blendshapes[j].indices.constData(), - *end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++) { - _blendedVertices[*index] += *vertex * coefficient; - } - } - sourceVertices = _blendedVertices.constData(); - } - glm::mat4 transform = glm::translate(_translation); - if (mesh.clusters.size() > 1) { - _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); - - // skin each vertex - const glm::vec4* clusterIndices = mesh.clusterIndices.constData(); - const glm::vec4* clusterWeights = mesh.clusterWeights.constData(); - for (int j = 0; j < vertexCount; j++) { - _blendedVertices[j] = - glm::vec3(state.clusterMatrices[clusterIndices[j][0]] * - glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][0] + - glm::vec3(state.clusterMatrices[clusterIndices[j][1]] * - glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][1] + - glm::vec3(state.clusterMatrices[clusterIndices[j][2]] * - glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][2] + - glm::vec3(state.clusterMatrices[clusterIndices[j][3]] * - glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][3]; - } - sourceVertices = _blendedVertices.constData(); - - } else { - transform = state.clusterMatrices[0]; - } - if (_resetStates) { - for (int j = 0; j < vertexCount; j++) { - destVertices[j] = glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f)); - destVelocities[j] = glm::vec3(); - } - } else { - const float SPRINGINESS_MULTIPLIER = 200.0f; - const float DAMPING = 5.0f; - for (int j = 0; j < vertexCount; j++) { - destVelocities[j] += ((glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f)) - destVertices[j]) * - mesh.springiness * SPRINGINESS_MULTIPLIER - destVelocities[j] * DAMPING) * deltaTime; - destVertices[j] += destVelocities[j] * deltaTime; - } - } - for (int j = 0; j < vertexCount; j++) { - destNormals[j] = glm::vec3(); - - const glm::vec3& middle = destVertices[j]; - for (QVarLengthArray, 4>::const_iterator connection = mesh.vertexConnections.at(j).constBegin(); - connection != mesh.vertexConnections.at(j).constEnd(); connection++) { - destNormals[j] += glm::normalize(glm::cross(destVertices[connection->second] - middle, - destVertices[connection->first] - middle)); - } - } - } - _resetStates = false; + // update our LOD, then simulate + simulate(deltaTime, fullUpdate, updateGeometry()); } bool Model::render(float alpha) { @@ -577,6 +439,186 @@ bool Model::findSphereCollisions(const glm::vec3& sphereCenter, float sphereRadi return collided; } +QVector Model::updateGeometry() { + QVector newJointStates; + if (_nextGeometry) { + _nextGeometry = _nextGeometry->getLODOrFallback(_lodDistance, _nextLODHysteresis); + _nextGeometry->setLoadPriority(this, -_lodDistance); + _nextGeometry->ensureLoading(); + if (_nextGeometry->isLoaded()) { + applyNextGeometry(); + return newJointStates; + } + } + if (!_geometry) { + return newJointStates; + } + QSharedPointer geometry = _geometry->getLODOrFallback(_lodDistance, _lodHysteresis); + if (_geometry != geometry) { + if (!_jointStates.isEmpty()) { + // copy the existing joint states + const FBXGeometry& oldGeometry = _geometry->getFBXGeometry(); + const FBXGeometry& newGeometry = geometry->getFBXGeometry(); + newJointStates = createJointStates(newGeometry); + 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] = _jointStates.at(oldIndex); + } + } + } + deleteGeometry(); + _dilatedTextures.clear(); + _geometry = geometry; + } + _geometry->setLoadPriority(this, -_lodDistance); + _geometry->ensureLoading(); + return newJointStates; +} + +void Model::simulate(float deltaTime, bool fullUpdate, const QVector& newJointStates) { + if (!isActive()) { + return; + } + + // set up world vertices on first simulate after load + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + if (_jointStates.isEmpty()) { + _jointStates = newJointStates.isEmpty() ? createJointStates(geometry) : newJointStates; + foreach (const FBXMesh& mesh, geometry.meshes) { + MeshState state; + state.clusterMatrices.resize(mesh.clusters.size()); + if (mesh.springiness > 0.0f) { + state.worldSpaceVertices.resize(mesh.vertices.size()); + state.vertexVelocities.resize(mesh.vertices.size()); + state.worldSpaceNormals.resize(mesh.vertices.size()); + } + _meshStates.append(state); + } + foreach (const FBXAttachment& attachment, geometry.attachments) { + Model* model = new Model(this); + model->init(); + model->setURL(attachment.url); + _attachments.append(model); + } + _resetStates = fullUpdate = true; + createCollisionShapes(); + } + + // exit early if we don't have to perform a full update + if (!(fullUpdate || _resetStates)) { + return; + } + + // update the world space transforms for all joints + for (int i = 0; i < _jointStates.size(); i++) { + updateJointState(i); + } + + // update the attachment transforms and simulate them + for (int i = 0; i < _attachments.size(); i++) { + const FBXAttachment& attachment = geometry.attachments.at(i); + Model* model = _attachments.at(i); + + glm::vec3 jointTranslation = _translation; + glm::quat jointRotation = _rotation; + getJointPosition(attachment.jointIndex, jointTranslation); + getJointRotation(attachment.jointIndex, jointRotation); + + model->setTranslation(jointTranslation + jointRotation * attachment.translation * _scale); + model->setRotation(jointRotation * attachment.rotation); + model->setScale(_scale * attachment.scale); + + model->simulate(deltaTime); + } + + for (int i = 0; i < _meshStates.size(); i++) { + MeshState& state = _meshStates[i]; + const FBXMesh& mesh = geometry.meshes.at(i); + for (int j = 0; j < mesh.clusters.size(); j++) { + const FBXCluster& cluster = mesh.clusters.at(j); + state.clusterMatrices[j] = _jointStates[cluster.jointIndex].transform * cluster.inverseBindMatrix; + } + int vertexCount = state.worldSpaceVertices.size(); + if (vertexCount == 0) { + continue; + } + glm::vec3* destVertices = state.worldSpaceVertices.data(); + glm::vec3* destVelocities = state.vertexVelocities.data(); + glm::vec3* destNormals = state.worldSpaceNormals.data(); + + const glm::vec3* sourceVertices = mesh.vertices.constData(); + if (!mesh.blendshapes.isEmpty()) { + _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); + memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3)); + + // blend in each coefficient + for (unsigned int j = 0; j < _blendshapeCoefficients.size(); j++) { + float coefficient = _blendshapeCoefficients[j]; + if (coefficient == 0.0f || j >= (unsigned int)mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) { + continue; + } + const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData(); + for (const int* index = mesh.blendshapes[j].indices.constData(), + *end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++) { + _blendedVertices[*index] += *vertex * coefficient; + } + } + sourceVertices = _blendedVertices.constData(); + } + glm::mat4 transform = glm::translate(_translation); + if (mesh.clusters.size() > 1) { + _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); + + // skin each vertex + const glm::vec4* clusterIndices = mesh.clusterIndices.constData(); + const glm::vec4* clusterWeights = mesh.clusterWeights.constData(); + for (int j = 0; j < vertexCount; j++) { + _blendedVertices[j] = + glm::vec3(state.clusterMatrices[clusterIndices[j][0]] * + glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][0] + + glm::vec3(state.clusterMatrices[clusterIndices[j][1]] * + glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][1] + + glm::vec3(state.clusterMatrices[clusterIndices[j][2]] * + glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][2] + + glm::vec3(state.clusterMatrices[clusterIndices[j][3]] * + glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][3]; + } + sourceVertices = _blendedVertices.constData(); + + } else { + transform = state.clusterMatrices[0]; + } + if (_resetStates) { + for (int j = 0; j < vertexCount; j++) { + destVertices[j] = glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f)); + destVelocities[j] = glm::vec3(); + } + } else { + const float SPRINGINESS_MULTIPLIER = 200.0f; + const float DAMPING = 5.0f; + for (int j = 0; j < vertexCount; j++) { + destVelocities[j] += ((glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f)) - destVertices[j]) * + mesh.springiness * SPRINGINESS_MULTIPLIER - destVelocities[j] * DAMPING) * deltaTime; + destVertices[j] += destVelocities[j] * deltaTime; + } + } + for (int j = 0; j < vertexCount; j++) { + destNormals[j] = glm::vec3(); + + const glm::vec3& middle = destVertices[j]; + for (QVarLengthArray, 4>::const_iterator connection = mesh.vertexConnections.at(j).constBegin(); + connection != mesh.vertexConnections.at(j).constEnd(); connection++) { + destNormals[j] += glm::normalize(glm::cross(destVertices[connection->second] - middle, + destVertices[connection->first] - middle)); + } + } + } + _resetStates = false; +} + void Model::updateJointState(int index) { _shapesAreDirty = true; JointState& state = _jointStates[index]; @@ -873,45 +915,6 @@ void Model::applyCollision(CollisionInfo& collision) { } } -QVector Model::updateGeometry() { - QVector newJointStates; - if (_nextGeometry) { - _nextGeometry = _nextGeometry->getLODOrFallback(_lodDistance, _nextLODHysteresis); - _nextGeometry->setLoadPriority(this, -_lodDistance); - _nextGeometry->ensureLoading(); - if (_nextGeometry->isLoaded()) { - applyNextGeometry(); - return newJointStates; - } - } - if (!_geometry) { - return newJointStates; - } - QSharedPointer geometry = _geometry->getLODOrFallback(_lodDistance, _lodHysteresis); - if (_geometry != geometry) { - if (!_jointStates.isEmpty()) { - // copy the existing joint states - const FBXGeometry& oldGeometry = _geometry->getFBXGeometry(); - const FBXGeometry& newGeometry = geometry->getFBXGeometry(); - newJointStates = createJointStates(newGeometry); - 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] = _jointStates.at(oldIndex); - } - } - } - deleteGeometry(); - _dilatedTextures.clear(); - _geometry = geometry; - } - _geometry->setLoadPriority(this, -_lodDistance); - _geometry->ensureLoading(); - return newJointStates; -} - void Model::applyNextGeometry() { // delete our local geometry and custom textures deleteGeometry(); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index ae38423242..165465d2cc 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -226,6 +226,9 @@ protected: QVector _meshStates; + QVector updateGeometry(); + void simulate(float deltaTime, bool fullUpdate, const QVector& newJointStates); + /// Updates the state of the joint at the specified index. virtual void updateJointState(int index); @@ -256,7 +259,6 @@ protected: private: - QVector updateGeometry(); void applyNextGeometry(); void deleteGeometry(); void renderMeshes(float alpha, bool translucent); From e5b5778caf2ba2e9b80edd17e25ed4a414211359 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 13 Mar 2014 15:04:22 -0700 Subject: [PATCH 27/44] Upload FST --- libraries/shared/src/AccountManager.cpp | 31 ++++-- libraries/shared/src/AccountManager.h | 7 +- libraries/shared/src/FstReader.cpp | 141 +++++++++++++++++------- libraries/shared/src/FstReader.h | 26 ++--- 4 files changed, 138 insertions(+), 67 deletions(-) diff --git a/libraries/shared/src/AccountManager.cpp b/libraries/shared/src/AccountManager.cpp index 7915a60690..6517d080ed 100644 --- a/libraries/shared/src/AccountManager.cpp +++ b/libraries/shared/src/AccountManager.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "NodeList.h" #include "PacketHeaders.h" @@ -30,6 +31,7 @@ Q_DECLARE_METATYPE(OAuthAccessToken) Q_DECLARE_METATYPE(DataServerAccountInfo) Q_DECLARE_METATYPE(QNetworkAccessManager::Operation) Q_DECLARE_METATYPE(JSONCallbackParameters) +Q_DECLARE_METATYPE(QHttpMultiPart) const QString ACCOUNTS_GROUP = "accounts"; @@ -99,21 +101,25 @@ void AccountManager::setAuthURL(const QUrl& authURL) { } void AccountManager::authenticatedRequest(const QString& path, QNetworkAccessManager::Operation operation, - const JSONCallbackParameters& callbackParams, const QByteArray& dataByteArray) { + const JSONCallbackParameters& callbackParams, + const QByteArray& dataByteArray, + QHttpMultiPart* dataMultiPart) { QMetaObject::invokeMethod(this, "invokedRequest", Q_ARG(const QString&, path), Q_ARG(QNetworkAccessManager::Operation, operation), Q_ARG(const JSONCallbackParameters&, callbackParams), - Q_ARG(const QByteArray&, dataByteArray)); + Q_ARG(const QByteArray&, dataByteArray), + Q_ARG(QHttpMultiPart*, dataMultiPart)); } void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager::Operation operation, - const JSONCallbackParameters& callbackParams, const QByteArray& dataByteArray) { - + const JSONCallbackParameters& callbackParams, + const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart) { + if (!_networkAccessManager) { _networkAccessManager = new QNetworkAccessManager(this); } - + if (hasValidAccessToken()) { QNetworkRequest authenticatedRequest; @@ -140,11 +146,18 @@ void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager:: case QNetworkAccessManager::PostOperation: case QNetworkAccessManager::PutOperation: authenticatedRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - - if (operation == QNetworkAccessManager::PostOperation) { - networkReply = _networkAccessManager->post(authenticatedRequest, dataByteArray); + if (dataMultiPart) { + if (operation == QNetworkAccessManager::PostOperation) { + networkReply = _networkAccessManager->post(authenticatedRequest, dataMultiPart); + } else { + networkReply = _networkAccessManager->put(authenticatedRequest, dataMultiPart); + } } else { - networkReply = _networkAccessManager->put(authenticatedRequest, dataByteArray); + if (operation == QNetworkAccessManager::PostOperation) { + networkReply = _networkAccessManager->post(authenticatedRequest, dataByteArray); + } else { + networkReply = _networkAccessManager->put(authenticatedRequest, dataByteArray); + } } break; diff --git a/libraries/shared/src/AccountManager.h b/libraries/shared/src/AccountManager.h index ee821fa43c..bfe84f392e 100644 --- a/libraries/shared/src/AccountManager.h +++ b/libraries/shared/src/AccountManager.h @@ -39,7 +39,8 @@ public: void authenticatedRequest(const QString& path, QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation, const JSONCallbackParameters& callbackParams = JSONCallbackParameters(), - const QByteArray& dataByteArray = QByteArray()); + const QByteArray& dataByteArray = QByteArray(), + QHttpMultiPart* dataMultiPart = NULL); const QUrl& getAuthURL() const { return _authURL; } void setAuthURL(const QUrl& authURL); @@ -77,7 +78,9 @@ private: void operator=(AccountManager const& other); // not implemented Q_INVOKABLE void invokedRequest(const QString& path, QNetworkAccessManager::Operation operation, - const JSONCallbackParameters& callbackParams, const QByteArray& dataByteArray); + const JSONCallbackParameters& callbackParams, + const QByteArray& dataByteArray, + QHttpMultiPart* dataMultiPart); QUrl _authURL; QNetworkAccessManager* _networkAccessManager; diff --git a/libraries/shared/src/FstReader.cpp b/libraries/shared/src/FstReader.cpp index d94f036af0..0e99a7b2f4 100644 --- a/libraries/shared/src/FstReader.cpp +++ b/libraries/shared/src/FstReader.cpp @@ -10,15 +10,38 @@ #include #include #include -#include #include #include +#include +#include + +#include "AccountManager.h" #include "FstReader.h" -FstReader::FstReader() { + +static const QString NAME_FIELD = "name"; +static const QString FILENAME_FIELD = "filename"; +static const QString TEXDIR_FIELD = "texdir"; +static const QString LOD_FIELD = "lod"; + +static const QString MODEL_URL = "/api/v1/models"; + +static const int MAX_SIZE = 10 * 1024 * 1024; // 10 MB + +FstReader::FstReader() : + _lodCount(-1), + _texturesCount(-1), + _readyToSend(false), + _dataMultiPart(new QHttpMultiPart(QHttpMultiPart::FormDataType)) +{ } +FstReader::~FstReader() { + if (_dataMultiPart) { + delete _dataMultiPart; + } +} bool FstReader::zip() { // File Dialog @@ -33,11 +56,18 @@ bool FstReader::zip() { qDebug() << "[ERROR] Could not open FST file : " << fst.fileName(); return false; } + + // Compress and copy the fst + if (!compressFile(QFileInfo(fst).filePath(), _zipDir.path() + "/" + QFileInfo(fst).fileName())) { + return false; + } + _totalSize += QFileInfo(fst).size(); + if (!addPart(_zipDir.path() + "/" + QFileInfo(fst).fileName(), + QString("fst"))) { + return false; + } qDebug() << "Reading FST file : " << QFileInfo(fst).filePath(); - - QDir rootDir(_zipDir.path()); - // Let's read through the FST file QTextStream stream(&fst); QList line; @@ -47,20 +77,34 @@ bool FstReader::zip() { continue; } + if (_totalSize > MAX_SIZE) { + qDebug() << "[ERROR] Model too big, over " << MAX_SIZE << " Bytes."; + return false; + } + // according to what is read, we modify the command - if (line.first() == nameField) { - _modelName = line[1]; - } else if (line.first() == filenameField) { + if (line.first() == NAME_FIELD) { + QHttpPart textPart; + textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;" + " name=\"model_name\""); + //textPart.setRawHeader("name", "\"model_name\""); + textPart.setBody(line[1].toUtf8()); + _dataMultiPart->append(textPart); + } else if (line.first() == FILENAME_FIELD) { QFileInfo fbx(QFileInfo(fst).path() + "/" + line[1]); if (!fbx.exists() || !fbx.isFile()) { // Check existence qDebug() << "[ERROR] FBX file " << fbx.absoluteFilePath() << " doesn't exist."; return false; - } else { // Compress and copy - _fbxFile = rootDir.path() + "/" + line[1]; - _totalSize += fbx.size(); - compressFile(fbx.filePath(), _fbxFile); } - } else if (line.first() == texdirField) { // Check existence + // Compress and copy + if (!compressFile(fbx.filePath(), _zipDir.path() + "/" + line[1])) { + return false; + } + _totalSize += fbx.size(); + if (!addPart(_zipDir.path() + "/" + line[1], "fbx")) { + return false; + } + } else if (line.first() == TEXDIR_FIELD) { // Check existence QFileInfo texdir(QFileInfo(fst).path() + "/" + line[1]); if (!texdir.exists() || !texdir.isDir()) { qDebug() << "[ERROR] Texture directory " << texdir.absolutePath() << " doesn't exist."; @@ -69,47 +113,41 @@ bool FstReader::zip() { if (!addTextures(texdir)) { // Recursive compress and copy return false; } - } else if (line.first() == lodField) { + } else if (line.first() == LOD_FIELD) { QFileInfo lod(QFileInfo(fst).path() + "/" + line[1]); if (!lod.exists() || !lod.isFile()) { // Check existence qDebug() << "[ERROR] FBX file " << lod.absoluteFilePath() << " doesn't exist."; - //return false; - } else { // Compress and copy - _lodFiles.push_back(rootDir.path() + "/" + line[1]); - _totalSize += lod.size(); - compressFile(lod.filePath(), _lodFiles.back()); + return false; + } + // Compress and copy + if (!compressFile(lod.filePath(), _zipDir.path() + "/" + line[1])) { + return false; + } + _totalSize += lod.size(); + if (!addPart(_zipDir.path() + "/" + line[1], QString("lod%1").arg(++_lodCount))) { + return false; } } } - // Compress and copy the fst - _fstFile = rootDir.path() + "/" + QFileInfo(fst).fileName(); - _totalSize += QFileInfo(fst).size(); - compressFile(fst.fileName(), _fstFile); - + _readyToSend = true; return true; } bool FstReader::send() { - QString command = QString("curl -F \"model_name=%1\"").arg(_modelName); - - command += QString(" -F \"fst=@%1\" -F \"fbx=@%2\"").arg(_fstFile, _fbxFile); - for (int i = 0; i < _lodFiles.size(); ++i) { - command += QString(" -F \"lod%1=@%2\"").arg(i).arg(_lodFiles[i]); + if (!_readyToSend) { + return false; } - for (int i = 0; i < _textureFiles.size(); ++i) { - command += QString(" -F \"lod%1=@%2\"").arg(i).arg(_textureFiles[i]); - } - command += " http://localhost:3000/api/v1/models/?access_token\\=017894b7312316a2b5025613fcc58c13bc701da9b797cca34b60aae9d1c53acb --trace-ascii /dev/stdout"; - qDebug() << "[DEBUG] " << command; + AccountManager::getInstance().authenticatedRequest(MODEL_URL, QNetworkAccessManager::PostOperation, JSONCallbackParameters(), QByteArray(), _dataMultiPart); + _dataMultiPart = NULL; return true; } -bool FstReader::addTextures(QFileInfo& texdir) { +bool FstReader::addTextures(const QFileInfo& texdir) { QStringList filter; - filter << "*.png" << "*.tiff" << "*.jpg" << "*.jpeg"; + filter << "*.png" << "*.tif" << "*.jpg" << "*.jpeg"; QFileInfoList list = QDir(texdir.filePath()).entryInfoList(filter, QDir::Files | @@ -118,9 +156,15 @@ bool FstReader::addTextures(QFileInfo& texdir) { QDir::NoSymLinks); foreach (QFileInfo info, list) { if (info.isFile()) { - _textureFiles.push_back(_zipDir.path() + "/" + info.fileName()); + // Compress and copy + if (!compressFile(info.filePath(), _zipDir.path() + "/" + info.fileName())) { + return false; + } _totalSize += info.size(); - compressFile(info.canonicalFilePath(), _textureFiles.back()); + if (!addPart(_zipDir.path() + "/" + info.fileName(), + QString("texture%1").arg(++_texturesCount))) { + return false; + } } else if (info.isDir()) { if (!addTextures(info)) { return false; @@ -153,7 +197,26 @@ bool FstReader::compressFile(const QString &inFileName, const QString &outFileNa } - +bool FstReader::addPart(const QString &path, const QString& name) { + QFile* file = new QFile(path); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << "[ERROR] Couldn't open " << file->fileName(); + return false; + } + + QHttpPart part; + part.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;" + " name=\"" + name.toUtf8() + "\";" + " filename=\"" + QFileInfo(*file).fileName().toUtf8() + "\""); + part.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream"); + part.setBodyDevice(file); + _dataMultiPart->append(part); + file->setParent(_dataMultiPart); + + qDebug() << QFileInfo(*file).fileName().toUtf8(); + + return true; +} diff --git a/libraries/shared/src/FstReader.h b/libraries/shared/src/FstReader.h index c5816ea415..aab42bd967 100644 --- a/libraries/shared/src/FstReader.h +++ b/libraries/shared/src/FstReader.h @@ -10,39 +10,31 @@ #ifndef __hifi__FstReader__ #define __hifi__FstReader__ -#include -#include #include - -static const QString nameField = "name"; -static const QString filenameField = "filename"; -static const QString texdirField = "texdir"; -static const QString lodField = "lod"; - -static const int MAX_SIZE = 1024 * 1024; // 1 MB +class QHttpMultiPart; class FstReader { public: FstReader(); + ~FstReader(); bool zip(); bool send(); private: QTemporaryDir _zipDir; - - QString _modelName; - QString _fstFile; - QString _fbxFile; - QStringList _lodFiles; - QStringList _textureFiles; - + int _lodCount; + int _texturesCount; int _totalSize; + bool _readyToSend; + + QHttpMultiPart* _dataMultiPart; - bool addTextures(QFileInfo& texdir); + bool addTextures(const QFileInfo& texdir); bool compressFile(const QString& inFileName, const QString& outFileName); + bool addPart(const QString& path, const QString& name); }; #endif /* defined(__hifi__FstReader__) */ From fc32d9581dda05e5586eb8bd3ec35ca989113137 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 15:17:16 -0700 Subject: [PATCH 28/44] Visage toggle bits. --- interface/interface_en.ts | 8 +++---- interface/src/Menu.cpp | 9 ++++++-- interface/src/Menu.h | 3 ++- interface/src/devices/Visage.cpp | 36 +++++++++++++++++++------------- interface/src/devices/Visage.h | 10 +++++++-- 5 files changed, 42 insertions(+), 24 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 80433032dc..496e3a66e5 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -113,18 +113,18 @@ Menu - + Open .ini config file - - + + Text files (*.ini) - + Save .ini config file diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 00ae0a3772..4e880f2512 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -270,11 +270,16 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::LookAtVectors, 0, false); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, - MenuOption::FaceshiftTCP, + MenuOption::Faceshift, 0, - false, + true, appInstance->getFaceshift(), SLOT(setTCPEnabled(bool))); +#ifdef HAVE_VISAGE + addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Visage, 0, true, + appInstance->getVisage(), SLOT(setEnabled(bool))); +#endif + addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, false); QMenu* handOptionsMenu = developerMenu->addMenu("Hand Options"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 00ef51178a..f02db150ba 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -239,7 +239,7 @@ namespace MenuOption { const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes"; const QString HeadMouse = "Head Mouse"; const QString HandsCollideWithSelf = "Collide With Self"; - const QString FaceshiftTCP = "Faceshift (TCP)"; + const QString Faceshift = "Faceshift"; const QString FirstPerson = "First Person"; const QString FrameTimer = "Show Timer"; const QString FrustumRenderMode = "Render Mode"; @@ -292,6 +292,7 @@ namespace MenuOption { const QString StopAllScripts = "Stop All Scripts"; const QString TestPing = "Test Ping"; const QString TransmitterDrive = "Transmitter Drive"; + const QString Visage = "Visage"; const QString Quit = "Quit"; const QString Voxels = "Voxels"; const QString VoxelMode = "Cycle Voxel Mode"; diff --git a/interface/src/devices/Visage.cpp b/interface/src/devices/Visage.cpp index 727c083265..745b543d87 100644 --- a/interface/src/devices/Visage.cpp +++ b/interface/src/devices/Visage.cpp @@ -40,25 +40,11 @@ Visage::Visage() : #ifdef HAVE_VISAGE QByteArray licensePath = Application::resourcesPath().toLatin1() + "visage/license.vlc"; initializeLicenseManager(licensePath.data()); - _tracker = new VisageTracker2(Application::resourcesPath().toLatin1() + "visage/tracker.cfg"); - if (_tracker->trackFromCam()) { - _data = new FaceData(); - - } else { - delete _tracker; - _tracker = NULL; - } #endif } Visage::~Visage() { -#ifdef HAVE_VISAGE - if (_tracker) { - _tracker->stop(); - delete _tracker; - delete _data; - } -#endif + setEnabled(false); } #ifdef HAVE_VISAGE @@ -160,3 +146,23 @@ void Visage::update() { void Visage::reset() { _headOrigin += _headTranslation / TRANSLATION_SCALE; } + +void Visage::setEnabled(bool enabled) { +#ifdef HAVE_VISAGE + if (enabled == (_tracker != NULL)) { + return; + } + if (enabled) { + _tracker = new VisageTracker2(Application::resourcesPath().toLatin1() + "visage/tracker.cfg"); + _data = new FaceData(); + if (_tracker->trackFromCam()) { + return; + } + } + _tracker->stop(); + delete _tracker; + delete _data; + _tracker = NULL; + _data = NULL; +#endif +} diff --git a/interface/src/devices/Visage.h b/interface/src/devices/Visage.h index c238b3bb8c..28d990ae7a 100644 --- a/interface/src/devices/Visage.h +++ b/interface/src/devices/Visage.h @@ -24,11 +24,13 @@ namespace VisageSDK { } /// Handles input from the Visage webcam feature tracking software. -class Visage { +class Visage : public QObject { + Q_OBJECT + public: Visage(); - ~Visage(); + virtual ~Visage(); bool isActive() const { return _active; } @@ -42,6 +44,10 @@ public: void update(); void reset(); + +public slots: + + void setEnabled(bool enabled); private: From 423f26f669db865b41de3fdb10da79a639b254fd Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 13 Mar 2014 15:26:02 -0700 Subject: [PATCH 29/44] Review comments --- interface/src/Application.cpp | 2 +- libraries/shared/src/AccountManager.cpp | 1 - libraries/shared/src/FstReader.cpp | 8 +------- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0bc8b0f22d..aed212c692 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3462,7 +3462,7 @@ void Application::reloadAllScripts() { void Application::uploadFST() { FstReader reader; - if(reader.zip()) { + if (reader.zip()) { reader.send(); } } diff --git a/libraries/shared/src/AccountManager.cpp b/libraries/shared/src/AccountManager.cpp index 6517d080ed..bb32896ca0 100644 --- a/libraries/shared/src/AccountManager.cpp +++ b/libraries/shared/src/AccountManager.cpp @@ -31,7 +31,6 @@ Q_DECLARE_METATYPE(OAuthAccessToken) Q_DECLARE_METATYPE(DataServerAccountInfo) Q_DECLARE_METATYPE(QNetworkAccessManager::Operation) Q_DECLARE_METATYPE(JSONCallbackParameters) -Q_DECLARE_METATYPE(QHttpMultiPart) const QString ACCOUNTS_GROUP = "accounts"; diff --git a/libraries/shared/src/FstReader.cpp b/libraries/shared/src/FstReader.cpp index 0e99a7b2f4..d82ddf68a3 100644 --- a/libraries/shared/src/FstReader.cpp +++ b/libraries/shared/src/FstReader.cpp @@ -38,9 +38,7 @@ FstReader::FstReader() : } FstReader::~FstReader() { - if (_dataMultiPart) { - delete _dataMultiPart; - } + delete _dataMultiPart; } bool FstReader::zip() { @@ -87,7 +85,6 @@ bool FstReader::zip() { QHttpPart textPart; textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;" " name=\"model_name\""); - //textPart.setRawHeader("name", "\"model_name\""); textPart.setBody(line[1].toUtf8()); _dataMultiPart->append(textPart); } else if (line.first() == FILENAME_FIELD) { @@ -141,7 +138,6 @@ bool FstReader::send() { AccountManager::getInstance().authenticatedRequest(MODEL_URL, QNetworkAccessManager::PostOperation, JSONCallbackParameters(), QByteArray(), _dataMultiPart); - _dataMultiPart = NULL; return true; } @@ -213,8 +209,6 @@ bool FstReader::addPart(const QString &path, const QString& name) { _dataMultiPart->append(part); file->setParent(_dataMultiPart); - qDebug() << QFileInfo(*file).fileName().toUtf8(); - return true; } From 007bfa8866ce3234f025110b617303610aacf896 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 15:26:07 -0700 Subject: [PATCH 30/44] Tweak to Visage toggle. --- interface/src/devices/Visage.cpp | 27 +++++++++++++-------------- interface/src/devices/Visage.h | 1 + 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/interface/src/devices/Visage.cpp b/interface/src/devices/Visage.cpp index 745b543d87..876a810431 100644 --- a/interface/src/devices/Visage.cpp +++ b/interface/src/devices/Visage.cpp @@ -32,6 +32,7 @@ using namespace VisageSDK; const glm::vec3 DEFAULT_HEAD_ORIGIN(0.0f, 0.0f, 0.7f); Visage::Visage() : + _enabled(false), _active(false), _headOrigin(DEFAULT_HEAD_ORIGIN), _estimatedEyePitch(0.0f), @@ -40,11 +41,16 @@ Visage::Visage() : #ifdef HAVE_VISAGE QByteArray licensePath = Application::resourcesPath().toLatin1() + "visage/license.vlc"; initializeLicenseManager(licensePath.data()); + _tracker = new VisageTracker2(Application::resourcesPath().toLatin1() + "visage/tracker.cfg"); + _data = new FaceData(); #endif } Visage::~Visage() { - setEnabled(false); +#ifdef HAVE_VISAGE + delete _tracker; + delete _data; +#endif } #ifdef HAVE_VISAGE @@ -105,7 +111,7 @@ const float TRANSLATION_SCALE = 20.0f; void Visage::update() { #ifdef HAVE_VISAGE - _active = (_tracker && _tracker->getTrackingData(_data) == TRACK_STAT_OK); + _active = (_tracker->getTrackingData(_data) == TRACK_STAT_OK); if (!_active) { return; } @@ -149,20 +155,13 @@ void Visage::reset() { void Visage::setEnabled(bool enabled) { #ifdef HAVE_VISAGE - if (enabled == (_tracker != NULL)) { + if (_enabled == enabled) { return; } - if (enabled) { - _tracker = new VisageTracker2(Application::resourcesPath().toLatin1() + "visage/tracker.cfg"); - _data = new FaceData(); - if (_tracker->trackFromCam()) { - return; - } + if (_enabled = enabled) { + _tracker->trackFromCam(); + } else { + _tracker->stop(); } - _tracker->stop(); - delete _tracker; - delete _data; - _tracker = NULL; - _data = NULL; #endif } diff --git a/interface/src/devices/Visage.h b/interface/src/devices/Visage.h index 28d990ae7a..e71bdc0fb5 100644 --- a/interface/src/devices/Visage.h +++ b/interface/src/devices/Visage.h @@ -57,6 +57,7 @@ private: QMultiHash > _actionUnitIndexMap; #endif + bool _enabled; bool _active; glm::quat _headRotation; glm::vec3 _headTranslation; From 4523ae742e0b2d018a443a13265106f16b39d0be Mon Sep 17 00:00:00 2001 From: Geenz Date: Thu, 13 Mar 2014 18:51:14 -0400 Subject: [PATCH 31/44] =?UTF-8?q?Tweak=20in=20code=20styling=20per=20Brad?= =?UTF-8?q?=E2=80=99s=20feedback,=20along=20with=20using=20SIGNAL=20and=20?= =?UTF-8?q?SLOT=20instead=20of=20function=20pointers=20directly.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- interface/src/GLCanvas.cpp | 13 ++++++++----- interface/src/GLCanvas.h | 6 ++++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index bf99608c07..249f7a373d 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -13,15 +13,18 @@ #include #include -GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer, QGL::NoStencilBuffer)), _throttleRendering(false), _idleRenderInterval(100) { +GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer, QGL::NoStencilBuffer)), + _throttleRendering(false), + _idleRenderInterval(100) +{ } void GLCanvas::initializeGL() { Application::getInstance()->initializeGL(); setAttribute(Qt::WA_AcceptTouchEvents); setAcceptDrops(true); - connect(Application::getInstance(), &Application::applicationStateChanged, this, &GLCanvas::activeChanged); - connect(&_frameTimer, &QTimer::timeout, this, &GLCanvas::throttleRender); + connect(Application::getInstance(), SIGNAL(applicationStateChanged(Qt::ApplicationState)), this, SLOT(activeChanged(Qt::ApplicationState))); + connect(&_frameTimer, SIGNAL(timeout()), this, SLOT(throttleRender())); } void GLCanvas::paintGL() { @@ -54,8 +57,8 @@ void GLCanvas::mouseReleaseEvent(QMouseEvent* event) { Application::getInstance()->mouseReleaseEvent(event); } -void GLCanvas::activeChanged() { - switch (Application::applicationState()) { +void GLCanvas::activeChanged(Qt::ApplicationState state) { + switch (state) { case Qt::ApplicationActive: // If we're active, stop the frame timer and the throttle. _frameTimer.stop(); diff --git a/interface/src/GLCanvas.h b/interface/src/GLCanvas.h index 7e4a4d0334..e6dcc38977 100644 --- a/interface/src/GLCanvas.h +++ b/interface/src/GLCanvas.h @@ -14,6 +14,7 @@ /// customized canvas that simply forwards requests/events to the singleton application class GLCanvas : public QGLWidget { + Q_OBJECT public: GLCanvas(); protected: @@ -39,8 +40,9 @@ protected: virtual void dragEnterEvent(QDragEnterEvent *event); virtual void dropEvent(QDropEvent* event); - - void activeChanged(); + +private slots: + void activeChanged(Qt::ApplicationState state); void throttleRender(); }; From 881ecb07cd3268d2622d9a8249e09018132e8cdd Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Thu, 13 Mar 2014 23:00:01 +0200 Subject: [PATCH 32/44] Changed the font of the entire chat window to Helvetica/Arial. --- interface/interface_en.ts | 10 +++++----- interface/ui/chatWindow.ui | 13 +++++++++++-- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 80433032dc..b6e35f3f5f 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -28,19 +28,19 @@ ChatWindow - + Chat - - + + Connecting to XMPP... - - + + online now: diff --git a/interface/ui/chatWindow.ui b/interface/ui/chatWindow.ui index ecb4d79c41..22f2dcd5dd 100644 --- a/interface/ui/chatWindow.ui +++ b/interface/ui/chatWindow.ui @@ -13,6 +13,9 @@ Chat + + font-family: Helvetica, Arial, sans-serif; + 0 @@ -100,7 +103,7 @@ - margin-top: 12px; font-family: Helvetica, Arial, sans-serif; + margin-top: 12px; Qt::ScrollBarAlwaysOff @@ -114,7 +117,7 @@ 0 0 358 - 452 + 464 @@ -154,6 +157,12 @@ 0 + + + 0 + 60 + + border-color: palette(dark); border-style: solid; border-left-width: 1px; border-right-width: 1px; border-bottom-width: 1px; From 55d0835ba1645256d9ba83bfe7403ee82518fed0 Mon Sep 17 00:00:00 2001 From: Geenz Date: Thu, 13 Mar 2014 19:08:18 -0400 Subject: [PATCH 33/44] Indentation! --- interface/src/GLCanvas.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 249f7a373d..b68c4fdacd 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -14,8 +14,8 @@ #include GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer, QGL::NoStencilBuffer)), - _throttleRendering(false), - _idleRenderInterval(100) + _throttleRendering(false), + _idleRenderInterval(100) { } From 85a15a2284513d2a0a3481dc5aaf7ddcd8af1251 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Fri, 14 Mar 2014 00:43:02 +0200 Subject: [PATCH 34/44] Moved the chat from a window to a built-in panel. --- interface/interface_en.ts | 30 +++++++++++++++--------------- interface/src/Application.cpp | 10 +++++++++- interface/src/Menu.cpp | 16 +++++++--------- interface/src/ui/ChatWindow.cpp | 17 +++++++++++++---- interface/src/ui/ChatWindow.h | 7 ++++--- interface/ui/chatWindow.ui | 8 +++++++- 6 files changed, 55 insertions(+), 33 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index b6e35f3f5f..23ea3cc3ba 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -4,22 +4,22 @@ Application - + Export Voxels - + Sparse Voxel Octree Files (*.svo) - + Open Script - + JavaScript Files (*.js) @@ -27,25 +27,25 @@ ChatWindow - + Chat - + Connecting to XMPP... - + online now: - + day %n day @@ -53,7 +53,7 @@ - + hour %n hour @@ -61,7 +61,7 @@ - + minute %n minute @@ -76,7 +76,7 @@ - + %1 online now: @@ -113,18 +113,18 @@ Menu - + Open .ini config file - - + + Text files (*.ini) - + Save .ini config file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index aed212c692..b08f8f77f1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -291,7 +292,14 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : ResourceCache::setNetworkAccessManager(_networkAccessManager); ResourceCache::setRequestLimit(3); - _window->setCentralWidget(_glWidget); + QWidget* centralWidget = new QWidget(); + QHBoxLayout* mainLayout = new QHBoxLayout(); + mainLayout->setSpacing(0); + mainLayout->setContentsMargins(0, 0, 0, 0); + centralWidget->setLayout(mainLayout); + _glWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + centralWidget->layout()->addWidget(_glWidget); + _window->setCentralWidget(centralWidget); restoreSizeAndPosition(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 71e24e2382..c92d550fd6 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1041,22 +1041,20 @@ void Menu::showChat() { if (!_chatWindow) { _chatWindow = new ChatWindow(); QMainWindow* mainWindow = Application::getInstance()->getWindow(); - _chatWindow->setGeometry(mainWindow->width() - _chatWindow->width(), - mainWindow->geometry().y(), - _chatWindow->width(), - mainWindow->height()); + QBoxLayout* boxLayout = static_cast(mainWindow->centralWidget()->layout()); + boxLayout->addWidget(_chatWindow, 0, Qt::AlignRight); + } else { + if (!_chatWindow->isVisible()) { + _chatWindow->show(); + } } - if (!_chatWindow->isVisible()) { - _chatWindow->show(); - } - _chatWindow->raise(); } void Menu::toggleChat() { #ifdef HAVE_QXMPP _chatAction->setEnabled(XmppClient::getInstance().getXMPPClient().isConnected()); if (!_chatAction->isEnabled() && _chatWindow) { - _chatWindow->close(); + _chatWindow->hide(); } #endif } diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index d4f257c0f7..103f045cfa 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -28,7 +28,7 @@ const int NUM_MESSAGES_TO_TIME_STAMP = 20; const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?))://\\S+)"); ChatWindow::ChatWindow() : - QDialog(Application::getInstance()->getGLWidget(), Qt::CustomizeWindowHint), + QWidget(), ui(new Ui::ChatWindow), numMessagesAfterLastTimeStamp(0) { @@ -39,7 +39,6 @@ ChatWindow::ChatWindow() : ui->messagePlainTextEdit->installEventFilter(this); - setAttribute(Qt::WA_DeleteOnClose); #ifdef HAVE_QXMPP const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient(); if (xmppClient.isConnected()) { @@ -72,8 +71,18 @@ ChatWindow::~ChatWindow() { delete ui; } -void ChatWindow::reject() { - hide(); +void ChatWindow::keyPressEvent(QKeyEvent* event) { + QWidget::keyPressEvent(event); + if (event->key() == Qt::Key_Escape) { + hide(); + } +} + +void ChatWindow::showEvent(QShowEvent* event) { + QWidget::showEvent(event); + if (!event->spontaneous()) { + ui->messagePlainTextEdit->setFocus(); + } } bool ChatWindow::eventFilter(QObject* sender, QEvent* event) { diff --git a/interface/src/ui/ChatWindow.h b/interface/src/ui/ChatWindow.h index 57da4da45d..fbf9fc0859 100644 --- a/interface/src/ui/ChatWindow.h +++ b/interface/src/ui/ChatWindow.h @@ -9,9 +9,9 @@ #ifndef __interface__ChatWindow__ #define __interface__ChatWindow__ -#include #include #include +#include #include @@ -26,14 +26,15 @@ namespace Ui { class ChatWindow; } -class ChatWindow : public QDialog { +class ChatWindow : public QWidget { Q_OBJECT public: ChatWindow(); ~ChatWindow(); - virtual void reject(); + virtual void keyPressEvent(QKeyEvent *event); + virtual void showEvent(QShowEvent* event); protected: bool eventFilter(QObject* sender, QEvent* event); diff --git a/interface/ui/chatWindow.ui b/interface/ui/chatWindow.ui index 22f2dcd5dd..1106fca3cd 100644 --- a/interface/ui/chatWindow.ui +++ b/interface/ui/chatWindow.ui @@ -1,7 +1,7 @@ ChatWindow - + 0 @@ -10,6 +10,12 @@ 608 + + + 400 + 0 + + Chat From 9d1278b6637415b821cc8ed7a23e9a2fc5a2b426 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 16:18:47 -0700 Subject: [PATCH 35/44] Wait until we know that Faceshift didn't connect before we attempt to initialize Visage. --- interface/interface_en.ts | 4 ++-- interface/src/Application.cpp | 3 +++ interface/src/Menu.cpp | 2 +- interface/src/devices/Faceshift.cpp | 6 ++++++ interface/src/devices/Faceshift.h | 6 ++++++ interface/src/devices/Visage.cpp | 13 ++++++++++++- interface/src/devices/Visage.h | 6 +++++- 7 files changed, 35 insertions(+), 5 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 496e3a66e5..5eeacc67d8 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -14,12 +14,12 @@ - + Open Script - + JavaScript Files (*.js) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 96129e0161..a8b28f2c0a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1525,6 +1525,9 @@ void Application::init() { } qDebug("Loaded settings"); + // initialize Visage after loading the menu settings + _visage.init(); + // fire off an immediate domain-server check in now that settings are loaded NodeList::getInstance()->sendDomainServerCheckIn(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 4e880f2512..a42fe9da65 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -277,7 +277,7 @@ Menu::Menu() : SLOT(setTCPEnabled(bool))); #ifdef HAVE_VISAGE addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Visage, 0, true, - appInstance->getVisage(), SLOT(setEnabled(bool))); + appInstance->getVisage(), SLOT(updateEnabled())); #endif addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, false); diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 4fe89ff98b..8aa57fa792 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -49,12 +49,18 @@ Faceshift::Faceshift() : connect(&_tcpSocket, SIGNAL(connected()), SLOT(noteConnected())); connect(&_tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(noteError(QAbstractSocket::SocketError))); connect(&_tcpSocket, SIGNAL(readyRead()), SLOT(readFromSocket())); + connect(&_tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), SIGNAL(connectionStateChanged())); connect(&_udpSocket, SIGNAL(readyRead()), SLOT(readPendingDatagrams())); _udpSocket.bind(FACESHIFT_PORT); } +bool Faceshift::isConnectedOrConnecting() const { + return _tcpSocket.state() == QAbstractSocket::ConnectedState || + (_tcpRetryCount == 0 && _tcpSocket.state() != QAbstractSocket::UnconnectedState); +} + bool Faceshift::isActive() const { const quint64 ACTIVE_TIMEOUT_USECS = 1000000; return (usecTimestampNow() - _lastTrackingStateReceived) < ACTIVE_TIMEOUT_USECS; diff --git a/interface/src/devices/Faceshift.h b/interface/src/devices/Faceshift.h index 908354ae9d..66403715cd 100644 --- a/interface/src/devices/Faceshift.h +++ b/interface/src/devices/Faceshift.h @@ -27,6 +27,8 @@ public: Faceshift(); + bool isConnectedOrConnecting() const; + bool isActive() const; const glm::quat& getHeadRotation() const { return _headRotation; } @@ -66,6 +68,10 @@ public: void updateFakeCoefficients(float leftBlink, float rightBlink, float browUp, float jawOpen, std::vector& coefficients) const; +signals: + + void connectionStateChanged(); + public slots: void setTCPEnabled(bool enabled); diff --git a/interface/src/devices/Visage.cpp b/interface/src/devices/Visage.cpp index 876a810431..51b7324568 100644 --- a/interface/src/devices/Visage.cpp +++ b/interface/src/devices/Visage.cpp @@ -109,6 +109,11 @@ static const QMultiHash >& getActionUnitNameMap() const float TRANSLATION_SCALE = 20.0f; +void Visage::init() { + connect(Application::getInstance()->getFaceshift(), SIGNAL(connectionStateChanged()), SLOT(updateEnabled())); + updateEnabled(); +} + void Visage::update() { #ifdef HAVE_VISAGE _active = (_tracker->getTrackingData(_data) == TRACK_STAT_OK); @@ -153,12 +158,18 @@ void Visage::reset() { _headOrigin += _headTranslation / TRANSLATION_SCALE; } +void Visage::updateEnabled() { + setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Visage) && + !(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift) && + Application::getInstance()->getFaceshift()->isConnectedOrConnecting())); +} + void Visage::setEnabled(bool enabled) { #ifdef HAVE_VISAGE if (_enabled == enabled) { return; } - if (_enabled = enabled) { + if ((_enabled = enabled)) { _tracker->trackFromCam(); } else { _tracker->stop(); diff --git a/interface/src/devices/Visage.h b/interface/src/devices/Visage.h index e71bdc0fb5..7e50812ba7 100644 --- a/interface/src/devices/Visage.h +++ b/interface/src/devices/Visage.h @@ -32,6 +32,8 @@ public: Visage(); virtual ~Visage(); + void init(); + bool isActive() const { return _active; } const glm::quat& getHeadRotation() const { return _headRotation; } @@ -47,7 +49,7 @@ public: public slots: - void setEnabled(bool enabled); + void updateEnabled(); private: @@ -57,6 +59,8 @@ private: QMultiHash > _actionUnitIndexMap; #endif + void setEnabled(bool enabled); + bool _enabled; bool _active; glm::quat _headRotation; From 92bc675c97b03e8de2824150b166f2e6e9acbc91 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 16:21:45 -0700 Subject: [PATCH 36/44] Make sure to stop Visage before deleting it. --- interface/src/devices/Visage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/devices/Visage.cpp b/interface/src/devices/Visage.cpp index 51b7324568..b96ef1ee72 100644 --- a/interface/src/devices/Visage.cpp +++ b/interface/src/devices/Visage.cpp @@ -48,6 +48,7 @@ Visage::Visage() : Visage::~Visage() { #ifdef HAVE_VISAGE + _tracker->stop(); delete _tracker; delete _data; #endif From 5f6f4b3d37480abf3b373e2946028d0336b45253 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 16:45:27 -0700 Subject: [PATCH 37/44] Fixes required since enabling Faceshift is now the default. --- interface/interface_en.ts | 4 ++-- interface/src/Application.cpp | 3 ++- interface/src/devices/Faceshift.cpp | 6 +++++- interface/src/devices/Faceshift.h | 2 ++ 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 5eeacc67d8..53b8c8a0c5 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -14,12 +14,12 @@ - + Open Script - + JavaScript Files (*.js) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a8b28f2c0a..f616234cbc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1525,7 +1525,8 @@ void Application::init() { } qDebug("Loaded settings"); - // initialize Visage after loading the menu settings + // initialize Visage and Faceshift after loading the menu settings + _faceshift.init(); _visage.init(); // fire off an immediate domain-server check in now that settings are loaded diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 8aa57fa792..88974ce493 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -21,7 +21,7 @@ using namespace std; const quint16 FACESHIFT_PORT = 33433; Faceshift::Faceshift() : - _tcpEnabled(false), + _tcpEnabled(true), _tcpRetryCount(0), _lastTrackingStateReceived(0), _eyeGazeLeftPitch(0.0f), @@ -56,6 +56,10 @@ Faceshift::Faceshift() : _udpSocket.bind(FACESHIFT_PORT); } +void Faceshift::init() { + setTCPEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift)); +} + bool Faceshift::isConnectedOrConnecting() const { return _tcpSocket.state() == QAbstractSocket::ConnectedState || (_tcpRetryCount == 0 && _tcpSocket.state() != QAbstractSocket::UnconnectedState); diff --git a/interface/src/devices/Faceshift.h b/interface/src/devices/Faceshift.h index 66403715cd..a0898c446d 100644 --- a/interface/src/devices/Faceshift.h +++ b/interface/src/devices/Faceshift.h @@ -27,6 +27,8 @@ public: Faceshift(); + void init(); + bool isConnectedOrConnecting() const; bool isActive() const; From 38d03febbc7ccb1790119878c65550949782e2e9 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 16:58:15 -0700 Subject: [PATCH 38/44] Add this file back. Hope it didn't have anything important! --- interface/interface_en.ts | 154 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 interface/interface_en.ts diff --git a/interface/interface_en.ts b/interface/interface_en.ts new file mode 100644 index 0000000000..531e8966dc --- /dev/null +++ b/interface/interface_en.ts @@ -0,0 +1,154 @@ + + + + + Application + + + Export Voxels + + + + + Sparse Voxel Octree Files (*.svo) + + + + + Open Script + + + + + JavaScript Files (*.js) + + + + + ChatWindow + + + + Chat + + + + + + Connecting to XMPP... + + + + + + online now: + + + + + day + + + + + + + + hour + + + + + + + + minute + + + + + + + + %1 online now: + + + + + Dialog + + + + + + Update Required + + + + + + Download + + + + + + Skip Version + + + + + + Close + + + + + Menu + + + Open .ini config file + + + + + + Text files (*.ini) + + + + + Save .ini config file + + + + + QObject + + + + Import Voxels + + + + + Loading ... + + + + + Place voxels + + + + + <b>Import</b> %1 as voxels + + + + + Cancel + + + + From 3f78ef40f1aef043d4f2cd811ceb9656ddf8ec59 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 17:08:23 -0700 Subject: [PATCH 39/44] Fixed the translation file. --- interface/interface_en.ts | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 531e8966dc..c52ec91671 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -47,25 +47,32 @@ day - - - + + %n day + %n days hour - - - + + %n hour + %n hours minute - - - + + %n minute + %n minutes + + + + second + + %n second + %n seconds From b721533f0b934eb2ac77886a10ca3426e7da252f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 14 Mar 2014 10:43:12 -0700 Subject: [PATCH 40/44] Make chat a dock widget, since that's the behavior it's emulating anyway (and for some reason, the current strategy causes a problem on at least Ryan's and my machine). --- interface/interface_en.ts | 16 ++++++++-------- interface/src/Application.cpp | 10 +--------- interface/src/Menu.cpp | 6 ++---- interface/src/ui/ChatWindow.cpp | 1 - interface/src/ui/ChatWindow.h | 4 ++-- 5 files changed, 13 insertions(+), 24 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index c52ec91671..434acb80be 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -4,22 +4,22 @@ Application - + Export Voxels - + Sparse Voxel Octree Files (*.svo) - + Open Script - + JavaScript Files (*.js) @@ -45,7 +45,7 @@ - + day %n day @@ -53,7 +53,7 @@ - + hour %n hour @@ -61,7 +61,7 @@ - + minute %n minute @@ -76,7 +76,7 @@ - + %1 online now: diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fedde89a38..37b2810c68 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -292,14 +291,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : ResourceCache::setNetworkAccessManager(_networkAccessManager); ResourceCache::setRequestLimit(3); - QWidget* centralWidget = new QWidget(); - QHBoxLayout* mainLayout = new QHBoxLayout(); - mainLayout->setSpacing(0); - mainLayout->setContentsMargins(0, 0, 0, 0); - centralWidget->setLayout(mainLayout); - _glWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - centralWidget->layout()->addWidget(_glWidget); - _window->setCentralWidget(centralWidget); + _window->setCentralWidget(_glWidget); restoreSizeAndPosition(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 15cfb78cca..22b441d868 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1044,10 +1044,8 @@ void Menu::showMetavoxelEditor() { void Menu::showChat() { if (!_chatWindow) { - _chatWindow = new ChatWindow(); - QMainWindow* mainWindow = Application::getInstance()->getWindow(); - QBoxLayout* boxLayout = static_cast(mainWindow->centralWidget()->layout()); - boxLayout->addWidget(_chatWindow, 0, Qt::AlignRight); + Application::getInstance()->getWindow()->addDockWidget(Qt::RightDockWidgetArea, _chatWindow = new ChatWindow()); + } else { if (!_chatWindow->isVisible()) { _chatWindow->show(); diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index 103f045cfa..e28051f214 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -28,7 +28,6 @@ const int NUM_MESSAGES_TO_TIME_STAMP = 20; const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?))://\\S+)"); ChatWindow::ChatWindow() : - QWidget(), ui(new Ui::ChatWindow), numMessagesAfterLastTimeStamp(0) { diff --git a/interface/src/ui/ChatWindow.h b/interface/src/ui/ChatWindow.h index fbf9fc0859..da8d423b9d 100644 --- a/interface/src/ui/ChatWindow.h +++ b/interface/src/ui/ChatWindow.h @@ -10,8 +10,8 @@ #define __interface__ChatWindow__ #include +#include #include -#include #include @@ -26,7 +26,7 @@ namespace Ui { class ChatWindow; } -class ChatWindow : public QWidget { +class ChatWindow : public QDockWidget { Q_OBJECT public: From a7d35944ccd22bad8cfbcf1b5c806ea284debada Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 14 Mar 2014 10:48:57 -0700 Subject: [PATCH 41/44] Use an inner widget for the dock. --- interface/interface_en.ts | 8 ++++---- interface/src/ui/ChatWindow.cpp | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 434acb80be..9565d6e88a 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -45,7 +45,7 @@ - + day %n day @@ -53,7 +53,7 @@ - + hour %n hour @@ -61,7 +61,7 @@ - + minute %n minute @@ -76,7 +76,7 @@ - + %1 online now: diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index e28051f214..b7587f9508 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -31,7 +31,10 @@ ChatWindow::ChatWindow() : ui(new Ui::ChatWindow), numMessagesAfterLastTimeStamp(0) { - ui->setupUi(this); + QWidget* widget = new QWidget(); + setWidget(widget); + + ui->setupUi(widget); FlowLayout* flowLayout = new FlowLayout(0, 4, 4); ui->usersWidget->setLayout(flowLayout); From 5f7e41b79bf59567f36d6c8ca709f1eb07ad9ee7 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 14 Mar 2014 10:55:27 -0700 Subject: [PATCH 42/44] More dock widget tweaks. --- interface/interface_en.ts | 8 ++++---- interface/src/Menu.cpp | 8 ++++---- interface/src/ui/ChatWindow.cpp | 2 ++ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 9565d6e88a..f07f50f287 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -45,7 +45,7 @@ - + day %n day @@ -53,7 +53,7 @@ - + hour %n hour @@ -61,7 +61,7 @@ - + minute %n minute @@ -76,7 +76,7 @@ - + %1 online now: diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 22b441d868..c4b7fdcdd6 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1047,8 +1047,8 @@ void Menu::showChat() { Application::getInstance()->getWindow()->addDockWidget(Qt::RightDockWidgetArea, _chatWindow = new ChatWindow()); } else { - if (!_chatWindow->isVisible()) { - _chatWindow->show(); + if (!_chatWindow->toggleViewAction()->isChecked()) { + _chatWindow->toggleViewAction()->trigger(); } } } @@ -1056,8 +1056,8 @@ void Menu::showChat() { void Menu::toggleChat() { #ifdef HAVE_QXMPP _chatAction->setEnabled(XmppClient::getInstance().getXMPPClient().isConnected()); - if (!_chatAction->isEnabled() && _chatWindow) { - _chatWindow->hide(); + if (!_chatAction->isEnabled() && _chatWindow && _chatWindow->toggleViewAction()->isChecked()) { + _chatWindow->toggleViewAction()->trigger(); } #endif } diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index b7587f9508..55f32c5c7c 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -41,6 +41,8 @@ ChatWindow::ChatWindow() : ui->messagePlainTextEdit->installEventFilter(this); + ui->closeButton->hide(); + #ifdef HAVE_QXMPP const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient(); if (xmppClient.isConnected()) { From 4366b45445c79e1852a3772f87bacafa68780ec3 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 14 Mar 2014 11:13:15 -0700 Subject: [PATCH 43/44] Changed orientation tweak names, restore tweaked orientation rather than primary one. Closes #2310. --- interface/src/avatar/Head.cpp | 12 ++++++------ interface/src/avatar/Head.h | 17 +++++++++++------ interface/src/avatar/MyAvatar.cpp | 11 ++++++----- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 6c2bad865f..a9b85ffce2 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -36,9 +36,9 @@ Head::Head(Avatar* owningAvatar) : _leftEyeBlinkVelocity(0.0f), _rightEyeBlinkVelocity(0.0f), _timeWithoutTalking(0.0f), - _tweakedPitch(0.f), - _tweakedYaw(0.f), - _tweakedRoll(0.f), + _pitchTweak(0.f), + _yawTweak(0.f), + _rollTweak(0.f), _isCameraMoving(false), _faceModel(this) { @@ -202,15 +202,15 @@ glm::vec3 Head::getScalePivot() const { } float Head::getTweakedYaw() const { - return glm::clamp(_yaw + _tweakedYaw, MIN_HEAD_YAW, MAX_HEAD_YAW); + return glm::clamp(_yaw + _yawTweak, MIN_HEAD_YAW, MAX_HEAD_YAW); } float Head::getTweakedPitch() const { - return glm::clamp(_pitch + _tweakedPitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH); + return glm::clamp(_pitch + _pitchTweak, MIN_HEAD_PITCH, MAX_HEAD_PITCH); } float Head::getTweakedRoll() const { - return glm::clamp(_roll + _tweakedRoll, MIN_HEAD_ROLL, MAX_HEAD_ROLL); + return glm::clamp(_roll + _rollTweak, MIN_HEAD_ROLL, MAX_HEAD_ROLL); } void Head::applyCollision(CollisionInfo& collision) { diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 7e7a96a3a7..a9ea9b4cc6 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -70,10 +70,15 @@ public: /// Returns the point about which scaling occurs. glm::vec3 getScalePivot() const; - void tweakPitch(float pitch) { _tweakedPitch = pitch; } - void tweakYaw(float yaw) { _tweakedYaw = yaw; } - void tweakRoll(float roll) { _tweakedRoll = roll; } + void setPitchTweak(float pitch) { _pitchTweak = pitch; } + float getPitchTweak() const { return _pitchTweak; } + void setYawTweak(float yaw) { _yawTweak = yaw; } + float getYawTweak() const { return _yawTweak; } + + void setRollTweak(float roll) { _rollTweak = roll; } + float getRollTweak() const { return _rollTweak; } + virtual float getTweakedPitch() const; virtual float getTweakedYaw() const; virtual float getTweakedRoll() const; @@ -104,9 +109,9 @@ private: float _timeWithoutTalking; // tweaked angles affect the rendered head, but not the camera - float _tweakedPitch; - float _tweakedYaw; - float _tweakedRoll; + float _pitchTweak; + float _yawTweak; + float _rollTweak; bool _isCameraMoving; FaceModel _faceModel; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 0a2462e656..e4aaa07a4b 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -363,8 +363,9 @@ void MyAvatar::updateFromGyros(float deltaTime) { // restore rotation, lean to neutral positions const float RESTORE_PERIOD = 1.f; // seconds float restorePercentage = glm::clamp(deltaTime/RESTORE_PERIOD, 0.f, 1.f); - head->setYaw(glm::mix(head->getYaw(), 0.0f, restorePercentage)); - head->setRoll(glm::mix(head->getRoll(), 0.0f, restorePercentage)); + head->setPitchTweak(glm::mix(head->getPitchTweak(), 0.0f, restorePercentage)); + head->setYawTweak(glm::mix(head->getYawTweak(), 0.0f, restorePercentage)); + head->setRollTweak(glm::mix(head->getRollTweak(), 0.0f, restorePercentage)); head->setLeanSideways(glm::mix(head->getLeanSideways(), 0.0f, restorePercentage)); head->setLeanForward(glm::mix(head->getLeanForward(), 0.0f, restorePercentage)); return; @@ -375,9 +376,9 @@ void MyAvatar::updateFromGyros(float deltaTime) { const float AVATAR_HEAD_PITCH_MAGNIFY = 1.0f; const float AVATAR_HEAD_YAW_MAGNIFY = 1.0f; const float AVATAR_HEAD_ROLL_MAGNIFY = 1.0f; - head->tweakPitch(estimatedRotation.x * AVATAR_HEAD_PITCH_MAGNIFY); - head->tweakYaw(estimatedRotation.y * AVATAR_HEAD_YAW_MAGNIFY); - head->tweakRoll(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY); + head->setPitchTweak(estimatedRotation.x * AVATAR_HEAD_PITCH_MAGNIFY); + head->setYawTweak(estimatedRotation.y * AVATAR_HEAD_YAW_MAGNIFY); + head->setRollTweak(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY); // Update torso lean distance based on accelerometer data const float TORSO_LENGTH = 0.5f; From 8f200e917b78790874adc4268cd22f1ee67c73c1 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 14 Mar 2014 13:03:14 -0700 Subject: [PATCH 44/44] fix JS radians vs degrees issues --- examples/cameraExample.js | 2 +- examples/crazylegs.js | 8 ++++---- examples/gun.js | 2 +- examples/hydraMove.js | 2 +- examples/lookWithMouse.js | 2 +- examples/lookWithTouch.js | 2 +- examples/multitouchExample.js | 2 +- examples/seeingVoxelsExample.js | 4 ++-- libraries/script-engine/src/Quat.cpp | 12 ++++++++++-- libraries/script-engine/src/Quat.h | 6 ++++-- 10 files changed, 26 insertions(+), 16 deletions(-) diff --git a/examples/cameraExample.js b/examples/cameraExample.js index ddfff15935..6e3c51a348 100644 --- a/examples/cameraExample.js +++ b/examples/cameraExample.js @@ -74,7 +74,7 @@ function checkCamera(deltaTime) { if (yaw < -360) { yaw += 360; } - var orientation = Quat.fromPitchYawRoll(pitch, yaw, roll); + var orientation = Quat.fromPitchYawRollDegrees(pitch, yaw, roll); Camera.setOrientation(orientation); } } diff --git a/examples/crazylegs.js b/examples/crazylegs.js index 0f26088ae0..0daf2275f3 100644 --- a/examples/crazylegs.js +++ b/examples/crazylegs.js @@ -14,10 +14,10 @@ var cumulativeTime = 0.0; Script.update.connect(function(deltaTime) { cumulativeTime += deltaTime; - MyAvatar.setJointData("joint_R_hip", Quat.fromPitchYawRoll(0.0, 0.0, AMPLITUDE * Math.sin(cumulativeTime * FREQUENCY))); - MyAvatar.setJointData("joint_L_hip", Quat.fromPitchYawRoll(0.0, 0.0, -AMPLITUDE * Math.sin(cumulativeTime * FREQUENCY))); - MyAvatar.setJointData("joint_R_knee", Quat.fromPitchYawRoll(0.0, 0.0, + MyAvatar.setJointData("joint_R_hip", Quat.fromPitchYawRollDegrees(0.0, 0.0, AMPLITUDE * Math.sin(cumulativeTime * FREQUENCY))); + MyAvatar.setJointData("joint_L_hip", Quat.fromPitchYawRollDegrees(0.0, 0.0, -AMPLITUDE * Math.sin(cumulativeTime * FREQUENCY))); + MyAvatar.setJointData("joint_R_knee", Quat.fromPitchYawRollDegrees(0.0, 0.0, AMPLITUDE * (1.0 + Math.sin(cumulativeTime * FREQUENCY)))); - MyAvatar.setJointData("joint_L_knee", Quat.fromPitchYawRoll(0.0, 0.0, + MyAvatar.setJointData("joint_L_knee", Quat.fromPitchYawRollDegrees(0.0, 0.0, AMPLITUDE * (1.0 - Math.sin(cumulativeTime * FREQUENCY)))); }); diff --git a/examples/gun.js b/examples/gun.js index dee01fb84d..45b7487f25 100644 --- a/examples/gun.js +++ b/examples/gun.js @@ -78,7 +78,7 @@ function update(deltaTime) { // Check for mouseLook movement, update rotation // rotate body yaw for yaw received from mouse - var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3( { x: 0, y: yawFromMouse, z: 0 } )); + var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Radians( { x: 0, y: yawFromMouse, z: 0 } )); MyAvatar.orientation = newOrientation; yawFromMouse = 0; diff --git a/examples/hydraMove.js b/examples/hydraMove.js index 1f9634a8e6..92c594df9e 100644 --- a/examples/hydraMove.js +++ b/examples/hydraMove.js @@ -184,7 +184,7 @@ function flyWithHydra(deltaTime) { // change the body yaw based on our x controller var orientation = MyAvatar.orientation; - var deltaOrientation = Quat.fromPitchYawRoll(0, (-1 * viewJoystickPosition.x * JOYSTICK_YAW_MAG * deltaTime), 0); + var deltaOrientation = Quat.fromPitchYawRollDegrees(0, (-1 * viewJoystickPosition.x * JOYSTICK_YAW_MAG * deltaTime), 0); MyAvatar.orientation = Quat.multiply(orientation, deltaOrientation); // change the headPitch based on our x controller diff --git a/examples/lookWithMouse.js b/examples/lookWithMouse.js index 878813a94a..ef8f11ec16 100644 --- a/examples/lookWithMouse.js +++ b/examples/lookWithMouse.js @@ -54,7 +54,7 @@ function update(deltaTime) { print("update()..."); } // rotate body yaw for yaw received from mouse - var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3( { x: 0, y: yawFromMouse, z: 0 } )); + var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Radians( { x: 0, y: yawFromMouse, z: 0 } )); if (wantDebugging) { print("changing orientation" + " [old]MyAvatar.orientation="+MyAvatar.orientation.x + "," + MyAvatar.orientation.y + "," diff --git a/examples/lookWithTouch.js b/examples/lookWithTouch.js index ddc42c04c0..852573aea6 100644 --- a/examples/lookWithTouch.js +++ b/examples/lookWithTouch.js @@ -45,7 +45,7 @@ function touchUpdateEvent(event) { function update(deltaTime) { // rotate body yaw for yaw received from mouse - var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3( { x: 0, y: yawFromMouse, z: 0 } )); + var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromPitchYawRollRadians(0, yawFromMouse, 0)); if (wantDebugging) { print("changing orientation" + " [old]MyAvatar.orientation="+MyAvatar.orientation.x + "," + MyAvatar.orientation.y + "," diff --git a/examples/multitouchExample.js b/examples/multitouchExample.js index 1041651c7b..51bbcc2c20 100644 --- a/examples/multitouchExample.js +++ b/examples/multitouchExample.js @@ -92,7 +92,7 @@ Controller.touchEndEvent.connect(touchEndEvent); function update(deltaTime) { // rotate body yaw for yaw received from multitouch rotate - var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3( { x: 0, y: yawFromMultiTouch, z: 0 } )); + var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Radians( { x: 0, y: yawFromMultiTouch, z: 0 } )); if (wantDebugging) { print("changing orientation" + " [old]MyAvatar.orientation="+MyAvatar.orientation.x + "," + MyAvatar.orientation.y + "," diff --git a/examples/seeingVoxelsExample.js b/examples/seeingVoxelsExample.js index 62ebd599ee..257e869b5b 100644 --- a/examples/seeingVoxelsExample.js +++ b/examples/seeingVoxelsExample.js @@ -17,7 +17,7 @@ var yawMin = 20; var isLocal = false; // set up our VoxelViewer with a position and orientation -var orientation = Quat.fromPitchYawRoll(0, yaw, 0); +var orientation = Quat.fromPitchYawRollDegrees(0, yaw, 0); function init() { if (isLocal) { @@ -40,7 +40,7 @@ function keepLooking(deltaTime) { count++; if (count % 10 == 0) { yaw += yawDirection; - orientation = Quat.fromPitchYawRoll(0, yaw, 0); + orientation = Quat.fromPitchYawRollDegrees(0, yaw, 0); if (yaw > yawMax || yaw < yawMin) { yawDirection = yawDirection * -1; } diff --git a/libraries/script-engine/src/Quat.cpp b/libraries/script-engine/src/Quat.cpp index 14025f0c67..c939811db4 100644 --- a/libraries/script-engine/src/Quat.cpp +++ b/libraries/script-engine/src/Quat.cpp @@ -22,14 +22,22 @@ glm::quat Quat::multiply(const glm::quat& q1, const glm::quat& q2) { return q1 * q2; } -glm::quat Quat::fromVec3(const glm::vec3& eulerAngles) { +glm::quat Quat::fromVec3Degrees(const glm::vec3& eulerAngles) { return glm::quat(glm::radians(eulerAngles)); } -glm::quat Quat::fromPitchYawRoll(float pitch, float yaw, float roll) { +glm::quat Quat::fromVec3Radians(const glm::vec3& eulerAngles) { + return glm::quat(eulerAngles); +} + +glm::quat Quat::fromPitchYawRollDegrees(float pitch, float yaw, float roll) { return glm::quat(glm::radians(glm::vec3(pitch, yaw, roll))); } +glm::quat Quat::fromPitchYawRollRadians(float pitch, float yaw, float roll) { + return glm::quat(glm::vec3(pitch, yaw, roll)); +} + glm::quat Quat::inverse(const glm::quat& q) { return glm::inverse(q); } diff --git a/libraries/script-engine/src/Quat.h b/libraries/script-engine/src/Quat.h index 3e5f46682c..02c0a3e147 100644 --- a/libraries/script-engine/src/Quat.h +++ b/libraries/script-engine/src/Quat.h @@ -23,8 +23,10 @@ class Quat : public QObject { public slots: glm::quat multiply(const glm::quat& q1, const glm::quat& q2); - glm::quat fromVec3(const glm::vec3& vec3); - glm::quat fromPitchYawRoll(float pitch, float yaw, float roll); // degrees + glm::quat fromVec3Degrees(const glm::vec3& vec3); // degrees + glm::quat fromVec3Radians(const glm::vec3& vec3); // radians + glm::quat fromPitchYawRollDegrees(float pitch, float yaw, float roll); // degrees + glm::quat fromPitchYawRollRadians(float pitch, float yaw, float roll); // radians glm::quat inverse(const glm::quat& q); glm::vec3 getFront(const glm::quat& orientation); glm::vec3 getRight(const glm::quat& orientation);