From a46080cbf2889818c5e33d6e9be6a2f24320f574 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 8 Jan 2015 11:23:20 -0800 Subject: [PATCH 01/51] editModels > hydraGrab --- examples/editModels.js | 3043 ---------------------------------------- examples/hydraGrab.js | 742 ++++++++++ 2 files changed, 742 insertions(+), 3043 deletions(-) delete mode 100644 examples/editModels.js create mode 100644 examples/hydraGrab.js diff --git a/examples/editModels.js b/examples/editModels.js deleted file mode 100644 index 8ec099650a..0000000000 --- a/examples/editModels.js +++ /dev/null @@ -1,3043 +0,0 @@ -// -// editEntities.js -// examples -// -// Created by Clément Brisset on 4/24/14. -// Copyright 2014 High Fidelity, Inc. -// -// This script allows you to edit models either with the razor hydras or with your mouse -// -// If using the hydras : -// grab grab models with the triggers, you can then move the models around or scale them with both hands. -// You can switch mode using the bumpers so that you can move models around more easily. -// -// If using the mouse : -// - left click lets you move the model in the plane facing you. -// If pressing shift, it will move on the horizontal plane it's in. -// - right click lets you rotate the model. z and x give access to more axes of rotation while shift provides finer control. -// - left + right click lets you scale the model. -// - you can press r while holding the model to reset its rotation -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -Script.include("libraries/globals.js"); -Script.include("libraries/toolBars.js"); - -Script.include("libraries/entityPropertyDialogBox.js"); -var entityPropertyDialogBox = EntityPropertyDialogBox; - -var windowDimensions = Controller.getViewportDimensions(); -var toolIconUrl = HIFI_PUBLIC_BUCKET + "images/tools/"; -var toolHeight = 50; -var toolWidth = 50; - -var LASER_WIDTH = 4; -var LASER_COLOR = { red: 255, green: 0, blue: 0 }; -var LASER_LENGTH_FACTOR = 500; - -var MIN_ANGULAR_SIZE = 2; -var MAX_ANGULAR_SIZE = 45; -var allowLargeModels = false; -var allowSmallModels = false; -var wantEntityGlow = false; - -var LEFT = 0; -var RIGHT = 1; - -var SPAWN_DISTANCE = 1; -var DEFAULT_DIMENSION = 0.20; -var DEFAULT_TEXT_DIMENSION_X = 1.0; -var DEFAULT_TEXT_DIMENSION_Y = 1.0; -var DEFAULT_TEXT_DIMENSION_Z = 0.01; - -var modelURLs = [ - HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Alder.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Bush1.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Bush6.fbx", - HIFI_PUBLIC_BUCKET + "meshes/newInvader16x16-large-purple.svo", - HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed2.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed4.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed7.fbx" - ]; - -var jointList = MyAvatar.getJointNames(); - -var mode = 0; -var isActive = false; - - -if (typeof String.prototype.fileName !== "function") { - String.prototype.fileName = function () { - return this.replace(/^(.*[\/\\])*/, ""); - }; -} - -if (typeof String.prototype.fileBase !== "function") { - String.prototype.fileBase = function () { - var filename = this.fileName(); - return filename.slice(0, filename.indexOf(".")); - }; -} - -if (typeof String.prototype.fileType !== "function") { - String.prototype.fileType = function () { - return this.slice(this.lastIndexOf(".") + 1); - }; -} - -if (typeof String.prototype.path !== "function") { - String.prototype.path = function () { - return this.replace(/[\\\/][^\\\/]*$/, ""); - }; -} - -if (typeof String.prototype.regExpEscape !== "function") { - String.prototype.regExpEscape = function () { - return this.replace(/([$\^.+*?|\\\/{}()\[\]])/g, '\\$1'); - }; -} - -if (typeof String.prototype.toArrayBuffer !== "function") { - String.prototype.toArrayBuffer = function () { - var length, - buffer, - view, - charCode, - charCodes, - i; - - charCodes = []; - - length = this.length; - for (i = 0; i < length; i += 1) { - charCode = this.charCodeAt(i); - if (charCode <= 255) { - charCodes.push(charCode); - } else { - charCodes.push(charCode / 256); - charCodes.push(charCode % 256); - } - } - - length = charCodes.length; - buffer = new ArrayBuffer(length); - view = new Uint8Array(buffer); - for (i = 0; i < length; i += 1) { - view[i] = charCodes[i]; - } - - return buffer; - }; -} - -if (typeof DataView.prototype.indexOf !== "function") { - DataView.prototype.indexOf = function (searchString, position) { - var searchLength = searchString.length, - byteArrayLength = this.byteLength, - maxSearchIndex = byteArrayLength - searchLength, - searchCharCodes = [], - found, - i, - j; - - searchCharCodes[searchLength] = 0; - for (j = 0; j < searchLength; j += 1) { - searchCharCodes[j] = searchString.charCodeAt(j); - } - - i = position; - found = false; - while (i < maxSearchIndex && !found) { - j = 0; - while (j < searchLength && this.getUint8(i + j) === searchCharCodes[j]) { - j += 1; - } - found = (j === searchLength); - i += 1; - } - - return found ? i - 1 : -1; - }; -} - -if (typeof DataView.prototype.string !== "function") { - DataView.prototype.string = function (start, length) { - var charCodes = [], - end, - i; - - if (start === undefined) { - start = 0; - } - if (length === undefined) { - length = this.length; - } - - end = start + length; - for (i = start; i < end; i += 1) { - charCodes.push(this.getUint8(i)); - } - - return String.fromCharCode.apply(String, charCodes); - }; -} - -var progressDialog = (function () { - var that = {}, - progressBackground, - progressMessage, - cancelButton, - displayed = false, - backgroundWidth = 300, - backgroundHeight = 100, - messageHeight = 32, - cancelWidth = 70, - cancelHeight = 32, - textColor = { red: 255, green: 255, blue: 255 }, - textBackground = { red: 52, green: 52, blue: 52 }, - backgroundUrl = toolIconUrl + "progress-background.svg", - windowDimensions; - - progressBackground = Overlays.addOverlay("image", { - width: backgroundWidth, - height: backgroundHeight, - imageURL: backgroundUrl, - alpha: 0.9, - backgroundAlpha: 0.9, - visible: false - }); - - progressMessage = Overlays.addOverlay("text", { - width: backgroundWidth - 40, - height: messageHeight, - text: "", - textColor: textColor, - backgroundColor: textBackground, - alpha: 0.9, - backgroundAlpha: 0.9, - visible: false - }); - - cancelButton = Overlays.addOverlay("text", { - width: cancelWidth, - height: cancelHeight, - text: "Cancel", - textColor: textColor, - backgroundColor: textBackground, - alpha: 0.9, - backgroundAlpha: 0.9, - visible: false - }); - - function move() { - var progressX, - progressY; - - if (displayed) { - - if (windowDimensions.x === Window.innerWidth && windowDimensions.y === Window.innerHeight) { - return; - } - windowDimensions.x = Window.innerWidth; - windowDimensions.y = Window.innerHeight; - - progressX = (windowDimensions.x - backgroundWidth) / 2; // Center. - progressY = windowDimensions.y / 2 - backgroundHeight; // A little up from center. - - Overlays.editOverlay(progressBackground, { x: progressX, y: progressY }); - Overlays.editOverlay(progressMessage, { x: progressX + 20, y: progressY + 15 }); - Overlays.editOverlay(cancelButton, { - x: progressX + backgroundWidth - cancelWidth - 20, - y: progressY + backgroundHeight - cancelHeight - 15 - }); - } - } - that.move = move; - - that.onCancel = undefined; - - function open(message) { - if (!displayed) { - windowDimensions = { x: 0, y : 0 }; - displayed = true; - move(); - Overlays.editOverlay(progressBackground, { visible: true }); - Overlays.editOverlay(progressMessage, { visible: true, text: message }); - Overlays.editOverlay(cancelButton, { visible: true }); - } else { - throw new Error("open() called on progressDialog when already open"); - } - } - that.open = open; - - function isOpen() { - return displayed; - } - that.isOpen = isOpen; - - function update(message) { - if (displayed) { - Overlays.editOverlay(progressMessage, { text: message }); - } else { - throw new Error("update() called on progressDialog when not open"); - } - } - that.update = update; - - function close() { - if (displayed) { - Overlays.editOverlay(cancelButton, { visible: false }); - Overlays.editOverlay(progressMessage, { visible: false }); - Overlays.editOverlay(progressBackground, { visible: false }); - displayed = false; - } else { - throw new Error("close() called on progressDialog when not open"); - } - } - that.close = close; - - function mousePressEvent(event) { - if (Overlays.getOverlayAtPoint({ x: event.x, y: event.y }) === cancelButton) { - if (typeof this.onCancel === "function") { - close(); - this.onCancel(); - } - return true; - } - return false; - } - that.mousePressEvent = mousePressEvent; - - function cleanup() { - Overlays.deleteOverlay(cancelButton); - Overlays.deleteOverlay(progressMessage); - Overlays.deleteOverlay(progressBackground); - } - that.cleanup = cleanup; - - return that; -}()); - -var httpMultiPart = (function () { - var that = {}, - parts, - byteLength, - boundaryString, - crlf; - - function clear() { - boundaryString = "--boundary_" + String(Uuid.generate()).slice(1, 36) + "="; - parts = []; - byteLength = 0; - crlf = ""; - } - that.clear = clear; - - function boundary() { - return boundaryString.slice(2); - } - that.boundary = boundary; - - function length() { - return byteLength; - } - that.length = length; - - function add(object) { - // - name, string - // - name, buffer - var buffer, - string, - stringBuffer, - compressedBuffer; - - if (object.name === undefined) { - - throw new Error("Item to add to HttpMultiPart must have a name"); - - } else if (object.string !== undefined) { - //--= - //Content-Disposition: form-data; name="model_name" - // - // - - string = crlf + boundaryString + "\r\n" - + "Content-Disposition: form-data; name=\"" + object.name + "\"\r\n" - + "\r\n" - + object.string; - buffer = string.toArrayBuffer(); - - } else if (object.buffer !== undefined) { - //--= - //Content-Disposition: form-data; name="fbx"; filename="" - //Content-Type: application/octet-stream - // - // - - string = crlf + boundaryString + "\r\n" - + "Content-Disposition: form-data; name=\"" + object.name - + "\"; filename=\"" + object.buffer.filename + "\"\r\n" - + "Content-Type: application/octet-stream\r\n" - + "\r\n"; - stringBuffer = string.toArrayBuffer(); - - compressedBuffer = object.buffer.buffer.compress(); - buffer = new Uint8Array(stringBuffer.byteLength + compressedBuffer.byteLength); - buffer.set(new Uint8Array(stringBuffer)); - buffer.set(new Uint8Array(compressedBuffer), stringBuffer.byteLength); - - } else { - - throw new Error("Item to add to HttpMultiPart not recognized"); - } - - byteLength += buffer.byteLength; - parts.push(buffer); - - crlf = "\r\n"; - - return true; - } - that.add = add; - - function response() { - var buffer, - index, - str, - i; - - str = crlf + boundaryString + "--\r\n"; - buffer = str.toArrayBuffer(); - byteLength += buffer.byteLength; - parts.push(buffer); - - buffer = new Uint8Array(byteLength); - index = 0; - for (i = 0; i < parts.length; i += 1) { - buffer.set(new Uint8Array(parts[i]), index); - index += parts[i].byteLength; - } - - return buffer; - } - that.response = response; - - clear(); - - return that; -}()); - -var modelUploader = (function () { - var that = {}, - modelFile, - modelName, - modelURL, - modelCallback, - isProcessing, - fstBuffer, - fbxBuffer, - //svoBuffer, - mapping, - geometry, - API_URL = "https://data.highfidelity.io/api/v1/models", - MODEL_URL = "http://public.highfidelity.io/models/content", - NAME_FIELD = "name", - SCALE_FIELD = "scale", - FILENAME_FIELD = "filename", - TEXDIR_FIELD = "texdir", - MAX_TEXTURE_SIZE = 1024; - - function info(message) { - if (progressDialog.isOpen()) { - progressDialog.update(message); - } else { - progressDialog.open(message); - } - print(message); - } - - function error(message) { - if (progressDialog.isOpen()) { - progressDialog.close(); - } - print(message); - Window.alert(message); - } - - function randomChar(length) { - var characters = "0123457689abcdefghijklmnopqrstuvwxyz", - string = "", - i; - - for (i = 0; i < length; i += 1) { - string += characters[Math.floor(Math.random() * 36)]; - } - - return string; - } - - function resetDataObjects() { - fstBuffer = null; - fbxBuffer = null; - //svoBuffer = null; - mapping = {}; - geometry = {}; - geometry.textures = []; - geometry.embedded = []; - } - - function readFile(filename) { - var url = "file:///" + filename, - req = new XMLHttpRequest(); - - req.open("GET", url, false); - req.responseType = "arraybuffer"; - req.send(); - if (req.status !== 200) { - error("Could not read file: " + filename + " : " + req.statusText); - return null; - } - - return { - filename: filename.fileName(), - buffer: req.response - }; - } - - function readMapping(buffer) { - var dv = new DataView(buffer.buffer), - lines, - line, - tokens, - i, - name, - value, - remainder, - existing; - - mapping = {}; // { name : value | name : { value : [remainder] } } - lines = dv.string(0, dv.byteLength).split(/\r\n|\r|\n/); - for (i = 0; i < lines.length; i += 1) { - line = lines[i].trim(); - if (line.length > 0 && line[0] !== "#") { - tokens = line.split(/\s*=\s*/); - if (tokens.length > 1) { - name = tokens[0]; - value = tokens[1]; - if (tokens.length > 2) { - remainder = tokens.slice(2, tokens.length).join(" = "); - } else { - remainder = null; - } - if (tokens.length === 2 && mapping[name] === undefined) { - mapping[name] = value; - } else { - if (mapping[name] === undefined) { - mapping[name] = {}; - - } else if (typeof mapping[name] !== "object") { - existing = mapping[name]; - mapping[name] = { existing : null }; - } - - if (mapping[name][value] === undefined) { - mapping[name][value] = []; - } - mapping[name][value].push(remainder); - } - } - } - } - } - - function writeMapping(buffer) { - var name, - value, - remainder, - i, - string = ""; - - for (name in mapping) { - if (mapping.hasOwnProperty(name)) { - if (typeof mapping[name] === "object") { - for (value in mapping[name]) { - if (mapping[name].hasOwnProperty(value)) { - remainder = mapping[name][value]; - if (remainder === null) { - string += (name + " = " + value + "\n"); - } else { - for (i = 0; i < remainder.length; i += 1) { - string += (name + " = " + value + " = " + remainder[i] + "\n"); - } - } - } - } - } else { - string += (name + " = " + mapping[name] + "\n"); - } - } - } - - buffer.buffer = string.toArrayBuffer(); - } - - function readGeometry(fbxBuffer) { - var textures, - view, - index, - EOF, - previousNodeFilename; - - // Reference: - // http://code.blender.org/index.php/2013/08/fbx-binary-file-format-specification/ - - textures = {}; - view = new DataView(fbxBuffer.buffer); - EOF = false; - - function parseBinaryFBX() { - var endOffset, - numProperties, - propertyListLength, - nameLength, - name, - filename; - - endOffset = view.getUint32(index, true); - numProperties = view.getUint32(index + 4, true); - propertyListLength = view.getUint32(index + 8, true); - nameLength = view.getUint8(index + 12); - index += 13; - - if (endOffset === 0) { - return; - } - if (endOffset < index || endOffset > view.byteLength) { - EOF = true; - return; - } - - name = view.string(index, nameLength).toLowerCase(); - index += nameLength; - - if (name === "content" && previousNodeFilename !== "") { - // Blender 2.71 exporter "embeds" external textures as empty binary blobs so ignore these - if (propertyListLength > 5) { - geometry.embedded.push(previousNodeFilename); - } - } - - if (name === "relativefilename") { - filename = view.string(index + 5, view.getUint32(index + 1, true)).fileName(); - if (!textures.hasOwnProperty(filename)) { - textures[filename] = ""; - geometry.textures.push(filename); - } - previousNodeFilename = filename; - } else { - previousNodeFilename = ""; - } - - index += (propertyListLength); - - while (index < endOffset && !EOF) { - parseBinaryFBX(); - } - } - - function readTextFBX() { - var line, - view, - viewLength, - charCode, - charCodes, - numCharCodes, - filename, - relativeFilename = "", - MAX_CHAR_CODES = 250; - - view = new Uint8Array(fbxBuffer.buffer); - viewLength = view.byteLength; - charCodes = []; - numCharCodes = 0; - - for (index = 0; index < viewLength; index += 1) { - charCode = view[index]; - if (charCode !== 9 && charCode !== 32) { - if (charCode === 10) { // EOL. Can ignore EOF. - line = String.fromCharCode.apply(String, charCodes).toLowerCase(); - // For embedded textures, "Content:" line immediately follows "RelativeFilename:" line. - if (line.slice(0, 8) === "content:" && relativeFilename !== "") { - geometry.embedded.push(relativeFilename); - } - if (line.slice(0, 17) === "relativefilename:") { - filename = line.slice(line.indexOf("\""), line.lastIndexOf("\"") - line.length).fileName(); - if (!textures.hasOwnProperty(filename)) { - textures[filename] = ""; - geometry.textures.push(filename); - } - relativeFilename = filename; - } else { - relativeFilename = ""; - } - charCodes = []; - numCharCodes = 0; - } else { - if (numCharCodes < MAX_CHAR_CODES) { // Only interested in start of line - charCodes.push(charCode); - numCharCodes += 1; - } - } - } - } - } - - if (view.string(0, 18) === "Kaydara FBX Binary") { - previousNodeFilename = ""; - - index = 27; - while (index < view.byteLength - 39 && !EOF) { - parseBinaryFBX(); - } - - } else { - - readTextFBX(); - - } - } - - function readModel() { - var fbxFilename, - //svoFilename, - fileType; - - info("Reading model file"); - print("Model file: " + modelFile); - - if (modelFile.toLowerCase().fileType() === "fst") { - fstBuffer = readFile(modelFile); - if (fstBuffer === null) { - return false; - } - readMapping(fstBuffer); - fileType = mapping[FILENAME_FIELD].toLowerCase().fileType(); - if (mapping.hasOwnProperty(FILENAME_FIELD)) { - if (fileType === "fbx") { - fbxFilename = modelFile.path() + "\\" + mapping[FILENAME_FIELD]; - //} else if (fileType === "svo") { - // svoFilename = modelFile.path() + "\\" + mapping[FILENAME_FIELD]; - } else { - error("Unrecognized model type in FST file!"); - return false; - } - } else { - error("Model file name not found in FST file!"); - return false; - } - } else { - fstBuffer = { - filename: "Interface." + randomChar(6), // Simulate avatar model uploading behaviour - buffer: null - }; - - if (modelFile.toLowerCase().fileType() === "fbx") { - fbxFilename = modelFile; - mapping[FILENAME_FIELD] = modelFile.fileName(); - - //} else if (modelFile.toLowerCase().fileType() === "svo") { - // svoFilename = modelFile; - // mapping[FILENAME_FIELD] = modelFile.fileName(); - - } else { - error("Unrecognized file type: " + modelFile); - return false; - } - } - - if (!isProcessing) { return false; } - - if (fbxFilename) { - fbxBuffer = readFile(fbxFilename); - if (fbxBuffer === null) { - return false; - } - - if (!isProcessing) { return false; } - - readGeometry(fbxBuffer); - } - - //if (svoFilename) { - // svoBuffer = readFile(svoFilename); - // if (svoBuffer === null) { - // return false; - // } - //} - - // Add any missing basic mappings - if (!mapping.hasOwnProperty(NAME_FIELD)) { - mapping[NAME_FIELD] = modelFile.fileName().fileBase(); - } - if (!mapping.hasOwnProperty(TEXDIR_FIELD)) { - mapping[TEXDIR_FIELD] = "."; - } - if (!mapping.hasOwnProperty(SCALE_FIELD)) { - mapping[SCALE_FIELD] = 1.0; - } - - return true; - } - - function setProperties() { - var form = [], - directory, - displayAs, - validateAs; - - progressDialog.close(); - print("Setting model properties"); - - form.push({ label: "Name:", value: mapping[NAME_FIELD] }); - - directory = modelFile.path() + "/" + mapping[TEXDIR_FIELD]; - displayAs = new RegExp("^" + modelFile.path().regExpEscape() + "[\\\\\\\/](.*)"); - validateAs = new RegExp("^" + modelFile.path().regExpEscape() + "([\\\\\\\/].*)?"); - - form.push({ - label: "Texture directory:", - directory: modelFile.path() + "/" + mapping[TEXDIR_FIELD], - title: "Choose Texture Directory", - displayAs: displayAs, - validateAs: validateAs, - errorMessage: "Texture directory must be subdirectory of the model directory." - }); - - form.push({ button: "Cancel" }); - - if (!Window.form("Set Model Properties", form)) { - print("User cancelled uploading model"); - return false; - } - - mapping[NAME_FIELD] = form[0].value; - mapping[TEXDIR_FIELD] = form[1].directory.slice(modelFile.path().length + 1); - if (mapping[TEXDIR_FIELD] === "") { - mapping[TEXDIR_FIELD] = "."; - } - - writeMapping(fstBuffer); - - return true; - } - - function createHttpMessage(callback) { - var multiparts = [], - lodCount, - lodFile, - lodBuffer, - textureBuffer, - textureSourceFormat, - textureTargetFormat, - embeddedTextures, - i; - - info("Preparing to send model"); - - // Model name - if (mapping.hasOwnProperty(NAME_FIELD)) { - multiparts.push({ - name : "model_name", - string : mapping[NAME_FIELD] - }); - } else { - error("Model name is missing"); - httpMultiPart.clear(); - return; - } - - // FST file - if (fstBuffer) { - multiparts.push({ - name : "fst", - buffer: fstBuffer - }); - } - - // FBX file - if (fbxBuffer) { - multiparts.push({ - name : "fbx", - buffer: fbxBuffer - }); - } - - // SVO file - //if (svoBuffer) { - // multiparts.push({ - // name : "svo", - // buffer: svoBuffer - // }); - //} - - // LOD files - lodCount = 0; - for (lodFile in mapping.lod) { - if (mapping.lod.hasOwnProperty(lodFile)) { - lodBuffer = readFile(modelFile.path() + "\/" + lodFile); - if (lodBuffer === null) { - return; - } - multiparts.push({ - name: "lod" + lodCount, - buffer: lodBuffer - }); - lodCount += 1; - } - if (!isProcessing) { return; } - } - - // Textures - embeddedTextures = "|" + geometry.embedded.join("|") + "|"; - for (i = 0; i < geometry.textures.length; i += 1) { - if (embeddedTextures.indexOf("|" + geometry.textures[i].fileName() + "|") === -1) { - textureBuffer = readFile(modelFile.path() + "\/" - + (mapping[TEXDIR_FIELD] !== "." ? mapping[TEXDIR_FIELD] + "\/" : "") - + geometry.textures[i]); - if (textureBuffer === null) { - return; - } - - textureSourceFormat = geometry.textures[i].fileType().toLowerCase(); - textureTargetFormat = (textureSourceFormat === "jpg" ? "jpg" : "png"); - textureBuffer.buffer = - textureBuffer.buffer.recodeImage(textureSourceFormat, textureTargetFormat, MAX_TEXTURE_SIZE); - textureBuffer.filename = textureBuffer.filename.slice(0, -textureSourceFormat.length) + textureTargetFormat; - - multiparts.push({ - name: "texture" + i, - buffer: textureBuffer - }); - } - - if (!isProcessing) { return; } - } - - // Model category - multiparts.push({ - name : "model_category", - string : "content" - }); - - // Create HTTP message - httpMultiPart.clear(); - Script.setTimeout(function addMultipart() { - var multipart = multiparts.shift(); - httpMultiPart.add(multipart); - - if (!isProcessing) { return; } - - if (multiparts.length > 0) { - Script.setTimeout(addMultipart, 25); - } else { - callback(); - } - }, 25); - } - - function sendToHighFidelity() { - var req, - uploadedChecks, - HTTP_GET_TIMEOUT = 60, // 1 minute - HTTP_SEND_TIMEOUT = 900, // 15 minutes - UPLOADED_CHECKS = 30, - CHECK_UPLOADED_TIMEOUT = 1, // 1 second - handleCheckUploadedResponses, - handleUploadModelResponses, - handleRequestUploadResponses; - - function uploadTimedOut() { - error("Model upload failed: Internet request timed out!"); - } - - function debugResponse() { - print("req.errorCode = " + req.errorCode); - print("req.readyState = " + req.readyState); - print("req.status = " + req.status); - print("req.statusText = " + req.statusText); - print("req.responseType = " + req.responseType); - print("req.responseText = " + req.responseText); - print("req.response = " + req.response); - print("req.getAllResponseHeaders() = " + req.getAllResponseHeaders()); - } - - function checkUploaded() { - if (!isProcessing) { return; } - - info("Checking uploaded model"); - - req = new XMLHttpRequest(); - req.open("HEAD", modelURL, true); - req.timeout = HTTP_GET_TIMEOUT * 1000; - req.onreadystatechange = handleCheckUploadedResponses; - req.ontimeout = uploadTimedOut; - req.send(); - } - - handleCheckUploadedResponses = function () { - //debugResponse(); - if (req.readyState === req.DONE) { - if (req.status === 200) { - // Note: Unlike avatar models, for content models we don't need to refresh texture cache. - print("Model uploaded: " + modelURL); - progressDialog.close(); - if (Window.confirm("Your model has been uploaded as: " + modelURL + "\nDo you want to rez it?")) { - modelCallback(modelURL); - } - } else if (req.status === 404) { - if (uploadedChecks > 0) { - uploadedChecks -= 1; - Script.setTimeout(checkUploaded, CHECK_UPLOADED_TIMEOUT * 1000); - } else { - print("Error: " + req.status + " " + req.statusText); - error("We could not verify that your model was successfully uploaded but it may have been at: " - + modelURL); - } - } else { - print("Error: " + req.status + " " + req.statusText); - error("There was a problem with your upload, please try again later."); - } - } - }; - - function uploadModel(method) { - var url; - - if (!isProcessing) { return; } - - req = new XMLHttpRequest(); - if (method === "PUT") { - url = API_URL + "\/" + modelName; - req.open("PUT", url, true); //print("PUT " + url); - } else { - url = API_URL; - req.open("POST", url, true); //print("POST " + url); - } - req.setRequestHeader("Content-Type", "multipart/form-data; boundary=\"" + httpMultiPart.boundary() + "\""); - req.timeout = HTTP_SEND_TIMEOUT * 1000; - req.onreadystatechange = handleUploadModelResponses; - req.ontimeout = uploadTimedOut; - req.send(httpMultiPart.response().buffer); - } - - handleUploadModelResponses = function () { - //debugResponse(); - if (req.readyState === req.DONE) { - if (req.status === 200) { - uploadedChecks = UPLOADED_CHECKS; - checkUploaded(); - } else { - print("Error: " + req.status + " " + req.statusText); - error("There was a problem with your upload, please try again later."); - } - } - }; - - function requestUpload() { - var url; - - if (!isProcessing) { return; } - - url = API_URL + "\/" + modelName; // XMLHttpRequest automatically handles authorization of API requests. - req = new XMLHttpRequest(); - req.open("GET", url, true); //print("GET " + url); - req.responseType = "json"; - req.timeout = HTTP_GET_TIMEOUT * 1000; - req.onreadystatechange = handleRequestUploadResponses; - req.ontimeout = uploadTimedOut; - req.send(); - } - - handleRequestUploadResponses = function () { - var response; - - //debugResponse(); - if (req.readyState === req.DONE) { - if (req.status === 200) { - if (req.responseType === "json") { - response = JSON.parse(req.responseText); - if (response.status === "success") { - if (response.exists === false) { - uploadModel("POST"); - } else if (response.can_update === true) { - uploadModel("PUT"); - } else { - error("This model file already exists and is owned by someone else!"); - } - return; - } - } - } else { - print("Error: " + req.status + " " + req.statusText); - } - error("Model upload failed! Something went wrong at the data server."); - } - }; - - info("Sending model to High Fidelity"); - - requestUpload(); - } - - that.upload = function (file, callback) { - - modelFile = file; - modelCallback = callback; - - isProcessing = true; - - progressDialog.onCancel = function () { - print("User cancelled uploading model"); - isProcessing = false; - }; - - resetDataObjects(); - - if (readModel()) { - if (setProperties()) { - modelName = mapping[NAME_FIELD]; - modelURL = MODEL_URL + "\/" + mapping[NAME_FIELD] + ".fst"; // All models are uploaded as an FST - - createHttpMessage(sendToHighFidelity); - } - } - - resetDataObjects(); - }; - - return that; -}()); - -var toolBar = (function () { - var that = {}, - toolBar, - activeButton, - newModelButton, - newCubeButton, - newSphereButton, - newTextButton, - browseModelsButton, - loadURLMenuItem, - loadFileMenuItem, - menuItemWidth, - menuItemOffset, - menuItemHeight, - menuItemMargin = 5, - menuTextColor = { red: 255, green: 255, blue: 255 }, - menuBackgroundColor = { red: 18, green: 66, blue: 66 }; - - function initialize() { - toolBar = new ToolBar(0, 0, ToolBar.VERTICAL); - - activeButton = toolBar.addTool({ - imageURL: toolIconUrl + "models-tool.svg", - subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - width: toolWidth, - height: toolHeight, - alpha: 0.9, - visible: true - }, true, false); - - newModelButton = toolBar.addTool({ - imageURL: toolIconUrl + "add-model-tool.svg", - subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - width: toolWidth, - height: toolHeight, - alpha: 0.9, - visible: true - }, true, false); - - browseModelsButton = toolBar.addTool({ - imageURL: toolIconUrl + "list-icon.svg", - width: toolWidth, - height: toolHeight, - alpha: 0.9, - visible: true - }); - - menuItemOffset = toolBar.height / 3 + 2; - menuItemHeight = Tool.IMAGE_HEIGHT / 2 - 2; - - loadURLMenuItem = Overlays.addOverlay("text", { - height: menuItemHeight, - backgroundColor: menuBackgroundColor, - topMargin: menuItemMargin, - text: "Model URL", - alpha: 0.9, - backgroundAlpha: 0.9, - visible: false - }); - - loadFileMenuItem = Overlays.addOverlay("text", { - height: menuItemHeight, - backgroundColor: menuBackgroundColor, - topMargin: menuItemMargin, - text: "Model File", - alpha: 0.9, - backgroundAlpha: 0.9, - visible: false - }); - - menuItemWidth = Math.max(Overlays.textSize(loadURLMenuItem, "Model URL").width, - Overlays.textSize(loadFileMenuItem, "Model File").width) + 20; - Overlays.editOverlay(loadURLMenuItem, { width: menuItemWidth }); - Overlays.editOverlay(loadFileMenuItem, { width: menuItemWidth }); - - newCubeButton = toolBar.addTool({ - imageURL: toolIconUrl + "add-cube.svg", - subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - width: toolWidth, - height: toolHeight, - alpha: 0.9, - visible: true - }); - - newSphereButton = toolBar.addTool({ - imageURL: toolIconUrl + "add-sphere.svg", - subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - width: toolWidth, - height: toolHeight, - alpha: 0.9, - visible: true - }); - - newTextButton = toolBar.addTool({ - //imageURL: toolIconUrl + "add-text.svg", - imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/tools/add-text.svg", // temporarily - subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - width: toolWidth, - height: toolHeight, - alpha: 0.9, - visible: true - }); - } - - function toggleNewModelButton(active) { - if (active === undefined) { - active = !toolBar.toolSelected(newModelButton); - } - toolBar.selectTool(newModelButton, active); - - Overlays.editOverlay(loadURLMenuItem, { visible: active }); - Overlays.editOverlay(loadFileMenuItem, { visible: active }); - } - - var RESIZE_INTERVAL = 50; - var RESIZE_TIMEOUT = 20000; - var RESIZE_MAX_CHECKS = RESIZE_TIMEOUT / RESIZE_INTERVAL; - function addModel(url) { - var position; - - position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); - - if (position.x > 0 && position.y > 0 && position.z > 0) { - var entityId = Entities.addEntity({ - type: "Model", - position: position, - dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION }, - modelURL: url - }); - print("Model added: " + url); - - var checkCount = 0; - function resize() { - var entityProperties = Entities.getEntityProperties(entityId); - var naturalDimensions = entityProperties.naturalDimensions; - - checkCount++; - - if (naturalDimensions.x == 0 && naturalDimensions.y == 0 && naturalDimensions.z == 0) { - if (checkCount < RESIZE_MAX_CHECKS) { - Script.setTimeout(resize, RESIZE_INTERVAL); - } else { - print("Resize failed: timed out waiting for model (" + url + ") to load"); - } - } else { - entityProperties.dimensions = naturalDimensions; - Entities.editEntity(entityId, entityProperties); - } - } - - Script.setTimeout(resize, RESIZE_INTERVAL); - - } else { - print("Can't add model: Model would be out of bounds."); - } - } - - that.move = function () { - var newViewPort, - toolsX, - toolsY; - - newViewPort = Controller.getViewportDimensions(); - - if (toolBar === undefined) { - initialize(); - - } else if (windowDimensions.x === newViewPort.x && - windowDimensions.y === newViewPort.y) { - return; - } - - windowDimensions = newViewPort; - toolsX = windowDimensions.x - 8 - toolBar.width; - toolsY = (windowDimensions.y - toolBar.height) / 2; - - toolBar.move(toolsX, toolsY); - - Overlays.editOverlay(loadURLMenuItem, { x: toolsX - menuItemWidth, y: toolsY + menuItemOffset }); - Overlays.editOverlay(loadFileMenuItem, { x: toolsX - menuItemWidth, y: toolsY + menuItemOffset + menuItemHeight }); - }; - - that.mousePressEvent = function (event) { - var clickedOverlay, - url, - file; - - clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); - - if (activeButton === toolBar.clicked(clickedOverlay)) { - isActive = !isActive; - return true; - } - - if (newModelButton === toolBar.clicked(clickedOverlay)) { - toggleNewModelButton(); - return true; - } - - if (clickedOverlay === loadURLMenuItem) { - toggleNewModelButton(false); - url = Window.prompt("Model URL", modelURLs[Math.floor(Math.random() * modelURLs.length)]); - if (url !== null && url !== "") { - addModel(url); - } - return true; - } - - if (clickedOverlay === loadFileMenuItem) { - toggleNewModelButton(false); - - file = Window.browse("Select your model file ...", - Settings.getValue("LastModelUploadLocation").path(), - "Model files (*.fst *.fbx)"); - //"Model files (*.fst *.fbx *.svo)"); - if (file !== null) { - Settings.setValue("LastModelUploadLocation", file); - modelUploader.upload(file, addModel); - } - return true; - } - - if (browseModelsButton === toolBar.clicked(clickedOverlay)) { - toggleNewModelButton(false); - url = Window.s3Browse(".*(fbx|FBX)"); - if (url !== null && url !== "") { - addModel(url); - } - return true; - } - - if (newCubeButton === toolBar.clicked(clickedOverlay)) { - var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); - - if (position.x > 0 && position.y > 0 && position.z > 0) { - Entities.addEntity({ - type: "Box", - position: position, - dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION }, - color: { red: 255, green: 0, blue: 0 } - - }); - } else { - print("Can't create box: Box would be out of bounds."); - } - return true; - } - - if (newSphereButton === toolBar.clicked(clickedOverlay)) { - var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); - - if (position.x > 0 && position.y > 0 && position.z > 0) { - Entities.addEntity({ - type: "Sphere", - position: position, - dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION }, - color: { red: 255, green: 0, blue: 0 } - }); - } else { - print("Can't create box: Box would be out of bounds."); - } - return true; - } - - - if (newTextButton === toolBar.clicked(clickedOverlay)) { - var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); - - if (position.x > 0 && position.y > 0 && position.z > 0) { - Entities.addEntity({ - type: "Text", - position: position, - dimensions: { x: DEFAULT_TEXT_DIMENSION_X, y: DEFAULT_TEXT_DIMENSION_Y, z: DEFAULT_TEXT_DIMENSION_Z }, - backgroundColor: { red: 0, green: 0, blue: 0 }, - textColor: { red: 255, green: 255, blue: 255 }, - text: "some text", - lineHight: "0.1" - }); - } else { - print("Can't create box: Text would be out of bounds."); - } - return true; - } - - return false; - }; - - that.cleanup = function () { - toolBar.cleanup(); - Overlays.deleteOverlay(loadURLMenuItem); - Overlays.deleteOverlay(loadFileMenuItem); - }; - - return that; -}()); - - -var exportMenu = null; - -var ExportMenu = function (opts) { - var self = this; - - var windowDimensions = Controller.getViewportDimensions(); - var pos = { x: windowDimensions.x / 2, y: windowDimensions.y - 100 }; - - this._onClose = opts.onClose || function () { }; - this._position = { x: 0.0, y: 0.0, z: 0.0 }; - this._scale = 1.0; - - var minScale = 1; - var maxScale = 32768; - var titleWidth = 120; - var locationWidth = 100; - var scaleWidth = 144; - var exportWidth = 100; - var cancelWidth = 100; - var margin = 4; - var height = 30; - var outerHeight = height + (2 * margin); - var buttonColor = { red: 128, green: 128, blue: 128 }; - - var SCALE_MINUS = scaleWidth * 40.0 / 100.0; - var SCALE_PLUS = scaleWidth * 63.0 / 100.0; - - var fullWidth = locationWidth + scaleWidth + exportWidth + cancelWidth + (2 * margin); - var offset = fullWidth / 2; - pos.x -= offset; - - var background = Overlays.addOverlay("text", { - x: pos.x, - y: pos.y, - opacity: 1, - width: fullWidth, - height: outerHeight, - backgroundColor: { red: 200, green: 200, blue: 200 }, - text: "", - }); - - var titleText = Overlays.addOverlay("text", { - x: pos.x, - y: pos.y - height, - font: { size: 14 }, - width: titleWidth, - height: height, - backgroundColor: { red: 255, green: 255, blue: 255 }, - color: { red: 255, green: 255, blue: 255 }, - text: "Export Models" - }); - - var locationButton = Overlays.addOverlay("text", { - x: pos.x + margin, - y: pos.y + margin, - width: locationWidth, - height: height, - color: { red: 255, green: 255, blue: 255 }, - text: "0, 0, 0", - }); - var scaleOverlay = Overlays.addOverlay("image", { - x: pos.x + margin + locationWidth, - y: pos.y + margin, - width: scaleWidth, - height: height, - subImage: { x: 0, y: 3, width: 144, height: height }, - imageURL: toolIconUrl + "voxel-size-selector.svg", - alpha: 0.9, - }); - var scaleViewWidth = 40; - var scaleView = Overlays.addOverlay("text", { - x: pos.x + margin + locationWidth + SCALE_MINUS, - y: pos.y + margin, - width: scaleViewWidth, - height: height, - alpha: 0.0, - backgroundAlpha: 0.0, - color: { red: 255, green: 255, blue: 255 }, - text: "1" - }); - var exportButton = Overlays.addOverlay("text", { - x: pos.x + margin + locationWidth + scaleWidth, - y: pos.y + margin, - width: exportWidth, - height: height, - color: { red: 0, green: 255, blue: 255 }, - text: "Export" - }); - var cancelButton = Overlays.addOverlay("text", { - x: pos.x + margin + locationWidth + scaleWidth + exportWidth, - y: pos.y + margin, - width: cancelWidth, - height: height, - color: { red: 255, green: 255, blue: 255 }, - text: "Cancel" - }); - - var voxelPreview = Overlays.addOverlay("cube", { - position: { x: 0, y: 0, z: 0 }, - size: this._scale, - color: { red: 255, green: 255, blue: 0 }, - alpha: 1, - solid: false, - visible: true, - lineWidth: 4 - }); - - this.parsePosition = function (str) { - var parts = str.split(','); - if (parts.length == 3) { - var x = parseFloat(parts[0]); - var y = parseFloat(parts[1]); - var z = parseFloat(parts[2]); - if (isFinite(x) && isFinite(y) && isFinite(z)) { - return { x: x, y: y, z: z }; - } - } - return null; - }; - - this.showPositionPrompt = function () { - var positionStr = self._position.x + ", " + self._position.y + ", " + self._position.z; - while (1) { - positionStr = Window.prompt("Position to export form:", positionStr); - if (positionStr == null) { - break; - } - var position = self.parsePosition(positionStr); - if (position != null) { - self.setPosition(position.x, position.y, position.z); - break; - } - Window.alert("The position you entered was invalid."); - } - }; - - this.setScale = function (scale) { - self._scale = Math.min(maxScale, Math.max(minScale, scale)); - Overlays.editOverlay(scaleView, { text: self._scale }); - Overlays.editOverlay(voxelPreview, { size: self._scale }); - } - - this.decreaseScale = function () { - self.setScale(self._scale /= 2); - } - - this.increaseScale = function () { - self.setScale(self._scale *= 2); - } - - this.exportEntities = function() { - var x = self._position.x; - var y = self._position.y; - var z = self._position.z; - var s = self._scale; - var filename = "models__" + Window.location.hostname + "__" + x + "_" + y + "_" + z + "_" + s + "__.svo"; - filename = Window.save("Select where to save", filename, "*.svo") - if (filename) { - var success = Clipboard.exportEntities(filename, x, y, z, s); - if (!success) { - Window.alert("Export failed: no models found in selected area."); - } - } - self.close(); - }; - - this.getPosition = function () { - return self._position; - }; - - this.setPosition = function (x, y, z) { - self._position = { x: x, y: y, z: z }; - var positionStr = x + ", " + y + ", " + z; - Overlays.editOverlay(locationButton, { text: positionStr }); - Overlays.editOverlay(voxelPreview, { position: self._position }); - - }; - - this.mouseReleaseEvent = function (event) { - var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); - - if (clickedOverlay == locationButton) { - self.showPositionPrompt(); - } else if (clickedOverlay == exportButton) { - self.exportEntities(); - } else if (clickedOverlay == cancelButton) { - self.close(); - } else if (clickedOverlay == scaleOverlay) { - var x = event.x - pos.x - margin - locationWidth; - print(x); - if (x < SCALE_MINUS) { - self.decreaseScale(); - } else if (x > SCALE_PLUS) { - self.increaseScale(); - } - } - }; - - this.close = function () { - this.cleanup(); - this._onClose(); - }; - - this.cleanup = function () { - Overlays.deleteOverlay(background); - Overlays.deleteOverlay(titleText); - Overlays.deleteOverlay(locationButton); - Overlays.deleteOverlay(exportButton); - Overlays.deleteOverlay(cancelButton); - Overlays.deleteOverlay(voxelPreview); - Overlays.deleteOverlay(scaleOverlay); - Overlays.deleteOverlay(scaleView); - }; - - print("CONNECTING!"); - Controller.mouseReleaseEvent.connect(this.mouseReleaseEvent); -}; - - - -var ModelImporter = function (opts) { - var self = this; - - var height = 30; - var margin = 4; - var outerHeight = height + (2 * margin); - var titleWidth = 120; - var cancelWidth = 100; - var fullWidth = titleWidth + cancelWidth + (2 * margin); - - var localModels = Overlays.addOverlay("localmodels", { - position: { x: 1, y: 1, z: 1 }, - scale: 1, - visible: false - }); - var importScale = 1; - var importBoundaries = Overlays.addOverlay("cube", { - position: { x: 0, y: 0, z: 0 }, - size: 1, - color: { red: 128, blue: 128, green: 128 }, - lineWidth: 4, - solid: false, - visible: false - }); - - var pos = { x: windowDimensions.x / 2 - (fullWidth / 2), y: windowDimensions.y - 100 }; - - var background = Overlays.addOverlay("text", { - x: pos.x, - y: pos.y, - opacity: 1, - width: fullWidth, - height: outerHeight, - backgroundColor: { red: 200, green: 200, blue: 200 }, - visible: false, - text: "", - }); - - var titleText = Overlays.addOverlay("text", { - x: pos.x + margin, - y: pos.y + margin, - font: { size: 14 }, - width: titleWidth, - height: height, - backgroundColor: { red: 255, green: 255, blue: 255 }, - color: { red: 255, green: 255, blue: 255 }, - visible: false, - text: "Import Models" - }); - var cancelButton = Overlays.addOverlay("text", { - x: pos.x + margin + titleWidth, - y: pos.y + margin, - width: cancelWidth, - height: height, - color: { red: 255, green: 255, blue: 255 }, - visible: false, - text: "Close" - }); - this._importing = false; - - this.setImportVisible = function (visible) { - Overlays.editOverlay(importBoundaries, { visible: visible }); - Overlays.editOverlay(localModels, { visible: visible }); - Overlays.editOverlay(cancelButton, { visible: visible }); - Overlays.editOverlay(titleText, { visible: visible }); - Overlays.editOverlay(background, { visible: visible }); - }; - - var importPosition = { x: 0, y: 0, z: 0 }; - this.moveImport = function (position) { - importPosition = position; - Overlays.editOverlay(localModels, { - position: { x: importPosition.x, y: importPosition.y, z: importPosition.z } - }); - Overlays.editOverlay(importBoundaries, { - position: { x: importPosition.x, y: importPosition.y, z: importPosition.z } - }); - } - - this.mouseMoveEvent = function (event) { - if (self._importing) { - var pickRay = Camera.computePickRay(event.x, event.y); - var intersection = false; //Voxels.findRayIntersection(pickRay); - - var distance = 2;// * self._scale; - - if (false) {//intersection.intersects) { - var intersectionDistance = Vec3.length(Vec3.subtract(pickRay.origin, intersection.intersection)); - if (intersectionDistance < distance) { - distance = intersectionDistance * 0.99; - } - - } - - var targetPosition = { - x: pickRay.origin.x + (pickRay.direction.x * distance), - y: pickRay.origin.y + (pickRay.direction.y * distance), - z: pickRay.origin.z + (pickRay.direction.z * distance) - }; - - if (targetPosition.x < 0) targetPosition.x = 0; - if (targetPosition.y < 0) targetPosition.y = 0; - if (targetPosition.z < 0) targetPosition.z = 0; - - var nudgeFactor = 1; - var newPosition = { - x: Math.floor(targetPosition.x / nudgeFactor) * nudgeFactor, - y: Math.floor(targetPosition.y / nudgeFactor) * nudgeFactor, - z: Math.floor(targetPosition.z / nudgeFactor) * nudgeFactor - } - - self.moveImport(newPosition); - } - } - - this.mouseReleaseEvent = function (event) { - var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); - - if (clickedOverlay == cancelButton) { - self._importing = false; - self.setImportVisible(false); - } - }; - - // Would prefer to use {4} for the coords, but it would only capture the last digit. - var fileRegex = /__(.+)__(\d+(?:\.\d+)?)_(\d+(?:\.\d+)?)_(\d+(?:\.\d+)?)_(\d+(?:\.\d+)?)__/; - this.doImport = function () { - if (!self._importing) { - var filename = Window.browse("Select models to import", "", "*.svo") - if (filename) { - parts = fileRegex.exec(filename); - if (parts == null) { - Window.alert("The file you selected does not contain source domain or location information"); - } else { - var hostname = parts[1]; - var x = parts[2]; - var y = parts[3]; - var z = parts[4]; - var s = parts[5]; - importScale = s; - if (hostname != location.hostname) { - if (!Window.confirm(("These models were not originally exported from this domain. Continue?"))) { - return; - } - } else { - if (Window.confirm(("Would you like to import back to the source location?"))) { - var success = Clipboard.importEntities(filename); - if (success) { - Clipboard.pasteEntities(x, y, z, 1); - } else { - Window.alert("There was an error importing the entity file."); - } - return; - } - } - } - var success = Clipboard.importEntities(filename); - if (success) { - self._importing = true; - self.setImportVisible(true); - Overlays.editOverlay(importBoundaries, { size: s }); - } else { - Window.alert("There was an error importing the entity file."); - } - } - } - } - - this.paste = function () { - if (self._importing) { - // self._importing = false; - // self.setImportVisible(false); - Clipboard.pasteEntities(importPosition.x, importPosition.y, importPosition.z, 1); - } - } - - this.cleanup = function () { - Overlays.deleteOverlay(localModels); - Overlays.deleteOverlay(importBoundaries); - Overlays.deleteOverlay(cancelButton); - Overlays.deleteOverlay(titleText); - Overlays.deleteOverlay(background); - } - - Controller.mouseReleaseEvent.connect(this.mouseReleaseEvent); - Controller.mouseMoveEvent.connect(this.mouseMoveEvent); -}; - -var modelImporter = new ModelImporter(); - - -function isLocked(properties) { - // special case to lock the ground plane model in hq. - if (location.hostname == "hq.highfidelity.io" && - properties.modelURL == HIFI_PUBLIC_BUCKET + "ozan/Terrain_Reduce_forAlpha.fbx") { - return true; - } - return false; -} - - -function controller(wichSide) { - this.side = wichSide; - this.palm = 2 * wichSide; - this.tip = 2 * wichSide + 1; - this.trigger = wichSide; - this.bumper = 6 * wichSide + 5; - - this.oldPalmPosition = Controller.getSpatialControlPosition(this.palm); - this.palmPosition = Controller.getSpatialControlPosition(this.palm); - - this.oldTipPosition = Controller.getSpatialControlPosition(this.tip); - this.tipPosition = Controller.getSpatialControlPosition(this.tip); - - this.oldUp = Controller.getSpatialControlNormal(this.palm); - this.up = this.oldUp; - - this.oldFront = Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)); - this.front = this.oldFront; - - this.oldRight = Vec3.cross(this.front, this.up); - this.right = this.oldRight; - - this.oldRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm)); - this.rotation = this.oldRotation; - - this.triggerValue = Controller.getTriggerValue(this.trigger); - this.bumperValue = Controller.isButtonPressed(this.bumper); - - this.pressed = false; // is trigger pressed - this.pressing = false; // is trigger being pressed (is pressed now but wasn't previously) - - this.grabbing = false; - this.entityID = { isKnownID: false }; - this.modelURL = ""; - this.oldModelRotation; - this.oldModelPosition; - this.oldModelHalfDiagonal; - - this.positionAtGrab; - this.rotationAtGrab; - this.modelPositionAtGrab; - this.rotationAtGrab; - this.jointsIntersectingFromStart = []; - - this.laser = Overlays.addOverlay("line3d", { - start: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: LASER_COLOR, - alpha: 1, - visible: false, - lineWidth: LASER_WIDTH, - anchor: "MyAvatar" - }); - - this.guideScale = 0.02; - this.ball = Overlays.addOverlay("sphere", { - position: { x: 0, y: 0, z: 0 }, - size: this.guideScale, - solid: true, - color: { red: 0, green: 255, blue: 0 }, - alpha: 1, - visible: false, - anchor: "MyAvatar" - }); - this.leftRight = Overlays.addOverlay("line3d", { - start: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: { red: 0, green: 0, blue: 255 }, - alpha: 1, - visible: false, - lineWidth: LASER_WIDTH, - anchor: "MyAvatar" - }); - this.topDown = Overlays.addOverlay("line3d", { - start: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: { red: 0, green: 0, blue: 255 }, - alpha: 1, - visible: false, - lineWidth: LASER_WIDTH, - anchor: "MyAvatar" - }); - - - - this.grab = function (entityID, properties) { - if (isLocked(properties)) { - print("Model locked " + entityID.id); - } else { - print("Grabbing " + entityID.id); - this.grabbing = true; - this.entityID = entityID; - this.modelURL = properties.modelURL; - - this.oldModelPosition = properties.position; - this.oldModelRotation = properties.rotation; - this.oldModelHalfDiagonal = Vec3.length(properties.dimensions) / 2.0; - - this.positionAtGrab = this.palmPosition; - this.rotationAtGrab = this.rotation; - this.modelPositionAtGrab = properties.position; - this.rotationAtGrab = properties.rotation; - this.jointsIntersectingFromStart = []; - for (var i = 0; i < jointList.length; i++) { - var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition); - if (distance < this.oldModelHalfDiagonal) { - this.jointsIntersectingFromStart.push(i); - } - } - this.showLaser(false); - } - } - - this.release = function () { - if (this.grabbing) { - jointList = MyAvatar.getJointNames(); - - var closestJointIndex = -1; - var closestJointDistance = 10; - for (var i = 0; i < jointList.length; i++) { - var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition); - if (distance < closestJointDistance) { - closestJointDistance = distance; - closestJointIndex = i; - } - } - - if (closestJointIndex != -1) { - print("closestJoint: " + jointList[closestJointIndex]); - print("closestJointDistance (attach max distance): " + closestJointDistance + " (" + this.oldModelHalfDiagonal + ")"); - } - - if (closestJointDistance < this.oldModelHalfDiagonal) { - - if (this.jointsIntersectingFromStart.indexOf(closestJointIndex) != -1 || - (leftController.grabbing && rightController.grabbing && - leftController.entityID.id == rightController.entityID.id)) { - // Do nothing - } else { - print("Attaching to " + jointList[closestJointIndex]); - var jointPosition = MyAvatar.getJointPosition(jointList[closestJointIndex]); - var jointRotation = MyAvatar.getJointCombinedRotation(jointList[closestJointIndex]); - - var attachmentOffset = Vec3.subtract(this.oldModelPosition, jointPosition); - attachmentOffset = Vec3.multiplyQbyV(Quat.inverse(jointRotation), attachmentOffset); - var attachmentRotation = Quat.multiply(Quat.inverse(jointRotation), this.oldModelRotation); - - MyAvatar.attach(this.modelURL, jointList[closestJointIndex], - attachmentOffset, attachmentRotation, 2.0 * this.oldModelHalfDiagonal, - true, false); - Entities.deleteEntity(this.entityID); - } - } - } - - this.grabbing = false; - this.entityID.isKnownID = false; - this.jointsIntersectingFromStart = []; - this.showLaser(true); - } - - this.checkTrigger = function () { - if (this.triggerValue > 0.9) { - if (this.pressed) { - this.pressing = false; - } else { - this.pressing = true; - } - this.pressed = true; - } else { - this.pressing = false; - this.pressed = false; - } - } - - this.checkEntity = function (properties) { - // special case to lock the ground plane model in hq. - if (isLocked(properties)) { - return { valid: false }; - } - - - // P P - Model - // /| A - Palm - // / | d B - unit vector toward tip - // / | X - base of the perpendicular line - // A---X----->B d - distance fom axis - // x x - distance from A - // - // |X-A| = (P-A).B - // X == A + ((P-A).B)B - // d = |P-X| - - var A = this.palmPosition; - var B = this.front; - var P = properties.position; - - var x = Vec3.dot(Vec3.subtract(P, A), B); - var y = Vec3.dot(Vec3.subtract(P, A), this.up); - var z = Vec3.dot(Vec3.subtract(P, A), this.right); - var X = Vec3.sum(A, Vec3.multiply(B, x)); - var d = Vec3.length(Vec3.subtract(P, X)); - var halfDiagonal = Vec3.length(properties.dimensions) / 2.0; - - var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14; - - var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) - && (allowSmallModels || angularSize > MIN_ANGULAR_SIZE); - - if (0 < x && sizeOK) { - return { valid: true, x: x, y: y, z: z }; - } - return { valid: false }; - } - - this.glowedIntersectingModel = { isKnownID: false }; - this.moveLaser = function () { - // the overlays here are anchored to the avatar, which means they are specified in the avatar's local frame - - var inverseRotation = Quat.inverse(MyAvatar.orientation); - var startPosition = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.palmPosition, MyAvatar.position)); - var direction = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.tipPosition, this.palmPosition)); - var distance = Vec3.length(direction); - direction = Vec3.multiply(direction, LASER_LENGTH_FACTOR / distance); - var endPosition = Vec3.sum(startPosition, direction); - - Overlays.editOverlay(this.laser, { - start: startPosition, - end: endPosition - }); - - - Overlays.editOverlay(this.ball, { - position: endPosition - }); - Overlays.editOverlay(this.leftRight, { - start: Vec3.sum(endPosition, Vec3.multiply(this.right, 2 * this.guideScale)), - end: Vec3.sum(endPosition, Vec3.multiply(this.right, -2 * this.guideScale)) - }); - Overlays.editOverlay(this.topDown, { - start: Vec3.sum(endPosition, Vec3.multiply(this.up, 2 * this.guideScale)), - end: Vec3.sum(endPosition, Vec3.multiply(this.up, -2 * this.guideScale)) - }); - this.showLaser(!this.grabbing || mode == 0); - - if (this.glowedIntersectingModel.isKnownID) { - Entities.editEntity(this.glowedIntersectingModel, { glowLevel: 0.0 }); - this.glowedIntersectingModel.isKnownID = false; - } - if (!this.grabbing) { - var intersection = Entities.findRayIntersection({ - origin: this.palmPosition, - direction: this.front - }); - - var halfDiagonal = Vec3.length(intersection.properties.dimensions) / 2.0; - - var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), intersection.properties.position)) * 180 / 3.14; - var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) - && (allowSmallModels || angularSize > MIN_ANGULAR_SIZE); - if (intersection.accurate && intersection.entityID.isKnownID && sizeOK) { - this.glowedIntersectingModel = intersection.entityID; - - if (wantEntityGlow) { - Entities.editEntity(this.glowedIntersectingModel, { glowLevel: 0.25 }); - } - } - } - } - - this.showLaser = function (show) { - Overlays.editOverlay(this.laser, { visible: show }); - Overlays.editOverlay(this.ball, { visible: show }); - Overlays.editOverlay(this.leftRight, { visible: show }); - Overlays.editOverlay(this.topDown, { visible: show }); - } - this.moveEntity = function () { - if (this.grabbing) { - if (!this.entityID.isKnownID) { - print("Unknown grabbed ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID); - this.entityID = Entities.findRayIntersection({ - origin: this.palmPosition, - direction: this.front - }).entityID; - print("Identified ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID); - } - var newPosition; - var newRotation; - - switch (mode) { - case 0: - newPosition = Vec3.sum(this.palmPosition, - Vec3.multiply(this.front, this.x)); - newPosition = Vec3.sum(newPosition, - Vec3.multiply(this.up, this.y)); - newPosition = Vec3.sum(newPosition, - Vec3.multiply(this.right, this.z)); - - - newRotation = Quat.multiply(this.rotation, - Quat.inverse(this.oldRotation)); - newRotation = Quat.multiply(newRotation, - this.oldModelRotation); - break; - case 1: - var forward = Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -1 }); - var d = Vec3.dot(forward, MyAvatar.position); - - var factor1 = Vec3.dot(forward, this.positionAtGrab) - d; - var factor2 = Vec3.dot(forward, this.modelPositionAtGrab) - d; - var vector = Vec3.subtract(this.palmPosition, this.positionAtGrab); - - if (factor2 < 0) { - factor2 = 0; - } - if (factor1 <= 0) { - factor1 = 1; - factor2 = 1; - } - - newPosition = Vec3.sum(this.modelPositionAtGrab, - Vec3.multiply(vector, - factor2 / factor1)); - - newRotation = Quat.multiply(this.rotation, - Quat.inverse(this.rotationAtGrab)); - newRotation = Quat.multiply(newRotation, - this.rotationAtGrab); - break; - } - Entities.editEntity(this.entityID, { - position: newPosition, - rotation: newRotation - }); - this.oldModelRotation = newRotation; - this.oldModelPosition = newPosition; - - var indicesToRemove = []; - for (var i = 0; i < this.jointsIntersectingFromStart.length; ++i) { - var distance = Vec3.distance(MyAvatar.getJointPosition(this.jointsIntersectingFromStart[i]), this.oldModelPosition); - if (distance >= this.oldModelHalfDiagonal) { - indicesToRemove.push(this.jointsIntersectingFromStart[i]); - } - - } - for (var i = 0; i < indicesToRemove.length; ++i) { - this.jointsIntersectingFromStart.splice(this.jointsIntersectingFromStart.indexOf(indicesToRemove[i], 1)); - } - } - } - - this.update = function () { - this.oldPalmPosition = this.palmPosition; - this.oldTipPosition = this.tipPosition; - this.palmPosition = Controller.getSpatialControlPosition(this.palm); - this.tipPosition = Controller.getSpatialControlPosition(this.tip); - - this.oldUp = this.up; - this.up = Vec3.normalize(Controller.getSpatialControlNormal(this.palm)); - - this.oldFront = this.front; - this.front = Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)); - - this.oldRight = this.right; - this.right = Vec3.normalize(Vec3.cross(this.front, this.up)); - - this.oldRotation = this.rotation; - this.rotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm)); - - this.triggerValue = Controller.getTriggerValue(this.trigger); - - var bumperValue = Controller.isButtonPressed(this.bumper); - if (bumperValue && !this.bumperValue) { - if (mode == 0) { - mode = 1; - Overlays.editOverlay(leftController.laser, { color: { red: 0, green: 0, blue: 255 } }); - Overlays.editOverlay(rightController.laser, { color: { red: 0, green: 0, blue: 255 } }); - } else { - mode = 0; - Overlays.editOverlay(leftController.laser, { color: { red: 255, green: 0, blue: 0 } }); - Overlays.editOverlay(rightController.laser, { color: { red: 255, green: 0, blue: 0 } }); - } - } - this.bumperValue = bumperValue; - - - this.checkTrigger(); - - this.moveLaser(); - - if (!this.pressed && this.grabbing) { - // release if trigger not pressed anymore. - this.release(); - } - - if (this.pressing) { - // Checking for attachments intersecting - var attachments = MyAvatar.getAttachmentData(); - var attachmentIndex = -1; - var attachmentX = LASER_LENGTH_FACTOR; - - var newModel; - var newProperties; - - for (var i = 0; i < attachments.length; ++i) { - var position = Vec3.sum(MyAvatar.getJointPosition(attachments[i].jointName), - Vec3.multiplyQbyV(MyAvatar.getJointCombinedRotation(attachments[i].jointName), attachments[i].translation)); - var scale = attachments[i].scale; - - var A = this.palmPosition; - var B = this.front; - var P = position; - - var x = Vec3.dot(Vec3.subtract(P, A), B); - var X = Vec3.sum(A, Vec3.multiply(B, x)); - var d = Vec3.length(Vec3.subtract(P, X)); - - if (d < scale / 2.0 && 0 < x && x < attachmentX) { - attachmentIndex = i; - attachmentX = d; - } - } - - if (attachmentIndex != -1) { - print("Detaching: " + attachments[attachmentIndex].modelURL); - MyAvatar.detachOne(attachments[attachmentIndex].modelURL, attachments[attachmentIndex].jointName); - - newProperties = { - type: "Model", - position: Vec3.sum(MyAvatar.getJointPosition(attachments[attachmentIndex].jointName), - Vec3.multiplyQbyV(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName), attachments[attachmentIndex].translation)), - rotation: Quat.multiply(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName), - attachments[attachmentIndex].rotation), - - // TODO: how do we know the correct dimensions for detachment??? - dimensions: { x: attachments[attachmentIndex].scale / 2.0, - y: attachments[attachmentIndex].scale / 2.0, - z: attachments[attachmentIndex].scale / 2.0 }, - - modelURL: attachments[attachmentIndex].modelURL - }; - - newModel = Entities.addEntity(newProperties); - - - } else { - // There is none so ... - // Checking model tree - Vec3.print("Looking at: ", this.palmPosition); - var pickRay = { origin: this.palmPosition, - direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)) }; - var foundIntersection = Entities.findRayIntersection(pickRay); - - if(!foundIntersection.accurate) { - print("No accurate intersection"); - return; - } - newModel = foundIntersection.entityID; - if (!newModel.isKnownID) { - var identify = Entities.identifyEntity(newModel); - if (!identify.isKnownID) { - print("Unknown ID " + identify.id + " (update loop " + newModel.id + ")"); - return; - } - newModel = identify; - } - newProperties = Entities.getEntityProperties(newModel); - } - print("foundEntity.modelURL=" + newProperties.modelURL); - if (isLocked(newProperties)) { - print("Model locked " + newProperties.id); - } else { - var check = this.checkEntity(newProperties); - if (!check.valid) { - return; - } - - this.grab(newModel, newProperties); - - this.x = check.x; - this.y = check.y; - this.z = check.z; - return; - } - } - } - - this.cleanup = function () { - Overlays.deleteOverlay(this.laser); - Overlays.deleteOverlay(this.ball); - Overlays.deleteOverlay(this.leftRight); - Overlays.deleteOverlay(this.topDown); - } -} - -var leftController = new controller(LEFT); -var rightController = new controller(RIGHT); - -function moveEntities() { - if (leftController.grabbing && rightController.grabbing && rightController.entityID.id == leftController.entityID.id) { - var newPosition = leftController.oldModelPosition; - var rotation = leftController.oldModelRotation; - var ratio = 1; - - - switch (mode) { - case 0: - var oldLeftPoint = Vec3.sum(leftController.oldPalmPosition, Vec3.multiply(leftController.oldFront, leftController.x)); - var oldRightPoint = Vec3.sum(rightController.oldPalmPosition, Vec3.multiply(rightController.oldFront, rightController.x)); - - var oldMiddle = Vec3.multiply(Vec3.sum(oldLeftPoint, oldRightPoint), 0.5); - var oldLength = Vec3.length(Vec3.subtract(oldLeftPoint, oldRightPoint)); - - - var leftPoint = Vec3.sum(leftController.palmPosition, Vec3.multiply(leftController.front, leftController.x)); - var rightPoint = Vec3.sum(rightController.palmPosition, Vec3.multiply(rightController.front, rightController.x)); - - var middle = Vec3.multiply(Vec3.sum(leftPoint, rightPoint), 0.5); - var length = Vec3.length(Vec3.subtract(leftPoint, rightPoint)); - - - ratio = length / oldLength; - newPosition = Vec3.sum(middle, - Vec3.multiply(Vec3.subtract(leftController.oldModelPosition, oldMiddle), ratio)); - break; - case 1: - var u = Vec3.normalize(Vec3.subtract(rightController.oldPalmPosition, leftController.oldPalmPosition)); - var v = Vec3.normalize(Vec3.subtract(rightController.palmPosition, leftController.palmPosition)); - - var cos_theta = Vec3.dot(u, v); - if (cos_theta > 1) { - cos_theta = 1; - } - var angle = Math.acos(cos_theta) / Math.PI * 180; - if (angle < 0.1) { - return; - - } - var w = Vec3.normalize(Vec3.cross(u, v)); - - rotation = Quat.multiply(Quat.angleAxis(angle, w), leftController.oldModelRotation); - - - leftController.positionAtGrab = leftController.palmPosition; - leftController.rotationAtGrab = leftController.rotation; - leftController.modelPositionAtGrab = leftController.oldModelPosition; - leftController.rotationAtGrab = rotation; - rightController.positionAtGrab = rightController.palmPosition; - rightController.rotationAtGrab = rightController.rotation; - rightController.modelPositionAtGrab = rightController.oldModelPosition; - rightController.rotationAtGrab = rotation; - break; - } - Entities.editEntity(leftController.entityID, { - position: newPosition, - rotation: rotation, - // TODO: how do we know the correct dimensions for detachment??? - //radius: leftController.oldModelHalfDiagonal * ratio - dimensions: { x: leftController.oldModelHalfDiagonal * ratio, - y: leftController.oldModelHalfDiagonal * ratio, - z: leftController.oldModelHalfDiagonal * ratio } - - - }); - leftController.oldModelPosition = newPosition; - leftController.oldModelRotation = rotation; - leftController.oldModelHalfDiagonal *= ratio; - - rightController.oldModelPosition = newPosition; - rightController.oldModelRotation = rotation; - rightController.oldModelHalfDiagonal *= ratio; - return; - } - leftController.moveEntity(); - rightController.moveEntity(); -} - -var hydraConnected = false; -function checkController(deltaTime) { - var numberOfButtons = Controller.getNumberOfButtons(); - var numberOfTriggers = Controller.getNumberOfTriggers(); - var numberOfSpatialControls = Controller.getNumberOfSpatialControls(); - var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers; - - if (!isActive) { - // So that we hide the lasers bellow and keep updating the overlays position - numberOfButtons = 0; - } - - // this is expected for hydras - if (numberOfButtons == 12 && numberOfTriggers == 2 && controllersPerTrigger == 2) { - if (!hydraConnected) { - hydraConnected = true; - } - - leftController.update(); - rightController.update(); - moveEntities(); - } else { - if (hydraConnected) { - hydraConnected = false; - - leftController.showLaser(false); - rightController.showLaser(false); - } - } - toolBar.move(); - progressDialog.move(); -} - -var entitySelected = false; -var selectedEntityID; -var selectedEntityProperties; -var mouseLastPosition; -var orientation; -var intersection; - - -var SCALE_FACTOR = 200.0; - -function rayPlaneIntersection(pickRay, point, normal) { - var d = -Vec3.dot(point, normal); - var t = -(Vec3.dot(pickRay.origin, normal) + d) / Vec3.dot(pickRay.direction, normal); - - return Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, t)); -} - -function Tooltip() { - this.x = 285; - this.y = 115; - this.width = 500; - this.height = 300; // 145; - this.margin = 5; - this.decimals = 3; - - this.textOverlay = Overlays.addOverlay("text", { - x: this.x, - y: this.y, - width: this.width, - height: this.height, - margin: this.margin, - text: "", - color: { red: 228, green: 228, blue: 228 }, - alpha: 0.8, - backgroundAlpha: 0.8, - visible: false - }); - this.show = function (doShow) { - Overlays.editOverlay(this.textOverlay, { visible: doShow }); - } - this.updateText = function(properties) { - var angles = Quat.safeEulerAngles(properties.rotation); - var text = "Entity Properties:\n" - text += "type: " + properties.type + "\n" - text += "X: " + properties.position.x.toFixed(this.decimals) + "\n" - text += "Y: " + properties.position.y.toFixed(this.decimals) + "\n" - text += "Z: " + properties.position.z.toFixed(this.decimals) + "\n" - text += "Pitch: " + angles.x.toFixed(this.decimals) + "\n" - text += "Yaw: " + angles.y.toFixed(this.decimals) + "\n" - text += "Roll: " + angles.z.toFixed(this.decimals) + "\n" - text += "Dimensions: " + properties.dimensions.x.toFixed(this.decimals) + ", " - + properties.dimensions.y.toFixed(this.decimals) + ", " - + properties.dimensions.z.toFixed(this.decimals) + "\n"; - - text += "Natural Dimensions: " + properties.naturalDimensions.x.toFixed(this.decimals) + ", " - + properties.naturalDimensions.y.toFixed(this.decimals) + ", " - + properties.naturalDimensions.z.toFixed(this.decimals) + "\n"; - - text += "ID: " + properties.id + "\n" - if (properties.type == "Model") { - text += "Model URL: " + properties.modelURL + "\n" - text += "Animation URL: " + properties.animationURL + "\n" - text += "Animation is playing: " + properties.animationIsPlaying + "\n" - if (properties.sittingPoints && properties.sittingPoints.length > 0) { - text += properties.sittingPoints.length + " Sitting points: " - for (var i = 0; i < properties.sittingPoints.length; ++i) { - text += properties.sittingPoints[i].name + " " - } - } else { - text += "No sitting points" + "\n" - } - } - if (properties.lifetime > -1) { - text += "Lifetime: " + properties.lifetime + "\n" - } - text += "Age: " + properties.ageAsText + "\n" - text += "Mass: " + properties.mass + "\n" - text += "Script: " + properties.script + "\n" - - - Overlays.editOverlay(this.textOverlay, { text: text }); - } - - this.cleanup = function () { - Overlays.deleteOverlay(this.textOverlay); - } -} -var tooltip = new Tooltip(); - -function mousePressEvent(event) { - if (event.isAlt) { - return; - } - - mouseLastPosition = { x: event.x, y: event.y }; - entitySelected = false; - var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); - - if (toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event)) { - // Event handled; do nothing. - return; - } else { - // If we aren't active and didn't click on an overlay: quit - if (!isActive) { - return; - } - - var pickRay = Camera.computePickRay(event.x, event.y); - Vec3.print("[Mouse] Looking at: ", pickRay.origin); - var foundIntersection = Entities.findRayIntersection(pickRay, true); // we want precision picking here - - if(!foundIntersection.accurate) { - return; - } - var foundEntity = foundIntersection.entityID; - - if (!foundEntity.isKnownID) { - var identify = Entities.identifyEntity(foundEntity); - if (!identify.isKnownID) { - print("Unknown ID " + identify.id + " (update loop " + foundEntity.id + ")"); - return; - } - foundEntity = identify; - } - - var properties = Entities.getEntityProperties(foundEntity); - if (isLocked(properties)) { - print("Model locked " + properties.id); - } else { - var halfDiagonal = Vec3.length(properties.dimensions) / 2.0; - - print("Checking properties: " + properties.id + " " + properties.isKnownID + " - Half Diagonal:" + halfDiagonal); - // P P - Model - // /| A - Palm - // / | d B - unit vector toward tip - // / | X - base of the perpendicular line - // A---X----->B d - distance fom axis - // x x - distance from A - // - // |X-A| = (P-A).B - // X == A + ((P-A).B)B - // d = |P-X| - - var A = pickRay.origin; - var B = Vec3.normalize(pickRay.direction); - var P = properties.position; - - var x = Vec3.dot(Vec3.subtract(P, A), B); - var X = Vec3.sum(A, Vec3.multiply(B, x)); - var d = Vec3.length(Vec3.subtract(P, X)); - var halfDiagonal = Vec3.length(properties.dimensions) / 2.0; - - var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14; - - var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) - && (allowSmallModels || angularSize > MIN_ANGULAR_SIZE); - - if (0 < x && sizeOK) { - entitySelected = true; - selectedEntityID = foundEntity; - selectedEntityProperties = properties; - orientation = MyAvatar.orientation; - intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation)); - } - } - } - if (entitySelected) { - selectedEntityProperties.oldDimensions = selectedEntityProperties.dimensions; - selectedEntityProperties.oldPosition = { - x: selectedEntityProperties.position.x, - y: selectedEntityProperties.position.y, - z: selectedEntityProperties.position.z, - }; - selectedEntityProperties.oldRotation = { - x: selectedEntityProperties.rotation.x, - y: selectedEntityProperties.rotation.y, - z: selectedEntityProperties.rotation.z, - w: selectedEntityProperties.rotation.w, - }; - selectedEntityProperties.glowLevel = 0.0; - - print("Clicked on " + selectedEntityID.id + " " + entitySelected); - tooltip.updateText(selectedEntityProperties); - tooltip.show(true); - } -} - -var glowedEntityID = { id: -1, isKnownID: false }; -var oldModifier = 0; -var modifier = 0; -var wasShifted = false; -function mouseMoveEvent(event) { - if (event.isAlt || !isActive) { - return; - } - - var pickRay = Camera.computePickRay(event.x, event.y); - if (!entitySelected) { - var entityIntersection = Entities.findRayIntersection(pickRay); - if (entityIntersection.accurate) { - if(glowedEntityID.isKnownID && glowedEntityID.id != entityIntersection.entityID.id) { - Entities.editEntity(glowedEntityID, { glowLevel: 0.0 }); - glowedEntityID.id = -1; - glowedEntityID.isKnownID = false; - } - - var halfDiagonal = Vec3.length(entityIntersection.properties.dimensions) / 2.0; - - var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), - entityIntersection.properties.position)) * 180 / 3.14; - - var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) - && (allowSmallModels || angularSize > MIN_ANGULAR_SIZE); - - if (entityIntersection.entityID.isKnownID && sizeOK) { - if (wantEntityGlow) { - Entities.editEntity(entityIntersection.entityID, { glowLevel: 0.25 }); - } - glowedEntityID = entityIntersection.entityID; - } - - } - return; - } - - if (event.isLeftButton) { - if (event.isRightButton) { - modifier = 1; // Scale - } else { - modifier = 2; // Translate - } - } else if (event.isRightButton) { - modifier = 3; // rotate - } else { - modifier = 0; - } - pickRay = Camera.computePickRay(event.x, event.y); - if (wasShifted != event.isShifted || modifier != oldModifier) { - selectedEntityProperties.oldDimensions = selectedEntityProperties.dimensions; - - selectedEntityProperties.oldPosition = { - x: selectedEntityProperties.position.x, - y: selectedEntityProperties.position.y, - z: selectedEntityProperties.position.z, - }; - selectedEntityProperties.oldRotation = { - x: selectedEntityProperties.rotation.x, - y: selectedEntityProperties.rotation.y, - z: selectedEntityProperties.rotation.z, - w: selectedEntityProperties.rotation.w, - }; - orientation = MyAvatar.orientation; - intersection = rayPlaneIntersection(pickRay, - selectedEntityProperties.oldPosition, - Quat.getFront(orientation)); - - mouseLastPosition = { x: event.x, y: event.y }; - wasShifted = event.isShifted; - oldModifier = modifier; - return; - } - - - switch (modifier) { - case 0: - return; - case 1: - // Let's Scale - selectedEntityProperties.dimensions = Vec3.multiply(selectedEntityProperties.dimensions, - (1.0 + (mouseLastPosition.y - event.y) / SCALE_FACTOR)); - - var halfDiagonal = Vec3.length(selectedEntityProperties.dimensions) / 2.0; - - if (halfDiagonal < 0.01) { - print("Scale too small ... bailling."); - return; - } - break; - - case 2: - // Let's translate - var newIntersection = rayPlaneIntersection(pickRay, - selectedEntityProperties.oldPosition, - Quat.getFront(orientation)); - var vector = Vec3.subtract(newIntersection, intersection) - if (event.isShifted) { - var i = Vec3.dot(vector, Quat.getRight(orientation)); - var j = Vec3.dot(vector, Quat.getUp(orientation)); - vector = Vec3.sum(Vec3.multiply(Quat.getRight(orientation), i), - Vec3.multiply(Quat.getFront(orientation), j)); - } - selectedEntityProperties.position = Vec3.sum(selectedEntityProperties.oldPosition, vector); - break; - case 3: - // Let's rotate - if (somethingChanged) { - selectedEntityProperties.oldRotation.x = selectedEntityProperties.rotation.x; - selectedEntityProperties.oldRotation.y = selectedEntityProperties.rotation.y; - selectedEntityProperties.oldRotation.z = selectedEntityProperties.rotation.z; - selectedEntityProperties.oldRotation.w = selectedEntityProperties.rotation.w; - mouseLastPosition.x = event.x; - mouseLastPosition.y = event.y; - somethingChanged = false; - } - - - var pixelPerDegrees = windowDimensions.y / (1 * 360); // the entire height of the window allow you to make 2 full rotations - - //compute delta in pixel - var cameraForward = Quat.getFront(Camera.getOrientation()); - var rotationAxis = (!zIsPressed && xIsPressed) ? { x: 1, y: 0, z: 0 } : - (!zIsPressed && !xIsPressed) ? { x: 0, y: 1, z: 0 } : - { x: 0, y: 0, z: 1 }; - rotationAxis = Vec3.multiplyQbyV(selectedEntityProperties.rotation, rotationAxis); - var orthogonalAxis = Vec3.cross(cameraForward, rotationAxis); - var mouseDelta = { x: event.x - mouseLastPosition - .x, y: mouseLastPosition.y - event.y, z: 0 }; - var transformedMouseDelta = Vec3.multiplyQbyV(Camera.getOrientation(), mouseDelta); - var delta = Math.floor(Vec3.dot(transformedMouseDelta, Vec3.normalize(orthogonalAxis)) / pixelPerDegrees); - - var STEP = 15; - if (!event.isShifted) { - delta = Math.round(delta / STEP) * STEP; - } - - var rotation = Quat.fromVec3Degrees({ - x: (!zIsPressed && xIsPressed) ? delta : 0, // x is pressed - y: (!zIsPressed && !xIsPressed) ? delta : 0, // neither is pressed - z: (zIsPressed && !xIsPressed) ? delta : 0 // z is pressed - }); - rotation = Quat.multiply(selectedEntityProperties.oldRotation, rotation); - - selectedEntityProperties.rotation.x = rotation.x; - selectedEntityProperties.rotation.y = rotation.y; - selectedEntityProperties.rotation.z = rotation.z; - selectedEntityProperties.rotation.w = rotation.w; - break; - } - - Entities.editEntity(selectedEntityID, selectedEntityProperties); - tooltip.updateText(selectedEntityProperties); -} - - -function mouseReleaseEvent(event) { - if (event.isAlt || !isActive) { - return; - } - if (entitySelected) { - tooltip.show(false); - } - - entitySelected = false; - - glowedEntityID.id = -1; - glowedEntityID.isKnownID = false; -} - -// In order for editVoxels and editModels to play nice together, they each check to see if a "delete" menu item already -// exists. If it doesn't they add it. If it does they don't. They also only delete the menu item if they were the one that -// added it. -var modelMenuAddedDelete = false; -var originalLightsArePickable = Entities.getLightsArePickable(); -function setupModelMenus() { - print("setupModelMenus()"); - // adj our menuitems - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Models", isSeparator: true, beforeItem: "Physics" }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Edit Properties...", - shortcutKeyEvent: { text: "`" }, afterItem: "Models" }); - if (!Menu.menuItemExists("Edit", "Delete")) { - print("no delete... adding ours"); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete", - shortcutKeyEvent: { text: "backspace" }, afterItem: "Models" }); - modelMenuAddedDelete = true; - } else { - print("delete exists... don't add ours"); - } - - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Model List...", afterItem: "Models" }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Edit Properties..." }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Large Models", shortcutKey: "CTRL+META+L", - afterItem: "Paste Models", isCheckable: true }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Small Models", shortcutKey: "CTRL+META+S", - afterItem: "Allow Selecting of Large Models", isCheckable: true }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Lights", shortcutKey: "CTRL+SHIFT+META+L", - afterItem: "Allow Selecting of Small Models", isCheckable: true }); - - Menu.addMenuItem({ menuName: "File", menuItemName: "Models", isSeparator: true, beforeItem: "Settings" }); - Menu.addMenuItem({ menuName: "File", menuItemName: "Export Models", shortcutKey: "CTRL+META+E", afterItem: "Models" }); - Menu.addMenuItem({ menuName: "File", menuItemName: "Import Models", shortcutKey: "CTRL+META+I", afterItem: "Export Models" }); - - Entities.setLightsArePickable(false); - -} - -function cleanupModelMenus() { - Menu.removeSeparator("Edit", "Models"); - Menu.removeMenuItem("Edit", "Edit Properties..."); - if (modelMenuAddedDelete) { - // delete our menuitems - Menu.removeMenuItem("Edit", "Delete"); - } - - Menu.removeMenuItem("Edit", "Model List..."); - Menu.removeMenuItem("Edit", "Paste Models"); - Menu.removeMenuItem("Edit", "Allow Selecting of Large Models"); - Menu.removeMenuItem("Edit", "Allow Selecting of Small Models"); - Menu.removeMenuItem("Edit", "Allow Selecting of Lights"); - - Menu.removeSeparator("File", "Models"); - Menu.removeMenuItem("File", "Export Models"); - Menu.removeMenuItem("File", "Import Models"); -} - -function scriptEnding() { - leftController.cleanup(); - rightController.cleanup(); - progressDialog.cleanup(); - toolBar.cleanup(); - cleanupModelMenus(); - tooltip.cleanup(); - modelImporter.cleanup(); - if (exportMenu) { - exportMenu.close(); - } - Entities.setLightsArePickable(originalLightsArePickable); -} -Script.scriptEnding.connect(scriptEnding); - -// register the call back so it fires before each data send -Script.update.connect(checkController); -Controller.mousePressEvent.connect(mousePressEvent); -Controller.mouseMoveEvent.connect(mouseMoveEvent); -Controller.mouseReleaseEvent.connect(mouseReleaseEvent); - -setupModelMenus(); - -var propertiesForEditedEntity; -var editEntityFormArray; -var editModelID = -1; -var dimensionX; -var dimensionY; -var dimensionZ; -var rescalePercentage; - -function showPropertiesForm(editModelID) { - entityPropertyDialogBox.openDialog(editModelID); -} - -function handeMenuEvent(menuItem) { - print("menuItemEvent() in JS... menuItem=" + menuItem); - if (menuItem == "Allow Selecting of Small Models") { - allowSmallModels = Menu.isOptionChecked("Allow Selecting of Small Models"); - } else if (menuItem == "Allow Selecting of Large Models") { - allowLargeModels = Menu.isOptionChecked("Allow Selecting of Large Models"); - } else if (menuItem == "Allow Selecting of Lights") { - Entities.setLightsArePickable(Menu.isOptionChecked("Allow Selecting of Lights")); - } else if (menuItem == "Delete") { - if (leftController.grabbing) { - print(" Delete Entity.... leftController.entityID="+ leftController.entityID); - Entities.deleteEntity(leftController.entityID); - leftController.grabbing = false; - if (glowedEntityID.id == leftController.entityID.id) { - glowedEntityID = { id: -1, isKnownID: false }; - } - } else if (rightController.grabbing) { - print(" Delete Entity.... rightController.entityID="+ rightController.entityID); - Entities.deleteEntity(rightController.entityID); - rightController.grabbing = false; - if (glowedEntityID.id == rightController.entityID.id) { - glowedEntityID = { id: -1, isKnownID: false }; - } - } else if (entitySelected) { - print(" Delete Entity.... selectedEntityID="+ selectedEntityID); - Entities.deleteEntity(selectedEntityID); - entitySelected = false; - if (glowedEntityID.id == selectedEntityID.id) { - glowedEntityID = { id: -1, isKnownID: false }; - } - } else { - print(" Delete Entity.... not holding..."); - } - } else if (menuItem == "Model List...") { - var models = new Array(); - models = Entities.findEntities(MyAvatar.position, Number.MAX_VALUE); - for (var i = 0; i < models.length; i++) { - models[i].properties = Entities.getEntityProperties(models[i]); - models[i].toString = function() { - var modelname; - if (this.properties.type == "Model") { - modelname = decodeURIComponent( - this.properties.modelURL.indexOf("/") != -1 ? - this.properties.modelURL.substring(this.properties.modelURL.lastIndexOf("/") + 1) : - this.properties.modelURL); - } else { - modelname = this.properties.id; - } - return "[" + this.properties.type + "] " + modelname; - }; - } - var form = [{label: "Model: ", options: models}]; - form.push({label: "Action: ", options: ["Properties", "Delete", "Teleport"]}); - form.push({ button: "Cancel" }); - if (Window.form("Model List", form)) { - var selectedModel = form[0].value; - if (form[1].value == "Properties") { - editModelID = selectedModel; - showPropertiesForm(editModelID); - } else if (form[1].value == "Delete") { - Entities.deleteEntity(selectedModel); - } else if (form[1].value == "Teleport") { - MyAvatar.position = selectedModel.properties.position; - } - } - } else if (menuItem == "Edit Properties...") { - editModelID = -1; - if (leftController.grabbing) { - print(" Edit Properties.... leftController.entityID="+ leftController.entityID); - editModelID = leftController.entityID; - } else if (rightController.grabbing) { - print(" Edit Properties.... rightController.entityID="+ rightController.entityID); - editModelID = rightController.entityID; - } else if (entitySelected) { - print(" Edit Properties.... selectedEntityID="+ selectedEntityID); - editModelID = selectedEntityID; - } else { - print(" Edit Properties.... not holding..."); - } - if (editModelID != -1) { - print(" Edit Properties.... about to edit properties..."); - showPropertiesForm(editModelID); - } - } else if (menuItem == "Paste Models") { - modelImporter.paste(); - } else if (menuItem == "Export Models") { - if (!exportMenu) { - exportMenu = new ExportMenu({ - onClose: function () { - exportMenu = null; - } - }); - } - } else if (menuItem == "Import Models") { - modelImporter.doImport(); - } - tooltip.show(false); -} -Menu.menuItemEvent.connect(handeMenuEvent); - - - -// handling of inspect.js concurrence -var zIsPressed = false; -var xIsPressed = false; -var somethingChanged = false; -Controller.keyPressEvent.connect(function (event) { - if ((event.text == "z" || event.text == "Z") && !zIsPressed) { - zIsPressed = true; - somethingChanged = true; - } - if ((event.text == "x" || event.text == "X") && !xIsPressed) { - xIsPressed = true; - somethingChanged = true; - } - - // resets model orientation when holding with mouse - if (event.text == "r" && entitySelected) { - selectedEntityProperties.rotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 0 }); - Entities.editEntity(selectedEntityID, selectedEntityProperties); - tooltip.updateText(selectedEntityProperties); - somethingChanged = true; - } -}); - -Controller.keyReleaseEvent.connect(function (event) { - if (event.text == "z" || event.text == "Z") { - zIsPressed = false; - somethingChanged = true; - } - if (event.text == "x" || event.text == "X") { - xIsPressed = false; - somethingChanged = true; - } - // since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items - if (event.text == "`") { - handeMenuEvent("Edit Properties..."); - } - if (event.text == "BACKSPACE") { - handeMenuEvent("Delete"); - } -}); - diff --git a/examples/hydraGrab.js b/examples/hydraGrab.js new file mode 100644 index 0000000000..4d0b873fd2 --- /dev/null +++ b/examples/hydraGrab.js @@ -0,0 +1,742 @@ +// +// hydraGrab.js +// examples +// +// Created by Clément Brisset on 4/24/14. +// Copyright 2014 High Fidelity, Inc. +// +// This script allows you to edit models either with the razor hydras or with your mouse +// +// Using the hydras : +// grab models with the triggers, you can then move the models around or scale them with both hands. +// You can switch mode using the bumpers so that you can move models around more easily. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +Script.include("libraries/entityPropertyDialogBox.js"); +var entityPropertyDialogBox = EntityPropertyDialogBox; + +var LASER_WIDTH = 4; +var LASER_COLOR = { red: 255, green: 0, blue: 0 }; +var LASER_LENGTH_FACTOR = 500; + +var MIN_ANGULAR_SIZE = 2; +var MAX_ANGULAR_SIZE = 45; +var allowLargeModels = false; +var allowSmallModels = false; +var wantEntityGlow = false; + +var LEFT = 0; +var RIGHT = 1; + +var jointList = MyAvatar.getJointNames(); + +var mode = 0; + +function controller(wichSide) { + this.side = wichSide; + this.palm = 2 * wichSide; + this.tip = 2 * wichSide + 1; + this.trigger = wichSide; + this.bumper = 6 * wichSide + 5; + + this.oldPalmPosition = Controller.getSpatialControlPosition(this.palm); + this.palmPosition = Controller.getSpatialControlPosition(this.palm); + + this.oldTipPosition = Controller.getSpatialControlPosition(this.tip); + this.tipPosition = Controller.getSpatialControlPosition(this.tip); + + this.oldUp = Controller.getSpatialControlNormal(this.palm); + this.up = this.oldUp; + + this.oldFront = Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)); + this.front = this.oldFront; + + this.oldRight = Vec3.cross(this.front, this.up); + this.right = this.oldRight; + + this.oldRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm)); + this.rotation = this.oldRotation; + + this.triggerValue = Controller.getTriggerValue(this.trigger); + this.bumperValue = Controller.isButtonPressed(this.bumper); + + this.pressed = false; // is trigger pressed + this.pressing = false; // is trigger being pressed (is pressed now but wasn't previously) + + this.grabbing = false; + this.entityID = { isKnownID: false }; + this.modelURL = ""; + this.oldModelRotation; + this.oldModelPosition; + this.oldModelHalfDiagonal; + + this.positionAtGrab; + this.rotationAtGrab; + this.modelPositionAtGrab; + this.rotationAtGrab; + this.jointsIntersectingFromStart = []; + + this.laser = Overlays.addOverlay("line3d", { + start: { x: 0, y: 0, z: 0 }, + end: { x: 0, y: 0, z: 0 }, + color: LASER_COLOR, + alpha: 1, + visible: false, + lineWidth: LASER_WIDTH, + anchor: "MyAvatar" + }); + + this.guideScale = 0.02; + this.ball = Overlays.addOverlay("sphere", { + position: { x: 0, y: 0, z: 0 }, + size: this.guideScale, + solid: true, + color: { red: 0, green: 255, blue: 0 }, + alpha: 1, + visible: false, + anchor: "MyAvatar" + }); + this.leftRight = Overlays.addOverlay("line3d", { + start: { x: 0, y: 0, z: 0 }, + end: { x: 0, y: 0, z: 0 }, + color: { red: 0, green: 0, blue: 255 }, + alpha: 1, + visible: false, + lineWidth: LASER_WIDTH, + anchor: "MyAvatar" + }); + this.topDown = Overlays.addOverlay("line3d", { + start: { x: 0, y: 0, z: 0 }, + end: { x: 0, y: 0, z: 0 }, + color: { red: 0, green: 0, blue: 255 }, + alpha: 1, + visible: false, + lineWidth: LASER_WIDTH, + anchor: "MyAvatar" + }); + + + + this.grab = function (entityID, properties) { + print("Grabbing " + entityID.id); + this.grabbing = true; + this.entityID = entityID; + this.modelURL = properties.modelURL; + + this.oldModelPosition = properties.position; + this.oldModelRotation = properties.rotation; + this.oldModelHalfDiagonal = Vec3.length(properties.dimensions) / 2.0; + + this.positionAtGrab = this.palmPosition; + this.rotationAtGrab = this.rotation; + this.modelPositionAtGrab = properties.position; + this.rotationAtGrab = properties.rotation; + this.jointsIntersectingFromStart = []; + for (var i = 0; i < jointList.length; i++) { + var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition); + if (distance < this.oldModelHalfDiagonal) { + this.jointsIntersectingFromStart.push(i); + } + } + this.showLaser(false); + } + + this.release = function () { + if (this.grabbing) { + jointList = MyAvatar.getJointNames(); + + var closestJointIndex = -1; + var closestJointDistance = 10; + for (var i = 0; i < jointList.length; i++) { + var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition); + if (distance < closestJointDistance) { + closestJointDistance = distance; + closestJointIndex = i; + } + } + + if (closestJointIndex != -1) { + print("closestJoint: " + jointList[closestJointIndex]); + print("closestJointDistance (attach max distance): " + closestJointDistance + " (" + this.oldModelHalfDiagonal + ")"); + } + + if (closestJointDistance < this.oldModelHalfDiagonal) { + + if (this.jointsIntersectingFromStart.indexOf(closestJointIndex) != -1 || + (leftController.grabbing && rightController.grabbing && + leftController.entityID.id == rightController.entityID.id)) { + // Do nothing + } else { + print("Attaching to " + jointList[closestJointIndex]); + var jointPosition = MyAvatar.getJointPosition(jointList[closestJointIndex]); + var jointRotation = MyAvatar.getJointCombinedRotation(jointList[closestJointIndex]); + + var attachmentOffset = Vec3.subtract(this.oldModelPosition, jointPosition); + attachmentOffset = Vec3.multiplyQbyV(Quat.inverse(jointRotation), attachmentOffset); + var attachmentRotation = Quat.multiply(Quat.inverse(jointRotation), this.oldModelRotation); + + MyAvatar.attach(this.modelURL, jointList[closestJointIndex], + attachmentOffset, attachmentRotation, 2.0 * this.oldModelHalfDiagonal, + true, false); + Entities.deleteEntity(this.entityID); + } + } + } + + this.grabbing = false; + this.entityID.isKnownID = false; + this.jointsIntersectingFromStart = []; + this.showLaser(true); + } + + this.checkTrigger = function () { + if (this.triggerValue > 0.9) { + if (this.pressed) { + this.pressing = false; + } else { + this.pressing = true; + } + this.pressed = true; + } else { + this.pressing = false; + this.pressed = false; + } + } + + this.checkEntity = function (properties) { + // P P - Model + // /| A - Palm + // / | d B - unit vector toward tip + // / | X - base of the perpendicular line + // A---X----->B d - distance fom axis + // x x - distance from A + // + // |X-A| = (P-A).B + // X == A + ((P-A).B)B + // d = |P-X| + + var A = this.palmPosition; + var B = this.front; + var P = properties.position; + + var x = Vec3.dot(Vec3.subtract(P, A), B); + var y = Vec3.dot(Vec3.subtract(P, A), this.up); + var z = Vec3.dot(Vec3.subtract(P, A), this.right); + var X = Vec3.sum(A, Vec3.multiply(B, x)); + var d = Vec3.length(Vec3.subtract(P, X)); + var halfDiagonal = Vec3.length(properties.dimensions) / 2.0; + + var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14; + + var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) + && (allowSmallModels || angularSize > MIN_ANGULAR_SIZE); + + if (0 < x && sizeOK) { + return { valid: true, x: x, y: y, z: z }; + } + return { valid: false }; + } + + this.glowedIntersectingModel = { isKnownID: false }; + this.moveLaser = function () { + // the overlays here are anchored to the avatar, which means they are specified in the avatar's local frame + + var inverseRotation = Quat.inverse(MyAvatar.orientation); + var startPosition = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.palmPosition, MyAvatar.position)); + var direction = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.tipPosition, this.palmPosition)); + var distance = Vec3.length(direction); + direction = Vec3.multiply(direction, LASER_LENGTH_FACTOR / distance); + var endPosition = Vec3.sum(startPosition, direction); + + Overlays.editOverlay(this.laser, { + start: startPosition, + end: endPosition + }); + + + Overlays.editOverlay(this.ball, { + position: endPosition + }); + Overlays.editOverlay(this.leftRight, { + start: Vec3.sum(endPosition, Vec3.multiply(this.right, 2 * this.guideScale)), + end: Vec3.sum(endPosition, Vec3.multiply(this.right, -2 * this.guideScale)) + }); + Overlays.editOverlay(this.topDown, { + start: Vec3.sum(endPosition, Vec3.multiply(this.up, 2 * this.guideScale)), + end: Vec3.sum(endPosition, Vec3.multiply(this.up, -2 * this.guideScale)) + }); + this.showLaser(!this.grabbing || mode == 0); + + if (this.glowedIntersectingModel.isKnownID) { + Entities.editEntity(this.glowedIntersectingModel, { glowLevel: 0.0 }); + this.glowedIntersectingModel.isKnownID = false; + } + if (!this.grabbing) { + var intersection = Entities.findRayIntersection({ + origin: this.palmPosition, + direction: this.front + }); + + var halfDiagonal = Vec3.length(intersection.properties.dimensions) / 2.0; + + var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), intersection.properties.position)) * 180 / 3.14; + var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) + && (allowSmallModels || angularSize > MIN_ANGULAR_SIZE); + if (intersection.accurate && intersection.entityID.isKnownID && sizeOK) { + this.glowedIntersectingModel = intersection.entityID; + + if (wantEntityGlow) { + Entities.editEntity(this.glowedIntersectingModel, { glowLevel: 0.25 }); + } + } + } + } + + this.showLaser = function (show) { + Overlays.editOverlay(this.laser, { visible: show }); + Overlays.editOverlay(this.ball, { visible: show }); + Overlays.editOverlay(this.leftRight, { visible: show }); + Overlays.editOverlay(this.topDown, { visible: show }); + } + this.moveEntity = function () { + if (this.grabbing) { + if (!this.entityID.isKnownID) { + print("Unknown grabbed ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID); + this.entityID = Entities.findRayIntersection({ + origin: this.palmPosition, + direction: this.front + }).entityID; + print("Identified ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID); + } + var newPosition; + var newRotation; + + switch (mode) { + case 0: + newPosition = Vec3.sum(this.palmPosition, + Vec3.multiply(this.front, this.x)); + newPosition = Vec3.sum(newPosition, + Vec3.multiply(this.up, this.y)); + newPosition = Vec3.sum(newPosition, + Vec3.multiply(this.right, this.z)); + + + newRotation = Quat.multiply(this.rotation, + Quat.inverse(this.oldRotation)); + newRotation = Quat.multiply(newRotation, + this.oldModelRotation); + break; + case 1: + var forward = Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -1 }); + var d = Vec3.dot(forward, MyAvatar.position); + + var factor1 = Vec3.dot(forward, this.positionAtGrab) - d; + var factor2 = Vec3.dot(forward, this.modelPositionAtGrab) - d; + var vector = Vec3.subtract(this.palmPosition, this.positionAtGrab); + + if (factor2 < 0) { + factor2 = 0; + } + if (factor1 <= 0) { + factor1 = 1; + factor2 = 1; + } + + newPosition = Vec3.sum(this.modelPositionAtGrab, + Vec3.multiply(vector, + factor2 / factor1)); + + newRotation = Quat.multiply(this.rotation, + Quat.inverse(this.rotationAtGrab)); + newRotation = Quat.multiply(newRotation, + this.rotationAtGrab); + break; + } + Entities.editEntity(this.entityID, { + position: newPosition, + rotation: newRotation + }); + this.oldModelRotation = newRotation; + this.oldModelPosition = newPosition; + + var indicesToRemove = []; + for (var i = 0; i < this.jointsIntersectingFromStart.length; ++i) { + var distance = Vec3.distance(MyAvatar.getJointPosition(this.jointsIntersectingFromStart[i]), this.oldModelPosition); + if (distance >= this.oldModelHalfDiagonal) { + indicesToRemove.push(this.jointsIntersectingFromStart[i]); + } + + } + for (var i = 0; i < indicesToRemove.length; ++i) { + this.jointsIntersectingFromStart.splice(this.jointsIntersectingFromStart.indexOf(indicesToRemove[i], 1)); + } + } + } + + this.update = function () { + this.oldPalmPosition = this.palmPosition; + this.oldTipPosition = this.tipPosition; + this.palmPosition = Controller.getSpatialControlPosition(this.palm); + this.tipPosition = Controller.getSpatialControlPosition(this.tip); + + this.oldUp = this.up; + this.up = Vec3.normalize(Controller.getSpatialControlNormal(this.palm)); + + this.oldFront = this.front; + this.front = Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)); + + this.oldRight = this.right; + this.right = Vec3.normalize(Vec3.cross(this.front, this.up)); + + this.oldRotation = this.rotation; + this.rotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm)); + + this.triggerValue = Controller.getTriggerValue(this.trigger); + + var bumperValue = Controller.isButtonPressed(this.bumper); + if (bumperValue && !this.bumperValue) { + if (mode == 0) { + mode = 1; + Overlays.editOverlay(leftController.laser, { color: { red: 0, green: 0, blue: 255 } }); + Overlays.editOverlay(rightController.laser, { color: { red: 0, green: 0, blue: 255 } }); + } else { + mode = 0; + Overlays.editOverlay(leftController.laser, { color: { red: 255, green: 0, blue: 0 } }); + Overlays.editOverlay(rightController.laser, { color: { red: 255, green: 0, blue: 0 } }); + } + } + this.bumperValue = bumperValue; + + + this.checkTrigger(); + + this.moveLaser(); + + if (!this.pressed && this.grabbing) { + // release if trigger not pressed anymore. + this.release(); + } + + if (this.pressing) { + // Checking for attachments intersecting + var attachments = MyAvatar.getAttachmentData(); + var attachmentIndex = -1; + var attachmentX = LASER_LENGTH_FACTOR; + + var newModel; + var newProperties; + + for (var i = 0; i < attachments.length; ++i) { + var position = Vec3.sum(MyAvatar.getJointPosition(attachments[i].jointName), + Vec3.multiplyQbyV(MyAvatar.getJointCombinedRotation(attachments[i].jointName), attachments[i].translation)); + var scale = attachments[i].scale; + + var A = this.palmPosition; + var B = this.front; + var P = position; + + var x = Vec3.dot(Vec3.subtract(P, A), B); + var X = Vec3.sum(A, Vec3.multiply(B, x)); + var d = Vec3.length(Vec3.subtract(P, X)); + + if (d < scale / 2.0 && 0 < x && x < attachmentX) { + attachmentIndex = i; + attachmentX = d; + } + } + + if (attachmentIndex != -1) { + print("Detaching: " + attachments[attachmentIndex].modelURL); + MyAvatar.detachOne(attachments[attachmentIndex].modelURL, attachments[attachmentIndex].jointName); + + newProperties = { + type: "Model", + position: Vec3.sum(MyAvatar.getJointPosition(attachments[attachmentIndex].jointName), + Vec3.multiplyQbyV(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName), attachments[attachmentIndex].translation)), + rotation: Quat.multiply(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName), + attachments[attachmentIndex].rotation), + + // TODO: how do we know the correct dimensions for detachment??? + dimensions: { x: attachments[attachmentIndex].scale / 2.0, + y: attachments[attachmentIndex].scale / 2.0, + z: attachments[attachmentIndex].scale / 2.0 }, + + modelURL: attachments[attachmentIndex].modelURL + }; + + newModel = Entities.addEntity(newProperties); + + + } else { + // There is none so ... + // Checking model tree + Vec3.print("Looking at: ", this.palmPosition); + var pickRay = { origin: this.palmPosition, + direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)) }; + var foundIntersection = Entities.findRayIntersection(pickRay); + + if(!foundIntersection.accurate) { + print("No accurate intersection"); + return; + } + newModel = foundIntersection.entityID; + if (!newModel.isKnownID) { + var identify = Entities.identifyEntity(newModel); + if (!identify.isKnownID) { + print("Unknown ID " + identify.id + " (update loop " + newModel.id + ")"); + return; + } + newModel = identify; + } + newProperties = Entities.getEntityProperties(newModel); + } + print("foundEntity.modelURL=" + newProperties.modelURL); + var check = this.checkEntity(newProperties); + if (!check.valid) { + return; + } + + this.grab(newModel, newProperties); + + this.x = check.x; + this.y = check.y; + this.z = check.z; + return; + } + } + + this.cleanup = function () { + Overlays.deleteOverlay(this.laser); + Overlays.deleteOverlay(this.ball); + Overlays.deleteOverlay(this.leftRight); + Overlays.deleteOverlay(this.topDown); + } +} + +var leftController = new controller(LEFT); +var rightController = new controller(RIGHT); + +function moveEntities() { + if (leftController.grabbing && rightController.grabbing && rightController.entityID.id == leftController.entityID.id) { + var newPosition = leftController.oldModelPosition; + var rotation = leftController.oldModelRotation; + var ratio = 1; + + + switch (mode) { + case 0: + var oldLeftPoint = Vec3.sum(leftController.oldPalmPosition, Vec3.multiply(leftController.oldFront, leftController.x)); + var oldRightPoint = Vec3.sum(rightController.oldPalmPosition, Vec3.multiply(rightController.oldFront, rightController.x)); + + var oldMiddle = Vec3.multiply(Vec3.sum(oldLeftPoint, oldRightPoint), 0.5); + var oldLength = Vec3.length(Vec3.subtract(oldLeftPoint, oldRightPoint)); + + + var leftPoint = Vec3.sum(leftController.palmPosition, Vec3.multiply(leftController.front, leftController.x)); + var rightPoint = Vec3.sum(rightController.palmPosition, Vec3.multiply(rightController.front, rightController.x)); + + var middle = Vec3.multiply(Vec3.sum(leftPoint, rightPoint), 0.5); + var length = Vec3.length(Vec3.subtract(leftPoint, rightPoint)); + + + ratio = length / oldLength; + newPosition = Vec3.sum(middle, + Vec3.multiply(Vec3.subtract(leftController.oldModelPosition, oldMiddle), ratio)); + break; + case 1: + var u = Vec3.normalize(Vec3.subtract(rightController.oldPalmPosition, leftController.oldPalmPosition)); + var v = Vec3.normalize(Vec3.subtract(rightController.palmPosition, leftController.palmPosition)); + + var cos_theta = Vec3.dot(u, v); + if (cos_theta > 1) { + cos_theta = 1; + } + var angle = Math.acos(cos_theta) / Math.PI * 180; + if (angle < 0.1) { + return; + + } + var w = Vec3.normalize(Vec3.cross(u, v)); + + rotation = Quat.multiply(Quat.angleAxis(angle, w), leftController.oldModelRotation); + + + leftController.positionAtGrab = leftController.palmPosition; + leftController.rotationAtGrab = leftController.rotation; + leftController.modelPositionAtGrab = leftController.oldModelPosition; + leftController.rotationAtGrab = rotation; + rightController.positionAtGrab = rightController.palmPosition; + rightController.rotationAtGrab = rightController.rotation; + rightController.modelPositionAtGrab = rightController.oldModelPosition; + rightController.rotationAtGrab = rotation; + break; + } + Entities.editEntity(leftController.entityID, { + position: newPosition, + rotation: rotation, + // TODO: how do we know the correct dimensions for detachment??? + //radius: leftController.oldModelHalfDiagonal * ratio + dimensions: { x: leftController.oldModelHalfDiagonal * ratio, + y: leftController.oldModelHalfDiagonal * ratio, + z: leftController.oldModelHalfDiagonal * ratio } + + + }); + leftController.oldModelPosition = newPosition; + leftController.oldModelRotation = rotation; + leftController.oldModelHalfDiagonal *= ratio; + + rightController.oldModelPosition = newPosition; + rightController.oldModelRotation = rotation; + rightController.oldModelHalfDiagonal *= ratio; + return; + } + leftController.moveEntity(); + rightController.moveEntity(); +} + +var hydraConnected = false; +function checkController(deltaTime) { + var numberOfButtons = Controller.getNumberOfButtons(); + var numberOfTriggers = Controller.getNumberOfTriggers(); + var numberOfSpatialControls = Controller.getNumberOfSpatialControls(); + var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers; + + // this is expected for hydras + if (numberOfButtons == 12 && numberOfTriggers == 2 && controllersPerTrigger == 2) { + if (!hydraConnected) { + hydraConnected = true; + } + + leftController.update(); + rightController.update(); + moveEntities(); + } else { + if (hydraConnected) { + hydraConnected = false; + + leftController.showLaser(false); + rightController.showLaser(false); + } + } +} + +var glowedEntityID = { id: -1, isKnownID: false }; + +// In order for editVoxels and editModels to play nice together, they each check to see if a "delete" menu item already +// exists. If it doesn't they add it. If it does they don't. They also only delete the menu item if they were the one that +// added it. +var modelMenuAddedDelete = false; +var originalLightsArePickable = Entities.getLightsArePickable(); +function setupModelMenus() { + print("setupModelMenus()"); + // adj our menuitems + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Models", isSeparator: true, beforeItem: "Physics" }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Edit Properties...", + shortcutKeyEvent: { text: "`" }, afterItem: "Models" }); + if (!Menu.menuItemExists("Edit", "Delete")) { + print("no delete... adding ours"); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete", + shortcutKeyEvent: { text: "backspace" }, afterItem: "Models" }); + modelMenuAddedDelete = true; + } else { + print("delete exists... don't add ours"); + } + + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Large Models", shortcutKey: "CTRL+META+L", + afterItem: "Paste Models", isCheckable: true }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Small Models", shortcutKey: "CTRL+META+S", + afterItem: "Allow Selecting of Large Models", isCheckable: true }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Lights", shortcutKey: "CTRL+SHIFT+META+L", + afterItem: "Allow Selecting of Small Models", isCheckable: true }); + + Entities.setLightsArePickable(false); +} + +function cleanupModelMenus() { + Menu.removeMenuItem("Edit", "Edit Properties..."); + if (modelMenuAddedDelete) { + // delete our menuitems + Menu.removeMenuItem("Edit", "Delete"); + } + + Menu.removeMenuItem("Edit", "Allow Selecting of Large Models"); + Menu.removeMenuItem("Edit", "Allow Selecting of Small Models"); + Menu.removeMenuItem("Edit", "Allow Selecting of Lights"); + +} + +function scriptEnding() { + leftController.cleanup(); + rightController.cleanup(); + cleanupModelMenus(); + Entities.setLightsArePickable(originalLightsArePickable); +} +Script.scriptEnding.connect(scriptEnding); + +// register the call back so it fires before each data send +Script.update.connect(checkController); + +setupModelMenus(); + +var editModelID = -1; +function showPropertiesForm(editModelID) { + entityPropertyDialogBox.openDialog(editModelID); +} + +Menu.menuItemEvent.connect(function (menuItem) { + print("menuItemEvent() in JS... menuItem=" + menuItem); + if (menuItem == "Allow Selecting of Small Models") { + allowSmallModels = Menu.isOptionChecked("Allow Selecting of Small Models"); + } else if (menuItem == "Allow Selecting of Large Models") { + allowLargeModels = Menu.isOptionChecked("Allow Selecting of Large Models"); + } else if (menuItem == "Allow Selecting of Lights") { + Entities.setLightsArePickable(Menu.isOptionChecked("Allow Selecting of Lights")); + } else if (menuItem == "Delete") { + if (leftController.grabbing) { + print(" Delete Entity.... leftController.entityID="+ leftController.entityID); + Entities.deleteEntity(leftController.entityID); + leftController.grabbing = false; + if (glowedEntityID.id == leftController.entityID.id) { + glowedEntityID = { id: -1, isKnownID: false }; + } + } else if (rightController.grabbing) { + print(" Delete Entity.... rightController.entityID="+ rightController.entityID); + Entities.deleteEntity(rightController.entityID); + rightController.grabbing = false; + if (glowedEntityID.id == rightController.entityID.id) { + glowedEntityID = { id: -1, isKnownID: false }; + } + } else { + print(" Delete Entity.... not holding..."); + } + } else if (menuItem == "Edit Properties...") { + editModelID = -1; + if (leftController.grabbing) { + print(" Edit Properties.... leftController.entityID="+ leftController.entityID); + editModelID = leftController.entityID; + } else if (rightController.grabbing) { + print(" Edit Properties.... rightController.entityID="+ rightController.entityID); + editModelID = rightController.entityID; + } else { + print(" Edit Properties.... not holding..."); + } + if (editModelID != -1) { + print(" Edit Properties.... about to edit properties..."); + showPropertiesForm(editModelID); + } + } +}); + +Controller.keyReleaseEvent.connect(function (event) { + // since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items + if (event.text == "`") { + handeMenuEvent("Edit Properties..."); + } + if (event.text == "BACKSPACE") { + handeMenuEvent("Delete"); + } +}); + From 75758c1a3e6bb15de334b5c84edbff2f8f3bec66 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 8 Jan 2015 15:40:54 -0800 Subject: [PATCH 02/51] Use static GLEW in render-utils for Windows --- libraries/render-utils/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/render-utils/CMakeLists.txt b/libraries/render-utils/CMakeLists.txt index f84bd97c13..cf3d7a6ad7 100644 --- a/libraries/render-utils/CMakeLists.txt +++ b/libraries/render-utils/CMakeLists.txt @@ -9,5 +9,10 @@ include_glm() link_hifi_libraries(animation fbx shared gpu) +if (WIN32) + # we're using static GLEW, so define GLEW_STATIC + add_definitions(-DGLEW_STATIC) +endif () + # call macro to include our dependency includes and bubble them up via a property on our target include_dependency_includes() \ No newline at end of file From 5ab0df32881fca75a6f6457d22b293a34f609409 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 8 Jan 2015 18:31:10 -0800 Subject: [PATCH 03/51] removed editModels --- examples/editModels.js | 3041 ---------------------------------------- 1 file changed, 3041 deletions(-) delete mode 100644 examples/editModels.js diff --git a/examples/editModels.js b/examples/editModels.js deleted file mode 100644 index 7cb911b490..0000000000 --- a/examples/editModels.js +++ /dev/null @@ -1,3041 +0,0 @@ -// -// editEntities.js -// examples -// -// Created by Clément Brisset on 4/24/14. -// Copyright 2014 High Fidelity, Inc. -// -// This script allows you to edit models either with the razor hydras or with your mouse -// -// If using the hydras : -// grab grab models with the triggers, you can then move the models around or scale them with both hands. -// You can switch mode using the bumpers so that you can move models around more easily. -// -// If using the mouse : -// - left click lets you move the model in the plane facing you. -// If pressing shift, it will move on the horizontal plane it's in. -// - right click lets you rotate the model. z and x give access to more axes of rotation while shift provides finer control. -// - left + right click lets you scale the model. -// - you can press r while holding the model to reset its rotation -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -Script.include("libraries/globals.js"); -Script.include("libraries/toolBars.js"); - -Script.include("libraries/entityPropertyDialogBox.js"); -var entityPropertyDialogBox = EntityPropertyDialogBox; - -var windowDimensions = Controller.getViewportDimensions(); -var toolIconUrl = HIFI_PUBLIC_BUCKET + "images/tools/"; -var toolHeight = 50; -var toolWidth = 50; - -var LASER_WIDTH = 4; -var LASER_COLOR = { red: 255, green: 0, blue: 0 }; -var LASER_LENGTH_FACTOR = 500; - -var MIN_ANGULAR_SIZE = 2; -var MAX_ANGULAR_SIZE = 45; -var allowLargeModels = false; -var allowSmallModels = false; -var wantEntityGlow = false; - -var LEFT = 0; -var RIGHT = 1; - -var SPAWN_DISTANCE = 1; -var DEFAULT_DIMENSION = 0.20; -var DEFAULT_TEXT_DIMENSION_X = 1.0; -var DEFAULT_TEXT_DIMENSION_Y = 1.0; -var DEFAULT_TEXT_DIMENSION_Z = 0.01; - -var modelURLs = [ - HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Alder.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Bush1.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Bush6.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed2.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed4.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed7.fbx" - ]; - -var jointList = MyAvatar.getJointNames(); - -var mode = 0; -var isActive = false; - - -if (typeof String.prototype.fileName !== "function") { - String.prototype.fileName = function () { - return this.replace(/^(.*[\/\\])*/, ""); - }; -} - -if (typeof String.prototype.fileBase !== "function") { - String.prototype.fileBase = function () { - var filename = this.fileName(); - return filename.slice(0, filename.indexOf(".")); - }; -} - -if (typeof String.prototype.fileType !== "function") { - String.prototype.fileType = function () { - return this.slice(this.lastIndexOf(".") + 1); - }; -} - -if (typeof String.prototype.path !== "function") { - String.prototype.path = function () { - return this.replace(/[\\\/][^\\\/]*$/, ""); - }; -} - -if (typeof String.prototype.regExpEscape !== "function") { - String.prototype.regExpEscape = function () { - return this.replace(/([$\^.+*?|\\\/{}()\[\]])/g, '\\$1'); - }; -} - -if (typeof String.prototype.toArrayBuffer !== "function") { - String.prototype.toArrayBuffer = function () { - var length, - buffer, - view, - charCode, - charCodes, - i; - - charCodes = []; - - length = this.length; - for (i = 0; i < length; i += 1) { - charCode = this.charCodeAt(i); - if (charCode <= 255) { - charCodes.push(charCode); - } else { - charCodes.push(charCode / 256); - charCodes.push(charCode % 256); - } - } - - length = charCodes.length; - buffer = new ArrayBuffer(length); - view = new Uint8Array(buffer); - for (i = 0; i < length; i += 1) { - view[i] = charCodes[i]; - } - - return buffer; - }; -} - -if (typeof DataView.prototype.indexOf !== "function") { - DataView.prototype.indexOf = function (searchString, position) { - var searchLength = searchString.length, - byteArrayLength = this.byteLength, - maxSearchIndex = byteArrayLength - searchLength, - searchCharCodes = [], - found, - i, - j; - - searchCharCodes[searchLength] = 0; - for (j = 0; j < searchLength; j += 1) { - searchCharCodes[j] = searchString.charCodeAt(j); - } - - i = position; - found = false; - while (i < maxSearchIndex && !found) { - j = 0; - while (j < searchLength && this.getUint8(i + j) === searchCharCodes[j]) { - j += 1; - } - found = (j === searchLength); - i += 1; - } - - return found ? i - 1 : -1; - }; -} - -if (typeof DataView.prototype.string !== "function") { - DataView.prototype.string = function (start, length) { - var charCodes = [], - end, - i; - - if (start === undefined) { - start = 0; - } - if (length === undefined) { - length = this.length; - } - - end = start + length; - for (i = start; i < end; i += 1) { - charCodes.push(this.getUint8(i)); - } - - return String.fromCharCode.apply(String, charCodes); - }; -} - -var progressDialog = (function () { - var that = {}, - progressBackground, - progressMessage, - cancelButton, - displayed = false, - backgroundWidth = 300, - backgroundHeight = 100, - messageHeight = 32, - cancelWidth = 70, - cancelHeight = 32, - textColor = { red: 255, green: 255, blue: 255 }, - textBackground = { red: 52, green: 52, blue: 52 }, - backgroundUrl = toolIconUrl + "progress-background.svg", - windowDimensions; - - progressBackground = Overlays.addOverlay("image", { - width: backgroundWidth, - height: backgroundHeight, - imageURL: backgroundUrl, - alpha: 0.9, - backgroundAlpha: 0.9, - visible: false - }); - - progressMessage = Overlays.addOverlay("text", { - width: backgroundWidth - 40, - height: messageHeight, - text: "", - textColor: textColor, - backgroundColor: textBackground, - alpha: 0.9, - backgroundAlpha: 0.9, - visible: false - }); - - cancelButton = Overlays.addOverlay("text", { - width: cancelWidth, - height: cancelHeight, - text: "Cancel", - textColor: textColor, - backgroundColor: textBackground, - alpha: 0.9, - backgroundAlpha: 0.9, - visible: false - }); - - function move() { - var progressX, - progressY; - - if (displayed) { - - if (windowDimensions.x === Window.innerWidth && windowDimensions.y === Window.innerHeight) { - return; - } - windowDimensions.x = Window.innerWidth; - windowDimensions.y = Window.innerHeight; - - progressX = (windowDimensions.x - backgroundWidth) / 2; // Center. - progressY = windowDimensions.y / 2 - backgroundHeight; // A little up from center. - - Overlays.editOverlay(progressBackground, { x: progressX, y: progressY }); - Overlays.editOverlay(progressMessage, { x: progressX + 20, y: progressY + 15 }); - Overlays.editOverlay(cancelButton, { - x: progressX + backgroundWidth - cancelWidth - 20, - y: progressY + backgroundHeight - cancelHeight - 15 - }); - } - } - that.move = move; - - that.onCancel = undefined; - - function open(message) { - if (!displayed) { - windowDimensions = { x: 0, y : 0 }; - displayed = true; - move(); - Overlays.editOverlay(progressBackground, { visible: true }); - Overlays.editOverlay(progressMessage, { visible: true, text: message }); - Overlays.editOverlay(cancelButton, { visible: true }); - } else { - throw new Error("open() called on progressDialog when already open"); - } - } - that.open = open; - - function isOpen() { - return displayed; - } - that.isOpen = isOpen; - - function update(message) { - if (displayed) { - Overlays.editOverlay(progressMessage, { text: message }); - } else { - throw new Error("update() called on progressDialog when not open"); - } - } - that.update = update; - - function close() { - if (displayed) { - Overlays.editOverlay(cancelButton, { visible: false }); - Overlays.editOverlay(progressMessage, { visible: false }); - Overlays.editOverlay(progressBackground, { visible: false }); - displayed = false; - } else { - throw new Error("close() called on progressDialog when not open"); - } - } - that.close = close; - - function mousePressEvent(event) { - if (Overlays.getOverlayAtPoint({ x: event.x, y: event.y }) === cancelButton) { - if (typeof this.onCancel === "function") { - close(); - this.onCancel(); - } - return true; - } - return false; - } - that.mousePressEvent = mousePressEvent; - - function cleanup() { - Overlays.deleteOverlay(cancelButton); - Overlays.deleteOverlay(progressMessage); - Overlays.deleteOverlay(progressBackground); - } - that.cleanup = cleanup; - - return that; -}()); - -var httpMultiPart = (function () { - var that = {}, - parts, - byteLength, - boundaryString, - crlf; - - function clear() { - boundaryString = "--boundary_" + String(Uuid.generate()).slice(1, 36) + "="; - parts = []; - byteLength = 0; - crlf = ""; - } - that.clear = clear; - - function boundary() { - return boundaryString.slice(2); - } - that.boundary = boundary; - - function length() { - return byteLength; - } - that.length = length; - - function add(object) { - // - name, string - // - name, buffer - var buffer, - string, - stringBuffer, - compressedBuffer; - - if (object.name === undefined) { - - throw new Error("Item to add to HttpMultiPart must have a name"); - - } else if (object.string !== undefined) { - //--= - //Content-Disposition: form-data; name="model_name" - // - // - - string = crlf + boundaryString + "\r\n" - + "Content-Disposition: form-data; name=\"" + object.name + "\"\r\n" - + "\r\n" - + object.string; - buffer = string.toArrayBuffer(); - - } else if (object.buffer !== undefined) { - //--= - //Content-Disposition: form-data; name="fbx"; filename="" - //Content-Type: application/octet-stream - // - // - - string = crlf + boundaryString + "\r\n" - + "Content-Disposition: form-data; name=\"" + object.name - + "\"; filename=\"" + object.buffer.filename + "\"\r\n" - + "Content-Type: application/octet-stream\r\n" - + "\r\n"; - stringBuffer = string.toArrayBuffer(); - - compressedBuffer = object.buffer.buffer.compress(); - buffer = new Uint8Array(stringBuffer.byteLength + compressedBuffer.byteLength); - buffer.set(new Uint8Array(stringBuffer)); - buffer.set(new Uint8Array(compressedBuffer), stringBuffer.byteLength); - - } else { - - throw new Error("Item to add to HttpMultiPart not recognized"); - } - - byteLength += buffer.byteLength; - parts.push(buffer); - - crlf = "\r\n"; - - return true; - } - that.add = add; - - function response() { - var buffer, - index, - str, - i; - - str = crlf + boundaryString + "--\r\n"; - buffer = str.toArrayBuffer(); - byteLength += buffer.byteLength; - parts.push(buffer); - - buffer = new Uint8Array(byteLength); - index = 0; - for (i = 0; i < parts.length; i += 1) { - buffer.set(new Uint8Array(parts[i]), index); - index += parts[i].byteLength; - } - - return buffer; - } - that.response = response; - - clear(); - - return that; -}()); - -var modelUploader = (function () { - var that = {}, - modelFile, - modelName, - modelURL, - modelCallback, - isProcessing, - fstBuffer, - fbxBuffer, - //svoBuffer, - mapping, - geometry, - API_URL = "https://data.highfidelity.io/api/v1/models", - MODEL_URL = "http://public.highfidelity.io/models/content", - NAME_FIELD = "name", - SCALE_FIELD = "scale", - FILENAME_FIELD = "filename", - TEXDIR_FIELD = "texdir", - MAX_TEXTURE_SIZE = 1024; - - function info(message) { - if (progressDialog.isOpen()) { - progressDialog.update(message); - } else { - progressDialog.open(message); - } - print(message); - } - - function error(message) { - if (progressDialog.isOpen()) { - progressDialog.close(); - } - print(message); - Window.alert(message); - } - - function randomChar(length) { - var characters = "0123457689abcdefghijklmnopqrstuvwxyz", - string = "", - i; - - for (i = 0; i < length; i += 1) { - string += characters[Math.floor(Math.random() * 36)]; - } - - return string; - } - - function resetDataObjects() { - fstBuffer = null; - fbxBuffer = null; - //svoBuffer = null; - mapping = {}; - geometry = {}; - geometry.textures = []; - geometry.embedded = []; - } - - function readFile(filename) { - var url = "file:///" + filename, - req = new XMLHttpRequest(); - - req.open("GET", url, false); - req.responseType = "arraybuffer"; - req.send(); - if (req.status !== 200) { - error("Could not read file: " + filename + " : " + req.statusText); - return null; - } - - return { - filename: filename.fileName(), - buffer: req.response - }; - } - - function readMapping(buffer) { - var dv = new DataView(buffer.buffer), - lines, - line, - tokens, - i, - name, - value, - remainder, - existing; - - mapping = {}; // { name : value | name : { value : [remainder] } } - lines = dv.string(0, dv.byteLength).split(/\r\n|\r|\n/); - for (i = 0; i < lines.length; i += 1) { - line = lines[i].trim(); - if (line.length > 0 && line[0] !== "#") { - tokens = line.split(/\s*=\s*/); - if (tokens.length > 1) { - name = tokens[0]; - value = tokens[1]; - if (tokens.length > 2) { - remainder = tokens.slice(2, tokens.length).join(" = "); - } else { - remainder = null; - } - if (tokens.length === 2 && mapping[name] === undefined) { - mapping[name] = value; - } else { - if (mapping[name] === undefined) { - mapping[name] = {}; - - } else if (typeof mapping[name] !== "object") { - existing = mapping[name]; - mapping[name] = { existing : null }; - } - - if (mapping[name][value] === undefined) { - mapping[name][value] = []; - } - mapping[name][value].push(remainder); - } - } - } - } - } - - function writeMapping(buffer) { - var name, - value, - remainder, - i, - string = ""; - - for (name in mapping) { - if (mapping.hasOwnProperty(name)) { - if (typeof mapping[name] === "object") { - for (value in mapping[name]) { - if (mapping[name].hasOwnProperty(value)) { - remainder = mapping[name][value]; - if (remainder === null) { - string += (name + " = " + value + "\n"); - } else { - for (i = 0; i < remainder.length; i += 1) { - string += (name + " = " + value + " = " + remainder[i] + "\n"); - } - } - } - } - } else { - string += (name + " = " + mapping[name] + "\n"); - } - } - } - - buffer.buffer = string.toArrayBuffer(); - } - - function readGeometry(fbxBuffer) { - var textures, - view, - index, - EOF, - previousNodeFilename; - - // Reference: - // http://code.blender.org/index.php/2013/08/fbx-binary-file-format-specification/ - - textures = {}; - view = new DataView(fbxBuffer.buffer); - EOF = false; - - function parseBinaryFBX() { - var endOffset, - numProperties, - propertyListLength, - nameLength, - name, - filename; - - endOffset = view.getUint32(index, true); - numProperties = view.getUint32(index + 4, true); - propertyListLength = view.getUint32(index + 8, true); - nameLength = view.getUint8(index + 12); - index += 13; - - if (endOffset === 0) { - return; - } - if (endOffset < index || endOffset > view.byteLength) { - EOF = true; - return; - } - - name = view.string(index, nameLength).toLowerCase(); - index += nameLength; - - if (name === "content" && previousNodeFilename !== "") { - // Blender 2.71 exporter "embeds" external textures as empty binary blobs so ignore these - if (propertyListLength > 5) { - geometry.embedded.push(previousNodeFilename); - } - } - - if (name === "relativefilename") { - filename = view.string(index + 5, view.getUint32(index + 1, true)).fileName(); - if (!textures.hasOwnProperty(filename)) { - textures[filename] = ""; - geometry.textures.push(filename); - } - previousNodeFilename = filename; - } else { - previousNodeFilename = ""; - } - - index += (propertyListLength); - - while (index < endOffset && !EOF) { - parseBinaryFBX(); - } - } - - function readTextFBX() { - var line, - view, - viewLength, - charCode, - charCodes, - numCharCodes, - filename, - relativeFilename = "", - MAX_CHAR_CODES = 250; - - view = new Uint8Array(fbxBuffer.buffer); - viewLength = view.byteLength; - charCodes = []; - numCharCodes = 0; - - for (index = 0; index < viewLength; index += 1) { - charCode = view[index]; - if (charCode !== 9 && charCode !== 32) { - if (charCode === 10) { // EOL. Can ignore EOF. - line = String.fromCharCode.apply(String, charCodes).toLowerCase(); - // For embedded textures, "Content:" line immediately follows "RelativeFilename:" line. - if (line.slice(0, 8) === "content:" && relativeFilename !== "") { - geometry.embedded.push(relativeFilename); - } - if (line.slice(0, 17) === "relativefilename:") { - filename = line.slice(line.indexOf("\""), line.lastIndexOf("\"") - line.length).fileName(); - if (!textures.hasOwnProperty(filename)) { - textures[filename] = ""; - geometry.textures.push(filename); - } - relativeFilename = filename; - } else { - relativeFilename = ""; - } - charCodes = []; - numCharCodes = 0; - } else { - if (numCharCodes < MAX_CHAR_CODES) { // Only interested in start of line - charCodes.push(charCode); - numCharCodes += 1; - } - } - } - } - } - - if (view.string(0, 18) === "Kaydara FBX Binary") { - previousNodeFilename = ""; - - index = 27; - while (index < view.byteLength - 39 && !EOF) { - parseBinaryFBX(); - } - - } else { - - readTextFBX(); - - } - } - - function readModel() { - var fbxFilename, - //svoFilename, - fileType; - - info("Reading model file"); - print("Model file: " + modelFile); - - if (modelFile.toLowerCase().fileType() === "fst") { - fstBuffer = readFile(modelFile); - if (fstBuffer === null) { - return false; - } - readMapping(fstBuffer); - fileType = mapping[FILENAME_FIELD].toLowerCase().fileType(); - if (mapping.hasOwnProperty(FILENAME_FIELD)) { - if (fileType === "fbx") { - fbxFilename = modelFile.path() + "\\" + mapping[FILENAME_FIELD]; - //} else if (fileType === "svo") { - // svoFilename = modelFile.path() + "\\" + mapping[FILENAME_FIELD]; - } else { - error("Unrecognized model type in FST file!"); - return false; - } - } else { - error("Model file name not found in FST file!"); - return false; - } - } else { - fstBuffer = { - filename: "Interface." + randomChar(6), // Simulate avatar model uploading behaviour - buffer: null - }; - - if (modelFile.toLowerCase().fileType() === "fbx") { - fbxFilename = modelFile; - mapping[FILENAME_FIELD] = modelFile.fileName(); - - //} else if (modelFile.toLowerCase().fileType() === "svo") { - // svoFilename = modelFile; - // mapping[FILENAME_FIELD] = modelFile.fileName(); - - } else { - error("Unrecognized file type: " + modelFile); - return false; - } - } - - if (!isProcessing) { return false; } - - if (fbxFilename) { - fbxBuffer = readFile(fbxFilename); - if (fbxBuffer === null) { - return false; - } - - if (!isProcessing) { return false; } - - readGeometry(fbxBuffer); - } - - //if (svoFilename) { - // svoBuffer = readFile(svoFilename); - // if (svoBuffer === null) { - // return false; - // } - //} - - // Add any missing basic mappings - if (!mapping.hasOwnProperty(NAME_FIELD)) { - mapping[NAME_FIELD] = modelFile.fileName().fileBase(); - } - if (!mapping.hasOwnProperty(TEXDIR_FIELD)) { - mapping[TEXDIR_FIELD] = "."; - } - if (!mapping.hasOwnProperty(SCALE_FIELD)) { - mapping[SCALE_FIELD] = 1.0; - } - - return true; - } - - function setProperties() { - var form = [], - directory, - displayAs, - validateAs; - - progressDialog.close(); - print("Setting model properties"); - - form.push({ label: "Name:", value: mapping[NAME_FIELD] }); - - directory = modelFile.path() + "/" + mapping[TEXDIR_FIELD]; - displayAs = new RegExp("^" + modelFile.path().regExpEscape() + "[\\\\\\\/](.*)"); - validateAs = new RegExp("^" + modelFile.path().regExpEscape() + "([\\\\\\\/].*)?"); - - form.push({ - label: "Texture directory:", - directory: modelFile.path() + "/" + mapping[TEXDIR_FIELD], - title: "Choose Texture Directory", - displayAs: displayAs, - validateAs: validateAs, - errorMessage: "Texture directory must be subdirectory of the model directory." - }); - - form.push({ button: "Cancel" }); - - if (!Window.form("Set Model Properties", form)) { - print("User cancelled uploading model"); - return false; - } - - mapping[NAME_FIELD] = form[0].value; - mapping[TEXDIR_FIELD] = form[1].directory.slice(modelFile.path().length + 1); - if (mapping[TEXDIR_FIELD] === "") { - mapping[TEXDIR_FIELD] = "."; - } - - writeMapping(fstBuffer); - - return true; - } - - function createHttpMessage(callback) { - var multiparts = [], - lodCount, - lodFile, - lodBuffer, - textureBuffer, - textureSourceFormat, - textureTargetFormat, - embeddedTextures, - i; - - info("Preparing to send model"); - - // Model name - if (mapping.hasOwnProperty(NAME_FIELD)) { - multiparts.push({ - name : "model_name", - string : mapping[NAME_FIELD] - }); - } else { - error("Model name is missing"); - httpMultiPart.clear(); - return; - } - - // FST file - if (fstBuffer) { - multiparts.push({ - name : "fst", - buffer: fstBuffer - }); - } - - // FBX file - if (fbxBuffer) { - multiparts.push({ - name : "fbx", - buffer: fbxBuffer - }); - } - - // SVO file - //if (svoBuffer) { - // multiparts.push({ - // name : "svo", - // buffer: svoBuffer - // }); - //} - - // LOD files - lodCount = 0; - for (lodFile in mapping.lod) { - if (mapping.lod.hasOwnProperty(lodFile)) { - lodBuffer = readFile(modelFile.path() + "\/" + lodFile); - if (lodBuffer === null) { - return; - } - multiparts.push({ - name: "lod" + lodCount, - buffer: lodBuffer - }); - lodCount += 1; - } - if (!isProcessing) { return; } - } - - // Textures - embeddedTextures = "|" + geometry.embedded.join("|") + "|"; - for (i = 0; i < geometry.textures.length; i += 1) { - if (embeddedTextures.indexOf("|" + geometry.textures[i].fileName() + "|") === -1) { - textureBuffer = readFile(modelFile.path() + "\/" - + (mapping[TEXDIR_FIELD] !== "." ? mapping[TEXDIR_FIELD] + "\/" : "") - + geometry.textures[i]); - if (textureBuffer === null) { - return; - } - - textureSourceFormat = geometry.textures[i].fileType().toLowerCase(); - textureTargetFormat = (textureSourceFormat === "jpg" ? "jpg" : "png"); - textureBuffer.buffer = - textureBuffer.buffer.recodeImage(textureSourceFormat, textureTargetFormat, MAX_TEXTURE_SIZE); - textureBuffer.filename = textureBuffer.filename.slice(0, -textureSourceFormat.length) + textureTargetFormat; - - multiparts.push({ - name: "texture" + i, - buffer: textureBuffer - }); - } - - if (!isProcessing) { return; } - } - - // Model category - multiparts.push({ - name : "model_category", - string : "content" - }); - - // Create HTTP message - httpMultiPart.clear(); - Script.setTimeout(function addMultipart() { - var multipart = multiparts.shift(); - httpMultiPart.add(multipart); - - if (!isProcessing) { return; } - - if (multiparts.length > 0) { - Script.setTimeout(addMultipart, 25); - } else { - callback(); - } - }, 25); - } - - function sendToHighFidelity() { - var req, - uploadedChecks, - HTTP_GET_TIMEOUT = 60, // 1 minute - HTTP_SEND_TIMEOUT = 900, // 15 minutes - UPLOADED_CHECKS = 30, - CHECK_UPLOADED_TIMEOUT = 1, // 1 second - handleCheckUploadedResponses, - handleUploadModelResponses, - handleRequestUploadResponses; - - function uploadTimedOut() { - error("Model upload failed: Internet request timed out!"); - } - - function debugResponse() { - print("req.errorCode = " + req.errorCode); - print("req.readyState = " + req.readyState); - print("req.status = " + req.status); - print("req.statusText = " + req.statusText); - print("req.responseType = " + req.responseType); - print("req.responseText = " + req.responseText); - print("req.response = " + req.response); - print("req.getAllResponseHeaders() = " + req.getAllResponseHeaders()); - } - - function checkUploaded() { - if (!isProcessing) { return; } - - info("Checking uploaded model"); - - req = new XMLHttpRequest(); - req.open("HEAD", modelURL, true); - req.timeout = HTTP_GET_TIMEOUT * 1000; - req.onreadystatechange = handleCheckUploadedResponses; - req.ontimeout = uploadTimedOut; - req.send(); - } - - handleCheckUploadedResponses = function () { - //debugResponse(); - if (req.readyState === req.DONE) { - if (req.status === 200) { - // Note: Unlike avatar models, for content models we don't need to refresh texture cache. - print("Model uploaded: " + modelURL); - progressDialog.close(); - if (Window.confirm("Your model has been uploaded as: " + modelURL + "\nDo you want to rez it?")) { - modelCallback(modelURL); - } - } else if (req.status === 404) { - if (uploadedChecks > 0) { - uploadedChecks -= 1; - Script.setTimeout(checkUploaded, CHECK_UPLOADED_TIMEOUT * 1000); - } else { - print("Error: " + req.status + " " + req.statusText); - error("We could not verify that your model was successfully uploaded but it may have been at: " - + modelURL); - } - } else { - print("Error: " + req.status + " " + req.statusText); - error("There was a problem with your upload, please try again later."); - } - } - }; - - function uploadModel(method) { - var url; - - if (!isProcessing) { return; } - - req = new XMLHttpRequest(); - if (method === "PUT") { - url = API_URL + "\/" + modelName; - req.open("PUT", url, true); //print("PUT " + url); - } else { - url = API_URL; - req.open("POST", url, true); //print("POST " + url); - } - req.setRequestHeader("Content-Type", "multipart/form-data; boundary=\"" + httpMultiPart.boundary() + "\""); - req.timeout = HTTP_SEND_TIMEOUT * 1000; - req.onreadystatechange = handleUploadModelResponses; - req.ontimeout = uploadTimedOut; - req.send(httpMultiPart.response().buffer); - } - - handleUploadModelResponses = function () { - //debugResponse(); - if (req.readyState === req.DONE) { - if (req.status === 200) { - uploadedChecks = UPLOADED_CHECKS; - checkUploaded(); - } else { - print("Error: " + req.status + " " + req.statusText); - error("There was a problem with your upload, please try again later."); - } - } - }; - - function requestUpload() { - var url; - - if (!isProcessing) { return; } - - url = API_URL + "\/" + modelName; // XMLHttpRequest automatically handles authorization of API requests. - req = new XMLHttpRequest(); - req.open("GET", url, true); //print("GET " + url); - req.responseType = "json"; - req.timeout = HTTP_GET_TIMEOUT * 1000; - req.onreadystatechange = handleRequestUploadResponses; - req.ontimeout = uploadTimedOut; - req.send(); - } - - handleRequestUploadResponses = function () { - var response; - - //debugResponse(); - if (req.readyState === req.DONE) { - if (req.status === 200) { - if (req.responseType === "json") { - response = JSON.parse(req.responseText); - if (response.status === "success") { - if (response.exists === false) { - uploadModel("POST"); - } else if (response.can_update === true) { - uploadModel("PUT"); - } else { - error("This model file already exists and is owned by someone else!"); - } - return; - } - } - } else { - print("Error: " + req.status + " " + req.statusText); - } - error("Model upload failed! Something went wrong at the data server."); - } - }; - - info("Sending model to High Fidelity"); - - requestUpload(); - } - - that.upload = function (file, callback) { - - modelFile = file; - modelCallback = callback; - - isProcessing = true; - - progressDialog.onCancel = function () { - print("User cancelled uploading model"); - isProcessing = false; - }; - - resetDataObjects(); - - if (readModel()) { - if (setProperties()) { - modelName = mapping[NAME_FIELD]; - modelURL = MODEL_URL + "\/" + mapping[NAME_FIELD] + ".fst"; // All models are uploaded as an FST - - createHttpMessage(sendToHighFidelity); - } - } - - resetDataObjects(); - }; - - return that; -}()); - -var toolBar = (function () { - var that = {}, - toolBar, - activeButton, - newModelButton, - newCubeButton, - newSphereButton, - newTextButton, - browseModelsButton, - loadURLMenuItem, - loadFileMenuItem, - menuItemWidth, - menuItemOffset, - menuItemHeight, - menuItemMargin = 5, - menuTextColor = { red: 255, green: 255, blue: 255 }, - menuBackgroundColor = { red: 18, green: 66, blue: 66 }; - - function initialize() { - toolBar = new ToolBar(0, 0, ToolBar.VERTICAL); - - activeButton = toolBar.addTool({ - imageURL: toolIconUrl + "models-tool.svg", - subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - width: toolWidth, - height: toolHeight, - alpha: 0.9, - visible: true - }, true, false); - - newModelButton = toolBar.addTool({ - imageURL: toolIconUrl + "add-model-tool.svg", - subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - width: toolWidth, - height: toolHeight, - alpha: 0.9, - visible: true - }, true, false); - - browseModelsButton = toolBar.addTool({ - imageURL: toolIconUrl + "list-icon.svg", - width: toolWidth, - height: toolHeight, - alpha: 0.9, - visible: true - }); - - menuItemOffset = toolBar.height / 3 + 2; - menuItemHeight = Tool.IMAGE_HEIGHT / 2 - 2; - - loadURLMenuItem = Overlays.addOverlay("text", { - height: menuItemHeight, - backgroundColor: menuBackgroundColor, - topMargin: menuItemMargin, - text: "Model URL", - alpha: 0.9, - backgroundAlpha: 0.9, - visible: false - }); - - loadFileMenuItem = Overlays.addOverlay("text", { - height: menuItemHeight, - backgroundColor: menuBackgroundColor, - topMargin: menuItemMargin, - text: "Model File", - alpha: 0.9, - backgroundAlpha: 0.9, - visible: false - }); - - menuItemWidth = Math.max(Overlays.textSize(loadURLMenuItem, "Model URL").width, - Overlays.textSize(loadFileMenuItem, "Model File").width) + 20; - Overlays.editOverlay(loadURLMenuItem, { width: menuItemWidth }); - Overlays.editOverlay(loadFileMenuItem, { width: menuItemWidth }); - - newCubeButton = toolBar.addTool({ - imageURL: toolIconUrl + "add-cube.svg", - subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - width: toolWidth, - height: toolHeight, - alpha: 0.9, - visible: true - }); - - newSphereButton = toolBar.addTool({ - imageURL: toolIconUrl + "add-sphere.svg", - subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - width: toolWidth, - height: toolHeight, - alpha: 0.9, - visible: true - }); - - newTextButton = toolBar.addTool({ - imageURL: toolIconUrl + "add-text.svg", - subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - width: toolWidth, - height: toolHeight, - alpha: 0.9, - visible: true - }); - } - - function toggleNewModelButton(active) { - if (active === undefined) { - active = !toolBar.toolSelected(newModelButton); - } - toolBar.selectTool(newModelButton, active); - - Overlays.editOverlay(loadURLMenuItem, { visible: active }); - Overlays.editOverlay(loadFileMenuItem, { visible: active }); - } - - var RESIZE_INTERVAL = 50; - var RESIZE_TIMEOUT = 20000; - var RESIZE_MAX_CHECKS = RESIZE_TIMEOUT / RESIZE_INTERVAL; - function addModel(url) { - var position; - - position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); - - if (position.x > 0 && position.y > 0 && position.z > 0) { - var entityId = Entities.addEntity({ - type: "Model", - position: position, - dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION }, - modelURL: url - }); - print("Model added: " + url); - - var checkCount = 0; - function resize() { - var entityProperties = Entities.getEntityProperties(entityId); - var naturalDimensions = entityProperties.naturalDimensions; - - checkCount++; - - if (naturalDimensions.x == 0 && naturalDimensions.y == 0 && naturalDimensions.z == 0) { - if (checkCount < RESIZE_MAX_CHECKS) { - Script.setTimeout(resize, RESIZE_INTERVAL); - } else { - print("Resize failed: timed out waiting for model (" + url + ") to load"); - } - } else { - entityProperties.dimensions = naturalDimensions; - Entities.editEntity(entityId, entityProperties); - } - } - - Script.setTimeout(resize, RESIZE_INTERVAL); - - } else { - print("Can't add model: Model would be out of bounds."); - } - } - - that.move = function () { - var newViewPort, - toolsX, - toolsY; - - newViewPort = Controller.getViewportDimensions(); - - if (toolBar === undefined) { - initialize(); - - } else if (windowDimensions.x === newViewPort.x && - windowDimensions.y === newViewPort.y) { - return; - } - - windowDimensions = newViewPort; - toolsX = windowDimensions.x - 8 - toolBar.width; - toolsY = (windowDimensions.y - toolBar.height) / 2; - - toolBar.move(toolsX, toolsY); - - Overlays.editOverlay(loadURLMenuItem, { x: toolsX - menuItemWidth, y: toolsY + menuItemOffset }); - Overlays.editOverlay(loadFileMenuItem, { x: toolsX - menuItemWidth, y: toolsY + menuItemOffset + menuItemHeight }); - }; - - that.mousePressEvent = function (event) { - var clickedOverlay, - url, - file; - - clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); - - if (activeButton === toolBar.clicked(clickedOverlay)) { - isActive = !isActive; - return true; - } - - if (newModelButton === toolBar.clicked(clickedOverlay)) { - toggleNewModelButton(); - return true; - } - - if (clickedOverlay === loadURLMenuItem) { - toggleNewModelButton(false); - url = Window.prompt("Model URL", modelURLs[Math.floor(Math.random() * modelURLs.length)]); - if (url !== null && url !== "") { - addModel(url); - } - return true; - } - - if (clickedOverlay === loadFileMenuItem) { - toggleNewModelButton(false); - - file = Window.browse("Select your model file ...", - Settings.getValue("LastModelUploadLocation").path(), - "Model files (*.fst *.fbx)"); - //"Model files (*.fst *.fbx *.svo)"); - if (file !== null) { - Settings.setValue("LastModelUploadLocation", file); - modelUploader.upload(file, addModel); - } - return true; - } - - if (browseModelsButton === toolBar.clicked(clickedOverlay)) { - toggleNewModelButton(false); - url = Window.s3Browse(".*(fbx|FBX)"); - if (url !== null && url !== "") { - addModel(url); - } - return true; - } - - if (newCubeButton === toolBar.clicked(clickedOverlay)) { - var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); - - if (position.x > 0 && position.y > 0 && position.z > 0) { - Entities.addEntity({ - type: "Box", - position: position, - dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION }, - color: { red: 255, green: 0, blue: 0 } - - }); - } else { - print("Can't create box: Box would be out of bounds."); - } - return true; - } - - if (newSphereButton === toolBar.clicked(clickedOverlay)) { - var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); - - if (position.x > 0 && position.y > 0 && position.z > 0) { - Entities.addEntity({ - type: "Sphere", - position: position, - dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION }, - color: { red: 255, green: 0, blue: 0 } - }); - } else { - print("Can't create box: Box would be out of bounds."); - } - return true; - } - - - if (newTextButton === toolBar.clicked(clickedOverlay)) { - var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); - - if (position.x > 0 && position.y > 0 && position.z > 0) { - Entities.addEntity({ - type: "Text", - position: position, - dimensions: { x: DEFAULT_TEXT_DIMENSION_X, y: DEFAULT_TEXT_DIMENSION_Y, z: DEFAULT_TEXT_DIMENSION_Z }, - backgroundColor: { red: 0, green: 0, blue: 0 }, - textColor: { red: 255, green: 255, blue: 255 }, - text: "some text", - lineHight: "0.1" - }); - } else { - print("Can't create box: Text would be out of bounds."); - } - return true; - } - - return false; - }; - - that.cleanup = function () { - toolBar.cleanup(); - Overlays.deleteOverlay(loadURLMenuItem); - Overlays.deleteOverlay(loadFileMenuItem); - }; - - return that; -}()); - - -var exportMenu = null; - -var ExportMenu = function (opts) { - var self = this; - - var windowDimensions = Controller.getViewportDimensions(); - var pos = { x: windowDimensions.x / 2, y: windowDimensions.y - 100 }; - - this._onClose = opts.onClose || function () { }; - this._position = { x: 0.0, y: 0.0, z: 0.0 }; - this._scale = 1.0; - - var minScale = 1; - var maxScale = 32768; - var titleWidth = 120; - var locationWidth = 100; - var scaleWidth = 144; - var exportWidth = 100; - var cancelWidth = 100; - var margin = 4; - var height = 30; - var outerHeight = height + (2 * margin); - var buttonColor = { red: 128, green: 128, blue: 128 }; - - var SCALE_MINUS = scaleWidth * 40.0 / 100.0; - var SCALE_PLUS = scaleWidth * 63.0 / 100.0; - - var fullWidth = locationWidth + scaleWidth + exportWidth + cancelWidth + (2 * margin); - var offset = fullWidth / 2; - pos.x -= offset; - - var background = Overlays.addOverlay("text", { - x: pos.x, - y: pos.y, - opacity: 1, - width: fullWidth, - height: outerHeight, - backgroundColor: { red: 200, green: 200, blue: 200 }, - text: "", - }); - - var titleText = Overlays.addOverlay("text", { - x: pos.x, - y: pos.y - height, - font: { size: 14 }, - width: titleWidth, - height: height, - backgroundColor: { red: 255, green: 255, blue: 255 }, - color: { red: 255, green: 255, blue: 255 }, - text: "Export Models" - }); - - var locationButton = Overlays.addOverlay("text", { - x: pos.x + margin, - y: pos.y + margin, - width: locationWidth, - height: height, - color: { red: 255, green: 255, blue: 255 }, - text: "0, 0, 0", - }); - var scaleOverlay = Overlays.addOverlay("image", { - x: pos.x + margin + locationWidth, - y: pos.y + margin, - width: scaleWidth, - height: height, - subImage: { x: 0, y: 3, width: 144, height: height }, - imageURL: toolIconUrl + "voxel-size-selector.svg", - alpha: 0.9, - }); - var scaleViewWidth = 40; - var scaleView = Overlays.addOverlay("text", { - x: pos.x + margin + locationWidth + SCALE_MINUS, - y: pos.y + margin, - width: scaleViewWidth, - height: height, - alpha: 0.0, - backgroundAlpha: 0.0, - color: { red: 255, green: 255, blue: 255 }, - text: "1" - }); - var exportButton = Overlays.addOverlay("text", { - x: pos.x + margin + locationWidth + scaleWidth, - y: pos.y + margin, - width: exportWidth, - height: height, - color: { red: 0, green: 255, blue: 255 }, - text: "Export" - }); - var cancelButton = Overlays.addOverlay("text", { - x: pos.x + margin + locationWidth + scaleWidth + exportWidth, - y: pos.y + margin, - width: cancelWidth, - height: height, - color: { red: 255, green: 255, blue: 255 }, - text: "Cancel" - }); - - var voxelPreview = Overlays.addOverlay("cube", { - position: { x: 0, y: 0, z: 0 }, - size: this._scale, - color: { red: 255, green: 255, blue: 0 }, - alpha: 1, - solid: false, - visible: true, - lineWidth: 4 - }); - - this.parsePosition = function (str) { - var parts = str.split(','); - if (parts.length == 3) { - var x = parseFloat(parts[0]); - var y = parseFloat(parts[1]); - var z = parseFloat(parts[2]); - if (isFinite(x) && isFinite(y) && isFinite(z)) { - return { x: x, y: y, z: z }; - } - } - return null; - }; - - this.showPositionPrompt = function () { - var positionStr = self._position.x + ", " + self._position.y + ", " + self._position.z; - while (1) { - positionStr = Window.prompt("Position to export form:", positionStr); - if (positionStr == null) { - break; - } - var position = self.parsePosition(positionStr); - if (position != null) { - self.setPosition(position.x, position.y, position.z); - break; - } - Window.alert("The position you entered was invalid."); - } - }; - - this.setScale = function (scale) { - self._scale = Math.min(maxScale, Math.max(minScale, scale)); - Overlays.editOverlay(scaleView, { text: self._scale }); - Overlays.editOverlay(voxelPreview, { size: self._scale }); - } - - this.decreaseScale = function () { - self.setScale(self._scale /= 2); - } - - this.increaseScale = function () { - self.setScale(self._scale *= 2); - } - - this.exportEntities = function() { - var x = self._position.x; - var y = self._position.y; - var z = self._position.z; - var s = self._scale; - var filename = "models__" + Window.location.hostname + "__" + x + "_" + y + "_" + z + "_" + s + "__.svo"; - filename = Window.save("Select where to save", filename, "*.svo") - if (filename) { - var success = Clipboard.exportEntities(filename, x, y, z, s); - if (!success) { - Window.alert("Export failed: no models found in selected area."); - } - } - self.close(); - }; - - this.getPosition = function () { - return self._position; - }; - - this.setPosition = function (x, y, z) { - self._position = { x: x, y: y, z: z }; - var positionStr = x + ", " + y + ", " + z; - Overlays.editOverlay(locationButton, { text: positionStr }); - Overlays.editOverlay(voxelPreview, { position: self._position }); - - }; - - this.mouseReleaseEvent = function (event) { - var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); - - if (clickedOverlay == locationButton) { - self.showPositionPrompt(); - } else if (clickedOverlay == exportButton) { - self.exportEntities(); - } else if (clickedOverlay == cancelButton) { - self.close(); - } else if (clickedOverlay == scaleOverlay) { - var x = event.x - pos.x - margin - locationWidth; - print(x); - if (x < SCALE_MINUS) { - self.decreaseScale(); - } else if (x > SCALE_PLUS) { - self.increaseScale(); - } - } - }; - - this.close = function () { - this.cleanup(); - this._onClose(); - }; - - this.cleanup = function () { - Overlays.deleteOverlay(background); - Overlays.deleteOverlay(titleText); - Overlays.deleteOverlay(locationButton); - Overlays.deleteOverlay(exportButton); - Overlays.deleteOverlay(cancelButton); - Overlays.deleteOverlay(voxelPreview); - Overlays.deleteOverlay(scaleOverlay); - Overlays.deleteOverlay(scaleView); - }; - - print("CONNECTING!"); - Controller.mouseReleaseEvent.connect(this.mouseReleaseEvent); -}; - - - -var ModelImporter = function (opts) { - var self = this; - - var height = 30; - var margin = 4; - var outerHeight = height + (2 * margin); - var titleWidth = 120; - var cancelWidth = 100; - var fullWidth = titleWidth + cancelWidth + (2 * margin); - - var localModels = Overlays.addOverlay("localmodels", { - position: { x: 1, y: 1, z: 1 }, - scale: 1, - visible: false - }); - var importScale = 1; - var importBoundaries = Overlays.addOverlay("cube", { - position: { x: 0, y: 0, z: 0 }, - size: 1, - color: { red: 128, blue: 128, green: 128 }, - lineWidth: 4, - solid: false, - visible: false - }); - - var pos = { x: windowDimensions.x / 2 - (fullWidth / 2), y: windowDimensions.y - 100 }; - - var background = Overlays.addOverlay("text", { - x: pos.x, - y: pos.y, - opacity: 1, - width: fullWidth, - height: outerHeight, - backgroundColor: { red: 200, green: 200, blue: 200 }, - visible: false, - text: "", - }); - - var titleText = Overlays.addOverlay("text", { - x: pos.x + margin, - y: pos.y + margin, - font: { size: 14 }, - width: titleWidth, - height: height, - backgroundColor: { red: 255, green: 255, blue: 255 }, - color: { red: 255, green: 255, blue: 255 }, - visible: false, - text: "Import Models" - }); - var cancelButton = Overlays.addOverlay("text", { - x: pos.x + margin + titleWidth, - y: pos.y + margin, - width: cancelWidth, - height: height, - color: { red: 255, green: 255, blue: 255 }, - visible: false, - text: "Close" - }); - this._importing = false; - - this.setImportVisible = function (visible) { - Overlays.editOverlay(importBoundaries, { visible: visible }); - Overlays.editOverlay(localModels, { visible: visible }); - Overlays.editOverlay(cancelButton, { visible: visible }); - Overlays.editOverlay(titleText, { visible: visible }); - Overlays.editOverlay(background, { visible: visible }); - }; - - var importPosition = { x: 0, y: 0, z: 0 }; - this.moveImport = function (position) { - importPosition = position; - Overlays.editOverlay(localModels, { - position: { x: importPosition.x, y: importPosition.y, z: importPosition.z } - }); - Overlays.editOverlay(importBoundaries, { - position: { x: importPosition.x, y: importPosition.y, z: importPosition.z } - }); - } - - this.mouseMoveEvent = function (event) { - if (self._importing) { - var pickRay = Camera.computePickRay(event.x, event.y); - var intersection = false; //Voxels.findRayIntersection(pickRay); - - var distance = 2;// * self._scale; - - if (false) {//intersection.intersects) { - var intersectionDistance = Vec3.length(Vec3.subtract(pickRay.origin, intersection.intersection)); - if (intersectionDistance < distance) { - distance = intersectionDistance * 0.99; - } - - } - - var targetPosition = { - x: pickRay.origin.x + (pickRay.direction.x * distance), - y: pickRay.origin.y + (pickRay.direction.y * distance), - z: pickRay.origin.z + (pickRay.direction.z * distance) - }; - - if (targetPosition.x < 0) targetPosition.x = 0; - if (targetPosition.y < 0) targetPosition.y = 0; - if (targetPosition.z < 0) targetPosition.z = 0; - - var nudgeFactor = 1; - var newPosition = { - x: Math.floor(targetPosition.x / nudgeFactor) * nudgeFactor, - y: Math.floor(targetPosition.y / nudgeFactor) * nudgeFactor, - z: Math.floor(targetPosition.z / nudgeFactor) * nudgeFactor - } - - self.moveImport(newPosition); - } - } - - this.mouseReleaseEvent = function (event) { - var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); - - if (clickedOverlay == cancelButton) { - self._importing = false; - self.setImportVisible(false); - } - }; - - // Would prefer to use {4} for the coords, but it would only capture the last digit. - var fileRegex = /__(.+)__(\d+(?:\.\d+)?)_(\d+(?:\.\d+)?)_(\d+(?:\.\d+)?)_(\d+(?:\.\d+)?)__/; - this.doImport = function () { - if (!self._importing) { - var filename = Window.browse("Select models to import", "", "*.svo") - if (filename) { - parts = fileRegex.exec(filename); - if (parts == null) { - Window.alert("The file you selected does not contain source domain or location information"); - } else { - var hostname = parts[1]; - var x = parts[2]; - var y = parts[3]; - var z = parts[4]; - var s = parts[5]; - importScale = s; - if (hostname != location.hostname) { - if (!Window.confirm(("These models were not originally exported from this domain. Continue?"))) { - return; - } - } else { - if (Window.confirm(("Would you like to import back to the source location?"))) { - var success = Clipboard.importEntities(filename); - if (success) { - Clipboard.pasteEntities(x, y, z, 1); - } else { - Window.alert("There was an error importing the entity file."); - } - return; - } - } - } - var success = Clipboard.importEntities(filename); - if (success) { - self._importing = true; - self.setImportVisible(true); - Overlays.editOverlay(importBoundaries, { size: s }); - } else { - Window.alert("There was an error importing the entity file."); - } - } - } - } - - this.paste = function () { - if (self._importing) { - // self._importing = false; - // self.setImportVisible(false); - Clipboard.pasteEntities(importPosition.x, importPosition.y, importPosition.z, 1); - } - } - - this.cleanup = function () { - Overlays.deleteOverlay(localModels); - Overlays.deleteOverlay(importBoundaries); - Overlays.deleteOverlay(cancelButton); - Overlays.deleteOverlay(titleText); - Overlays.deleteOverlay(background); - } - - Controller.mouseReleaseEvent.connect(this.mouseReleaseEvent); - Controller.mouseMoveEvent.connect(this.mouseMoveEvent); -}; - -var modelImporter = new ModelImporter(); - - -function isLocked(properties) { - // special case to lock the ground plane model in hq. - if (location.hostname == "hq.highfidelity.io" && - properties.modelURL == HIFI_PUBLIC_BUCKET + "ozan/Terrain_Reduce_forAlpha.fbx") { - return true; - } - return false; -} - - -function controller(wichSide) { - this.side = wichSide; - this.palm = 2 * wichSide; - this.tip = 2 * wichSide + 1; - this.trigger = wichSide; - this.bumper = 6 * wichSide + 5; - - this.oldPalmPosition = Controller.getSpatialControlPosition(this.palm); - this.palmPosition = Controller.getSpatialControlPosition(this.palm); - - this.oldTipPosition = Controller.getSpatialControlPosition(this.tip); - this.tipPosition = Controller.getSpatialControlPosition(this.tip); - - this.oldUp = Controller.getSpatialControlNormal(this.palm); - this.up = this.oldUp; - - this.oldFront = Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)); - this.front = this.oldFront; - - this.oldRight = Vec3.cross(this.front, this.up); - this.right = this.oldRight; - - this.oldRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm)); - this.rotation = this.oldRotation; - - this.triggerValue = Controller.getTriggerValue(this.trigger); - this.bumperValue = Controller.isButtonPressed(this.bumper); - - this.pressed = false; // is trigger pressed - this.pressing = false; // is trigger being pressed (is pressed now but wasn't previously) - - this.grabbing = false; - this.entityID = { isKnownID: false }; - this.modelURL = ""; - this.oldModelRotation; - this.oldModelPosition; - this.oldModelHalfDiagonal; - - this.positionAtGrab; - this.rotationAtGrab; - this.modelPositionAtGrab; - this.rotationAtGrab; - this.jointsIntersectingFromStart = []; - - this.laser = Overlays.addOverlay("line3d", { - start: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: LASER_COLOR, - alpha: 1, - visible: false, - lineWidth: LASER_WIDTH, - anchor: "MyAvatar" - }); - - this.guideScale = 0.02; - this.ball = Overlays.addOverlay("sphere", { - position: { x: 0, y: 0, z: 0 }, - size: this.guideScale, - solid: true, - color: { red: 0, green: 255, blue: 0 }, - alpha: 1, - visible: false, - anchor: "MyAvatar" - }); - this.leftRight = Overlays.addOverlay("line3d", { - start: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: { red: 0, green: 0, blue: 255 }, - alpha: 1, - visible: false, - lineWidth: LASER_WIDTH, - anchor: "MyAvatar" - }); - this.topDown = Overlays.addOverlay("line3d", { - start: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: { red: 0, green: 0, blue: 255 }, - alpha: 1, - visible: false, - lineWidth: LASER_WIDTH, - anchor: "MyAvatar" - }); - - - - this.grab = function (entityID, properties) { - if (isLocked(properties)) { - print("Model locked " + entityID.id); - } else { - print("Grabbing " + entityID.id); - this.grabbing = true; - this.entityID = entityID; - this.modelURL = properties.modelURL; - - this.oldModelPosition = properties.position; - this.oldModelRotation = properties.rotation; - this.oldModelHalfDiagonal = Vec3.length(properties.dimensions) / 2.0; - - this.positionAtGrab = this.palmPosition; - this.rotationAtGrab = this.rotation; - this.modelPositionAtGrab = properties.position; - this.rotationAtGrab = properties.rotation; - this.jointsIntersectingFromStart = []; - for (var i = 0; i < jointList.length; i++) { - var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition); - if (distance < this.oldModelHalfDiagonal) { - this.jointsIntersectingFromStart.push(i); - } - } - this.showLaser(false); - } - } - - this.release = function () { - if (this.grabbing) { - jointList = MyAvatar.getJointNames(); - - var closestJointIndex = -1; - var closestJointDistance = 10; - for (var i = 0; i < jointList.length; i++) { - var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition); - if (distance < closestJointDistance) { - closestJointDistance = distance; - closestJointIndex = i; - } - } - - if (closestJointIndex != -1) { - print("closestJoint: " + jointList[closestJointIndex]); - print("closestJointDistance (attach max distance): " + closestJointDistance + " (" + this.oldModelHalfDiagonal + ")"); - } - - if (closestJointDistance < this.oldModelHalfDiagonal) { - - if (this.jointsIntersectingFromStart.indexOf(closestJointIndex) != -1 || - (leftController.grabbing && rightController.grabbing && - leftController.entityID.id == rightController.entityID.id)) { - // Do nothing - } else { - print("Attaching to " + jointList[closestJointIndex]); - var jointPosition = MyAvatar.getJointPosition(jointList[closestJointIndex]); - var jointRotation = MyAvatar.getJointCombinedRotation(jointList[closestJointIndex]); - - var attachmentOffset = Vec3.subtract(this.oldModelPosition, jointPosition); - attachmentOffset = Vec3.multiplyQbyV(Quat.inverse(jointRotation), attachmentOffset); - var attachmentRotation = Quat.multiply(Quat.inverse(jointRotation), this.oldModelRotation); - - MyAvatar.attach(this.modelURL, jointList[closestJointIndex], - attachmentOffset, attachmentRotation, 2.0 * this.oldModelHalfDiagonal, - true, false); - Entities.deleteEntity(this.entityID); - } - } - } - - this.grabbing = false; - this.entityID.isKnownID = false; - this.jointsIntersectingFromStart = []; - this.showLaser(true); - } - - this.checkTrigger = function () { - if (this.triggerValue > 0.9) { - if (this.pressed) { - this.pressing = false; - } else { - this.pressing = true; - } - this.pressed = true; - } else { - this.pressing = false; - this.pressed = false; - } - } - - this.checkEntity = function (properties) { - // special case to lock the ground plane model in hq. - if (isLocked(properties)) { - return { valid: false }; - } - - - // P P - Model - // /| A - Palm - // / | d B - unit vector toward tip - // / | X - base of the perpendicular line - // A---X----->B d - distance fom axis - // x x - distance from A - // - // |X-A| = (P-A).B - // X == A + ((P-A).B)B - // d = |P-X| - - var A = this.palmPosition; - var B = this.front; - var P = properties.position; - - var x = Vec3.dot(Vec3.subtract(P, A), B); - var y = Vec3.dot(Vec3.subtract(P, A), this.up); - var z = Vec3.dot(Vec3.subtract(P, A), this.right); - var X = Vec3.sum(A, Vec3.multiply(B, x)); - var d = Vec3.length(Vec3.subtract(P, X)); - var halfDiagonal = Vec3.length(properties.dimensions) / 2.0; - - var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14; - - var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) - && (allowSmallModels || angularSize > MIN_ANGULAR_SIZE); - - if (0 < x && sizeOK) { - return { valid: true, x: x, y: y, z: z }; - } - return { valid: false }; - } - - this.glowedIntersectingModel = { isKnownID: false }; - this.moveLaser = function () { - // the overlays here are anchored to the avatar, which means they are specified in the avatar's local frame - - var inverseRotation = Quat.inverse(MyAvatar.orientation); - var startPosition = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.palmPosition, MyAvatar.position)); - var direction = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.tipPosition, this.palmPosition)); - var distance = Vec3.length(direction); - direction = Vec3.multiply(direction, LASER_LENGTH_FACTOR / distance); - var endPosition = Vec3.sum(startPosition, direction); - - Overlays.editOverlay(this.laser, { - start: startPosition, - end: endPosition - }); - - - Overlays.editOverlay(this.ball, { - position: endPosition - }); - Overlays.editOverlay(this.leftRight, { - start: Vec3.sum(endPosition, Vec3.multiply(this.right, 2 * this.guideScale)), - end: Vec3.sum(endPosition, Vec3.multiply(this.right, -2 * this.guideScale)) - }); - Overlays.editOverlay(this.topDown, { - start: Vec3.sum(endPosition, Vec3.multiply(this.up, 2 * this.guideScale)), - end: Vec3.sum(endPosition, Vec3.multiply(this.up, -2 * this.guideScale)) - }); - this.showLaser(!this.grabbing || mode == 0); - - if (this.glowedIntersectingModel.isKnownID) { - Entities.editEntity(this.glowedIntersectingModel, { glowLevel: 0.0 }); - this.glowedIntersectingModel.isKnownID = false; - } - if (!this.grabbing) { - var intersection = Entities.findRayIntersection({ - origin: this.palmPosition, - direction: this.front - }); - - var halfDiagonal = Vec3.length(intersection.properties.dimensions) / 2.0; - - var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), intersection.properties.position)) * 180 / 3.14; - var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) - && (allowSmallModels || angularSize > MIN_ANGULAR_SIZE); - if (intersection.accurate && intersection.entityID.isKnownID && sizeOK) { - this.glowedIntersectingModel = intersection.entityID; - - if (wantEntityGlow) { - Entities.editEntity(this.glowedIntersectingModel, { glowLevel: 0.25 }); - } - } - } - } - - this.showLaser = function (show) { - Overlays.editOverlay(this.laser, { visible: show }); - Overlays.editOverlay(this.ball, { visible: show }); - Overlays.editOverlay(this.leftRight, { visible: show }); - Overlays.editOverlay(this.topDown, { visible: show }); - } - this.moveEntity = function () { - if (this.grabbing) { - if (!this.entityID.isKnownID) { - print("Unknown grabbed ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID); - this.entityID = Entities.findRayIntersection({ - origin: this.palmPosition, - direction: this.front - }).entityID; - print("Identified ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID); - } - var newPosition; - var newRotation; - - switch (mode) { - case 0: - newPosition = Vec3.sum(this.palmPosition, - Vec3.multiply(this.front, this.x)); - newPosition = Vec3.sum(newPosition, - Vec3.multiply(this.up, this.y)); - newPosition = Vec3.sum(newPosition, - Vec3.multiply(this.right, this.z)); - - - newRotation = Quat.multiply(this.rotation, - Quat.inverse(this.oldRotation)); - newRotation = Quat.multiply(newRotation, - this.oldModelRotation); - break; - case 1: - var forward = Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -1 }); - var d = Vec3.dot(forward, MyAvatar.position); - - var factor1 = Vec3.dot(forward, this.positionAtGrab) - d; - var factor2 = Vec3.dot(forward, this.modelPositionAtGrab) - d; - var vector = Vec3.subtract(this.palmPosition, this.positionAtGrab); - - if (factor2 < 0) { - factor2 = 0; - } - if (factor1 <= 0) { - factor1 = 1; - factor2 = 1; - } - - newPosition = Vec3.sum(this.modelPositionAtGrab, - Vec3.multiply(vector, - factor2 / factor1)); - - newRotation = Quat.multiply(this.rotation, - Quat.inverse(this.rotationAtGrab)); - newRotation = Quat.multiply(newRotation, - this.rotationAtGrab); - break; - } - Entities.editEntity(this.entityID, { - position: newPosition, - rotation: newRotation - }); - this.oldModelRotation = newRotation; - this.oldModelPosition = newPosition; - - var indicesToRemove = []; - for (var i = 0; i < this.jointsIntersectingFromStart.length; ++i) { - var distance = Vec3.distance(MyAvatar.getJointPosition(this.jointsIntersectingFromStart[i]), this.oldModelPosition); - if (distance >= this.oldModelHalfDiagonal) { - indicesToRemove.push(this.jointsIntersectingFromStart[i]); - } - - } - for (var i = 0; i < indicesToRemove.length; ++i) { - this.jointsIntersectingFromStart.splice(this.jointsIntersectingFromStart.indexOf(indicesToRemove[i], 1)); - } - } - } - - this.update = function () { - this.oldPalmPosition = this.palmPosition; - this.oldTipPosition = this.tipPosition; - this.palmPosition = Controller.getSpatialControlPosition(this.palm); - this.tipPosition = Controller.getSpatialControlPosition(this.tip); - - this.oldUp = this.up; - this.up = Vec3.normalize(Controller.getSpatialControlNormal(this.palm)); - - this.oldFront = this.front; - this.front = Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)); - - this.oldRight = this.right; - this.right = Vec3.normalize(Vec3.cross(this.front, this.up)); - - this.oldRotation = this.rotation; - this.rotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm)); - - this.triggerValue = Controller.getTriggerValue(this.trigger); - - var bumperValue = Controller.isButtonPressed(this.bumper); - if (bumperValue && !this.bumperValue) { - if (mode == 0) { - mode = 1; - Overlays.editOverlay(leftController.laser, { color: { red: 0, green: 0, blue: 255 } }); - Overlays.editOverlay(rightController.laser, { color: { red: 0, green: 0, blue: 255 } }); - } else { - mode = 0; - Overlays.editOverlay(leftController.laser, { color: { red: 255, green: 0, blue: 0 } }); - Overlays.editOverlay(rightController.laser, { color: { red: 255, green: 0, blue: 0 } }); - } - } - this.bumperValue = bumperValue; - - - this.checkTrigger(); - - this.moveLaser(); - - if (!this.pressed && this.grabbing) { - // release if trigger not pressed anymore. - this.release(); - } - - if (this.pressing) { - // Checking for attachments intersecting - var attachments = MyAvatar.getAttachmentData(); - var attachmentIndex = -1; - var attachmentX = LASER_LENGTH_FACTOR; - - var newModel; - var newProperties; - - for (var i = 0; i < attachments.length; ++i) { - var position = Vec3.sum(MyAvatar.getJointPosition(attachments[i].jointName), - Vec3.multiplyQbyV(MyAvatar.getJointCombinedRotation(attachments[i].jointName), attachments[i].translation)); - var scale = attachments[i].scale; - - var A = this.palmPosition; - var B = this.front; - var P = position; - - var x = Vec3.dot(Vec3.subtract(P, A), B); - var X = Vec3.sum(A, Vec3.multiply(B, x)); - var d = Vec3.length(Vec3.subtract(P, X)); - - if (d < scale / 2.0 && 0 < x && x < attachmentX) { - attachmentIndex = i; - attachmentX = d; - } - } - - if (attachmentIndex != -1) { - print("Detaching: " + attachments[attachmentIndex].modelURL); - MyAvatar.detachOne(attachments[attachmentIndex].modelURL, attachments[attachmentIndex].jointName); - - newProperties = { - type: "Model", - position: Vec3.sum(MyAvatar.getJointPosition(attachments[attachmentIndex].jointName), - Vec3.multiplyQbyV(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName), attachments[attachmentIndex].translation)), - rotation: Quat.multiply(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName), - attachments[attachmentIndex].rotation), - - // TODO: how do we know the correct dimensions for detachment??? - dimensions: { x: attachments[attachmentIndex].scale / 2.0, - y: attachments[attachmentIndex].scale / 2.0, - z: attachments[attachmentIndex].scale / 2.0 }, - - modelURL: attachments[attachmentIndex].modelURL - }; - - newModel = Entities.addEntity(newProperties); - - - } else { - // There is none so ... - // Checking model tree - Vec3.print("Looking at: ", this.palmPosition); - var pickRay = { origin: this.palmPosition, - direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)) }; - var foundIntersection = Entities.findRayIntersection(pickRay); - - if(!foundIntersection.accurate) { - print("No accurate intersection"); - return; - } - newModel = foundIntersection.entityID; - if (!newModel.isKnownID) { - var identify = Entities.identifyEntity(newModel); - if (!identify.isKnownID) { - print("Unknown ID " + identify.id + " (update loop " + newModel.id + ")"); - return; - } - newModel = identify; - } - newProperties = Entities.getEntityProperties(newModel); - } - print("foundEntity.modelURL=" + newProperties.modelURL); - if (isLocked(newProperties)) { - print("Model locked " + newProperties.id); - } else { - var check = this.checkEntity(newProperties); - if (!check.valid) { - return; - } - - this.grab(newModel, newProperties); - - this.x = check.x; - this.y = check.y; - this.z = check.z; - return; - } - } - } - - this.cleanup = function () { - Overlays.deleteOverlay(this.laser); - Overlays.deleteOverlay(this.ball); - Overlays.deleteOverlay(this.leftRight); - Overlays.deleteOverlay(this.topDown); - } -} - -var leftController = new controller(LEFT); -var rightController = new controller(RIGHT); - -function moveEntities() { - if (leftController.grabbing && rightController.grabbing && rightController.entityID.id == leftController.entityID.id) { - var newPosition = leftController.oldModelPosition; - var rotation = leftController.oldModelRotation; - var ratio = 1; - - - switch (mode) { - case 0: - var oldLeftPoint = Vec3.sum(leftController.oldPalmPosition, Vec3.multiply(leftController.oldFront, leftController.x)); - var oldRightPoint = Vec3.sum(rightController.oldPalmPosition, Vec3.multiply(rightController.oldFront, rightController.x)); - - var oldMiddle = Vec3.multiply(Vec3.sum(oldLeftPoint, oldRightPoint), 0.5); - var oldLength = Vec3.length(Vec3.subtract(oldLeftPoint, oldRightPoint)); - - - var leftPoint = Vec3.sum(leftController.palmPosition, Vec3.multiply(leftController.front, leftController.x)); - var rightPoint = Vec3.sum(rightController.palmPosition, Vec3.multiply(rightController.front, rightController.x)); - - var middle = Vec3.multiply(Vec3.sum(leftPoint, rightPoint), 0.5); - var length = Vec3.length(Vec3.subtract(leftPoint, rightPoint)); - - - ratio = length / oldLength; - newPosition = Vec3.sum(middle, - Vec3.multiply(Vec3.subtract(leftController.oldModelPosition, oldMiddle), ratio)); - break; - case 1: - var u = Vec3.normalize(Vec3.subtract(rightController.oldPalmPosition, leftController.oldPalmPosition)); - var v = Vec3.normalize(Vec3.subtract(rightController.palmPosition, leftController.palmPosition)); - - var cos_theta = Vec3.dot(u, v); - if (cos_theta > 1) { - cos_theta = 1; - } - var angle = Math.acos(cos_theta) / Math.PI * 180; - if (angle < 0.1) { - return; - - } - var w = Vec3.normalize(Vec3.cross(u, v)); - - rotation = Quat.multiply(Quat.angleAxis(angle, w), leftController.oldModelRotation); - - - leftController.positionAtGrab = leftController.palmPosition; - leftController.rotationAtGrab = leftController.rotation; - leftController.modelPositionAtGrab = leftController.oldModelPosition; - leftController.rotationAtGrab = rotation; - rightController.positionAtGrab = rightController.palmPosition; - rightController.rotationAtGrab = rightController.rotation; - rightController.modelPositionAtGrab = rightController.oldModelPosition; - rightController.rotationAtGrab = rotation; - break; - } - Entities.editEntity(leftController.entityID, { - position: newPosition, - rotation: rotation, - // TODO: how do we know the correct dimensions for detachment??? - //radius: leftController.oldModelHalfDiagonal * ratio - dimensions: { x: leftController.oldModelHalfDiagonal * ratio, - y: leftController.oldModelHalfDiagonal * ratio, - z: leftController.oldModelHalfDiagonal * ratio } - - - }); - leftController.oldModelPosition = newPosition; - leftController.oldModelRotation = rotation; - leftController.oldModelHalfDiagonal *= ratio; - - rightController.oldModelPosition = newPosition; - rightController.oldModelRotation = rotation; - rightController.oldModelHalfDiagonal *= ratio; - return; - } - leftController.moveEntity(); - rightController.moveEntity(); -} - -var hydraConnected = false; -function checkController(deltaTime) { - var numberOfButtons = Controller.getNumberOfButtons(); - var numberOfTriggers = Controller.getNumberOfTriggers(); - var numberOfSpatialControls = Controller.getNumberOfSpatialControls(); - var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers; - - if (!isActive) { - // So that we hide the lasers bellow and keep updating the overlays position - numberOfButtons = 0; - } - - // this is expected for hydras - if (numberOfButtons == 12 && numberOfTriggers == 2 && controllersPerTrigger == 2) { - if (!hydraConnected) { - hydraConnected = true; - } - - leftController.update(); - rightController.update(); - moveEntities(); - } else { - if (hydraConnected) { - hydraConnected = false; - - leftController.showLaser(false); - rightController.showLaser(false); - } - } - toolBar.move(); - progressDialog.move(); -} - -var entitySelected = false; -var selectedEntityID; -var selectedEntityProperties; -var mouseLastPosition; -var orientation; -var intersection; - - -var SCALE_FACTOR = 200.0; - -function rayPlaneIntersection(pickRay, point, normal) { - var d = -Vec3.dot(point, normal); - var t = -(Vec3.dot(pickRay.origin, normal) + d) / Vec3.dot(pickRay.direction, normal); - - return Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, t)); -} - -function Tooltip() { - this.x = 285; - this.y = 115; - this.width = 500; - this.height = 300; // 145; - this.margin = 5; - this.decimals = 3; - - this.textOverlay = Overlays.addOverlay("text", { - x: this.x, - y: this.y, - width: this.width, - height: this.height, - margin: this.margin, - text: "", - color: { red: 228, green: 228, blue: 228 }, - alpha: 0.8, - backgroundAlpha: 0.8, - visible: false - }); - this.show = function (doShow) { - Overlays.editOverlay(this.textOverlay, { visible: doShow }); - } - this.updateText = function(properties) { - var angles = Quat.safeEulerAngles(properties.rotation); - var text = "Entity Properties:\n" - text += "type: " + properties.type + "\n" - text += "X: " + properties.position.x.toFixed(this.decimals) + "\n" - text += "Y: " + properties.position.y.toFixed(this.decimals) + "\n" - text += "Z: " + properties.position.z.toFixed(this.decimals) + "\n" - text += "Pitch: " + angles.x.toFixed(this.decimals) + "\n" - text += "Yaw: " + angles.y.toFixed(this.decimals) + "\n" - text += "Roll: " + angles.z.toFixed(this.decimals) + "\n" - text += "Dimensions: " + properties.dimensions.x.toFixed(this.decimals) + ", " - + properties.dimensions.y.toFixed(this.decimals) + ", " - + properties.dimensions.z.toFixed(this.decimals) + "\n"; - - text += "Natural Dimensions: " + properties.naturalDimensions.x.toFixed(this.decimals) + ", " - + properties.naturalDimensions.y.toFixed(this.decimals) + ", " - + properties.naturalDimensions.z.toFixed(this.decimals) + "\n"; - - text += "ID: " + properties.id + "\n" - if (properties.type == "Model") { - text += "Model URL: " + properties.modelURL + "\n" - text += "Animation URL: " + properties.animationURL + "\n" - text += "Animation is playing: " + properties.animationIsPlaying + "\n" - if (properties.sittingPoints && properties.sittingPoints.length > 0) { - text += properties.sittingPoints.length + " Sitting points: " - for (var i = 0; i < properties.sittingPoints.length; ++i) { - text += properties.sittingPoints[i].name + " " - } - } else { - text += "No sitting points" + "\n" - } - } - if (properties.lifetime > -1) { - text += "Lifetime: " + properties.lifetime + "\n" - } - text += "Age: " + properties.ageAsText + "\n" - text += "Mass: " + properties.mass + "\n" - text += "Script: " + properties.script + "\n" - - - Overlays.editOverlay(this.textOverlay, { text: text }); - } - - this.cleanup = function () { - Overlays.deleteOverlay(this.textOverlay); - } -} -var tooltip = new Tooltip(); - -function mousePressEvent(event) { - if (event.isAlt) { - return; - } - - mouseLastPosition = { x: event.x, y: event.y }; - entitySelected = false; - var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); - - if (toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event)) { - // Event handled; do nothing. - return; - } else { - // If we aren't active and didn't click on an overlay: quit - if (!isActive) { - return; - } - - var pickRay = Camera.computePickRay(event.x, event.y); - Vec3.print("[Mouse] Looking at: ", pickRay.origin); - var foundIntersection = Entities.findRayIntersection(pickRay, true); // we want precision picking here - - if(!foundIntersection.accurate) { - return; - } - var foundEntity = foundIntersection.entityID; - - if (!foundEntity.isKnownID) { - var identify = Entities.identifyEntity(foundEntity); - if (!identify.isKnownID) { - print("Unknown ID " + identify.id + " (update loop " + foundEntity.id + ")"); - return; - } - foundEntity = identify; - } - - var properties = Entities.getEntityProperties(foundEntity); - if (isLocked(properties)) { - print("Model locked " + properties.id); - } else { - var halfDiagonal = Vec3.length(properties.dimensions) / 2.0; - - print("Checking properties: " + properties.id + " " + properties.isKnownID + " - Half Diagonal:" + halfDiagonal); - // P P - Model - // /| A - Palm - // / | d B - unit vector toward tip - // / | X - base of the perpendicular line - // A---X----->B d - distance fom axis - // x x - distance from A - // - // |X-A| = (P-A).B - // X == A + ((P-A).B)B - // d = |P-X| - - var A = pickRay.origin; - var B = Vec3.normalize(pickRay.direction); - var P = properties.position; - - var x = Vec3.dot(Vec3.subtract(P, A), B); - var X = Vec3.sum(A, Vec3.multiply(B, x)); - var d = Vec3.length(Vec3.subtract(P, X)); - var halfDiagonal = Vec3.length(properties.dimensions) / 2.0; - - var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14; - - var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) - && (allowSmallModels || angularSize > MIN_ANGULAR_SIZE); - - if (0 < x && sizeOK) { - entitySelected = true; - selectedEntityID = foundEntity; - selectedEntityProperties = properties; - orientation = MyAvatar.orientation; - intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation)); - } - } - } - if (entitySelected) { - selectedEntityProperties.oldDimensions = selectedEntityProperties.dimensions; - selectedEntityProperties.oldPosition = { - x: selectedEntityProperties.position.x, - y: selectedEntityProperties.position.y, - z: selectedEntityProperties.position.z, - }; - selectedEntityProperties.oldRotation = { - x: selectedEntityProperties.rotation.x, - y: selectedEntityProperties.rotation.y, - z: selectedEntityProperties.rotation.z, - w: selectedEntityProperties.rotation.w, - }; - selectedEntityProperties.glowLevel = 0.0; - - print("Clicked on " + selectedEntityID.id + " " + entitySelected); - tooltip.updateText(selectedEntityProperties); - tooltip.show(true); - } -} - -var glowedEntityID = { id: -1, isKnownID: false }; -var oldModifier = 0; -var modifier = 0; -var wasShifted = false; -function mouseMoveEvent(event) { - if (event.isAlt || !isActive) { - return; - } - - var pickRay = Camera.computePickRay(event.x, event.y); - if (!entitySelected) { - var entityIntersection = Entities.findRayIntersection(pickRay); - if (entityIntersection.accurate) { - if(glowedEntityID.isKnownID && glowedEntityID.id != entityIntersection.entityID.id) { - Entities.editEntity(glowedEntityID, { glowLevel: 0.0 }); - glowedEntityID.id = -1; - glowedEntityID.isKnownID = false; - } - - var halfDiagonal = Vec3.length(entityIntersection.properties.dimensions) / 2.0; - - var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), - entityIntersection.properties.position)) * 180 / 3.14; - - var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) - && (allowSmallModels || angularSize > MIN_ANGULAR_SIZE); - - if (entityIntersection.entityID.isKnownID && sizeOK) { - if (wantEntityGlow) { - Entities.editEntity(entityIntersection.entityID, { glowLevel: 0.25 }); - } - glowedEntityID = entityIntersection.entityID; - } - - } - return; - } - - if (event.isLeftButton) { - if (event.isRightButton) { - modifier = 1; // Scale - } else { - modifier = 2; // Translate - } - } else if (event.isRightButton) { - modifier = 3; // rotate - } else { - modifier = 0; - } - pickRay = Camera.computePickRay(event.x, event.y); - if (wasShifted != event.isShifted || modifier != oldModifier) { - selectedEntityProperties.oldDimensions = selectedEntityProperties.dimensions; - - selectedEntityProperties.oldPosition = { - x: selectedEntityProperties.position.x, - y: selectedEntityProperties.position.y, - z: selectedEntityProperties.position.z, - }; - selectedEntityProperties.oldRotation = { - x: selectedEntityProperties.rotation.x, - y: selectedEntityProperties.rotation.y, - z: selectedEntityProperties.rotation.z, - w: selectedEntityProperties.rotation.w, - }; - orientation = MyAvatar.orientation; - intersection = rayPlaneIntersection(pickRay, - selectedEntityProperties.oldPosition, - Quat.getFront(orientation)); - - mouseLastPosition = { x: event.x, y: event.y }; - wasShifted = event.isShifted; - oldModifier = modifier; - return; - } - - - switch (modifier) { - case 0: - return; - case 1: - // Let's Scale - selectedEntityProperties.dimensions = Vec3.multiply(selectedEntityProperties.dimensions, - (1.0 + (mouseLastPosition.y - event.y) / SCALE_FACTOR)); - - var halfDiagonal = Vec3.length(selectedEntityProperties.dimensions) / 2.0; - - if (halfDiagonal < 0.01) { - print("Scale too small ... bailling."); - return; - } - break; - - case 2: - // Let's translate - var newIntersection = rayPlaneIntersection(pickRay, - selectedEntityProperties.oldPosition, - Quat.getFront(orientation)); - var vector = Vec3.subtract(newIntersection, intersection) - if (event.isShifted) { - var i = Vec3.dot(vector, Quat.getRight(orientation)); - var j = Vec3.dot(vector, Quat.getUp(orientation)); - vector = Vec3.sum(Vec3.multiply(Quat.getRight(orientation), i), - Vec3.multiply(Quat.getFront(orientation), j)); - } - selectedEntityProperties.position = Vec3.sum(selectedEntityProperties.oldPosition, vector); - break; - case 3: - // Let's rotate - if (somethingChanged) { - selectedEntityProperties.oldRotation.x = selectedEntityProperties.rotation.x; - selectedEntityProperties.oldRotation.y = selectedEntityProperties.rotation.y; - selectedEntityProperties.oldRotation.z = selectedEntityProperties.rotation.z; - selectedEntityProperties.oldRotation.w = selectedEntityProperties.rotation.w; - mouseLastPosition.x = event.x; - mouseLastPosition.y = event.y; - somethingChanged = false; - } - - - var pixelPerDegrees = windowDimensions.y / (1 * 360); // the entire height of the window allow you to make 2 full rotations - - //compute delta in pixel - var cameraForward = Quat.getFront(Camera.getOrientation()); - var rotationAxis = (!zIsPressed && xIsPressed) ? { x: 1, y: 0, z: 0 } : - (!zIsPressed && !xIsPressed) ? { x: 0, y: 1, z: 0 } : - { x: 0, y: 0, z: 1 }; - rotationAxis = Vec3.multiplyQbyV(selectedEntityProperties.rotation, rotationAxis); - var orthogonalAxis = Vec3.cross(cameraForward, rotationAxis); - var mouseDelta = { x: event.x - mouseLastPosition - .x, y: mouseLastPosition.y - event.y, z: 0 }; - var transformedMouseDelta = Vec3.multiplyQbyV(Camera.getOrientation(), mouseDelta); - var delta = Math.floor(Vec3.dot(transformedMouseDelta, Vec3.normalize(orthogonalAxis)) / pixelPerDegrees); - - var STEP = 15; - if (!event.isShifted) { - delta = Math.round(delta / STEP) * STEP; - } - - var rotation = Quat.fromVec3Degrees({ - x: (!zIsPressed && xIsPressed) ? delta : 0, // x is pressed - y: (!zIsPressed && !xIsPressed) ? delta : 0, // neither is pressed - z: (zIsPressed && !xIsPressed) ? delta : 0 // z is pressed - }); - rotation = Quat.multiply(selectedEntityProperties.oldRotation, rotation); - - selectedEntityProperties.rotation.x = rotation.x; - selectedEntityProperties.rotation.y = rotation.y; - selectedEntityProperties.rotation.z = rotation.z; - selectedEntityProperties.rotation.w = rotation.w; - break; - } - - Entities.editEntity(selectedEntityID, selectedEntityProperties); - tooltip.updateText(selectedEntityProperties); -} - - -function mouseReleaseEvent(event) { - if (event.isAlt || !isActive) { - return; - } - if (entitySelected) { - tooltip.show(false); - } - - entitySelected = false; - - glowedEntityID.id = -1; - glowedEntityID.isKnownID = false; -} - -// In order for editVoxels and editModels to play nice together, they each check to see if a "delete" menu item already -// exists. If it doesn't they add it. If it does they don't. They also only delete the menu item if they were the one that -// added it. -var modelMenuAddedDelete = false; -var originalLightsArePickable = Entities.getLightsArePickable(); -function setupModelMenus() { - print("setupModelMenus()"); - // adj our menuitems - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Models", isSeparator: true, beforeItem: "Physics" }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Edit Properties...", - shortcutKeyEvent: { text: "`" }, afterItem: "Models" }); - if (!Menu.menuItemExists("Edit", "Delete")) { - print("no delete... adding ours"); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete", - shortcutKeyEvent: { text: "backspace" }, afterItem: "Models" }); - modelMenuAddedDelete = true; - } else { - print("delete exists... don't add ours"); - } - - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Model List...", afterItem: "Models" }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Edit Properties..." }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Large Models", shortcutKey: "CTRL+META+L", - afterItem: "Paste Models", isCheckable: true }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Small Models", shortcutKey: "CTRL+META+S", - afterItem: "Allow Selecting of Large Models", isCheckable: true }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Lights", shortcutKey: "CTRL+SHIFT+META+L", - afterItem: "Allow Selecting of Small Models", isCheckable: true }); - - Menu.addMenuItem({ menuName: "File", menuItemName: "Models", isSeparator: true, beforeItem: "Settings" }); - Menu.addMenuItem({ menuName: "File", menuItemName: "Export Models", shortcutKey: "CTRL+META+E", afterItem: "Models" }); - Menu.addMenuItem({ menuName: "File", menuItemName: "Import Models", shortcutKey: "CTRL+META+I", afterItem: "Export Models" }); - - Entities.setLightsArePickable(false); - -} - -function cleanupModelMenus() { - Menu.removeSeparator("Edit", "Models"); - Menu.removeMenuItem("Edit", "Edit Properties..."); - if (modelMenuAddedDelete) { - // delete our menuitems - Menu.removeMenuItem("Edit", "Delete"); - } - - Menu.removeMenuItem("Edit", "Model List..."); - Menu.removeMenuItem("Edit", "Paste Models"); - Menu.removeMenuItem("Edit", "Allow Selecting of Large Models"); - Menu.removeMenuItem("Edit", "Allow Selecting of Small Models"); - Menu.removeMenuItem("Edit", "Allow Selecting of Lights"); - - Menu.removeSeparator("File", "Models"); - Menu.removeMenuItem("File", "Export Models"); - Menu.removeMenuItem("File", "Import Models"); -} - -function scriptEnding() { - leftController.cleanup(); - rightController.cleanup(); - progressDialog.cleanup(); - toolBar.cleanup(); - cleanupModelMenus(); - tooltip.cleanup(); - modelImporter.cleanup(); - if (exportMenu) { - exportMenu.close(); - } - Entities.setLightsArePickable(originalLightsArePickable); -} -Script.scriptEnding.connect(scriptEnding); - -// register the call back so it fires before each data send -Script.update.connect(checkController); -Controller.mousePressEvent.connect(mousePressEvent); -Controller.mouseMoveEvent.connect(mouseMoveEvent); -Controller.mouseReleaseEvent.connect(mouseReleaseEvent); - -setupModelMenus(); - -var propertiesForEditedEntity; -var editEntityFormArray; -var editModelID = -1; -var dimensionX; -var dimensionY; -var dimensionZ; -var rescalePercentage; - -function showPropertiesForm(editModelID) { - entityPropertyDialogBox.openDialog(editModelID); -} - -function handeMenuEvent(menuItem) { - print("menuItemEvent() in JS... menuItem=" + menuItem); - if (menuItem == "Allow Selecting of Small Models") { - allowSmallModels = Menu.isOptionChecked("Allow Selecting of Small Models"); - } else if (menuItem == "Allow Selecting of Large Models") { - allowLargeModels = Menu.isOptionChecked("Allow Selecting of Large Models"); - } else if (menuItem == "Allow Selecting of Lights") { - Entities.setLightsArePickable(Menu.isOptionChecked("Allow Selecting of Lights")); - } else if (menuItem == "Delete") { - if (leftController.grabbing) { - print(" Delete Entity.... leftController.entityID="+ leftController.entityID); - Entities.deleteEntity(leftController.entityID); - leftController.grabbing = false; - if (glowedEntityID.id == leftController.entityID.id) { - glowedEntityID = { id: -1, isKnownID: false }; - } - } else if (rightController.grabbing) { - print(" Delete Entity.... rightController.entityID="+ rightController.entityID); - Entities.deleteEntity(rightController.entityID); - rightController.grabbing = false; - if (glowedEntityID.id == rightController.entityID.id) { - glowedEntityID = { id: -1, isKnownID: false }; - } - } else if (entitySelected) { - print(" Delete Entity.... selectedEntityID="+ selectedEntityID); - Entities.deleteEntity(selectedEntityID); - entitySelected = false; - if (glowedEntityID.id == selectedEntityID.id) { - glowedEntityID = { id: -1, isKnownID: false }; - } - } else { - print(" Delete Entity.... not holding..."); - } - } else if (menuItem == "Model List...") { - var models = new Array(); - models = Entities.findEntities(MyAvatar.position, Number.MAX_VALUE); - for (var i = 0; i < models.length; i++) { - models[i].properties = Entities.getEntityProperties(models[i]); - models[i].toString = function() { - var modelname; - if (this.properties.type == "Model") { - modelname = decodeURIComponent( - this.properties.modelURL.indexOf("/") != -1 ? - this.properties.modelURL.substring(this.properties.modelURL.lastIndexOf("/") + 1) : - this.properties.modelURL); - } else { - modelname = this.properties.id; - } - return "[" + this.properties.type + "] " + modelname; - }; - } - var form = [{label: "Model: ", options: models}]; - form.push({label: "Action: ", options: ["Properties", "Delete", "Teleport"]}); - form.push({ button: "Cancel" }); - if (Window.form("Model List", form)) { - var selectedModel = form[0].value; - if (form[1].value == "Properties") { - editModelID = selectedModel; - showPropertiesForm(editModelID); - } else if (form[1].value == "Delete") { - Entities.deleteEntity(selectedModel); - } else if (form[1].value == "Teleport") { - MyAvatar.position = selectedModel.properties.position; - } - } - } else if (menuItem == "Edit Properties...") { - editModelID = -1; - if (leftController.grabbing) { - print(" Edit Properties.... leftController.entityID="+ leftController.entityID); - editModelID = leftController.entityID; - } else if (rightController.grabbing) { - print(" Edit Properties.... rightController.entityID="+ rightController.entityID); - editModelID = rightController.entityID; - } else if (entitySelected) { - print(" Edit Properties.... selectedEntityID="+ selectedEntityID); - editModelID = selectedEntityID; - } else { - print(" Edit Properties.... not holding..."); - } - if (editModelID != -1) { - print(" Edit Properties.... about to edit properties..."); - showPropertiesForm(editModelID); - } - } else if (menuItem == "Paste Models") { - modelImporter.paste(); - } else if (menuItem == "Export Models") { - if (!exportMenu) { - exportMenu = new ExportMenu({ - onClose: function () { - exportMenu = null; - } - }); - } - } else if (menuItem == "Import Models") { - modelImporter.doImport(); - } - tooltip.show(false); -} -Menu.menuItemEvent.connect(handeMenuEvent); - - - -// handling of inspect.js concurrence -var zIsPressed = false; -var xIsPressed = false; -var somethingChanged = false; -Controller.keyPressEvent.connect(function (event) { - if ((event.text == "z" || event.text == "Z") && !zIsPressed) { - zIsPressed = true; - somethingChanged = true; - } - if ((event.text == "x" || event.text == "X") && !xIsPressed) { - xIsPressed = true; - somethingChanged = true; - } - - // resets model orientation when holding with mouse - if (event.text == "r" && entitySelected) { - selectedEntityProperties.rotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 0 }); - Entities.editEntity(selectedEntityID, selectedEntityProperties); - tooltip.updateText(selectedEntityProperties); - somethingChanged = true; - } -}); - -Controller.keyReleaseEvent.connect(function (event) { - if (event.text == "z" || event.text == "Z") { - zIsPressed = false; - somethingChanged = true; - } - if (event.text == "x" || event.text == "X") { - xIsPressed = false; - somethingChanged = true; - } - // since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items - if (event.text == "`") { - handeMenuEvent("Edit Properties..."); - } - if (event.text == "BACKSPACE") { - handeMenuEvent("Delete"); - } -}); - From 4946ec18b6be68b73d88ce41013498244b74ef4c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 9 Jan 2015 09:28:01 -0800 Subject: [PATCH 04/51] remove some TODO comments --- libraries/entities/src/EntityItem.cpp | 1 - libraries/physics/src/ObjectMotionState.cpp | 2 -- libraries/physics/src/ObjectMotionState.h | 2 +- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index a744d39f05..48ceed863e 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1015,7 +1015,6 @@ void EntityItem::recalculateCollisionShape() { entityAACube.scale(TREE_SCALE); // scale to meters _collisionShape.setTranslation(entityAACube.calcCenter()); _collisionShape.setScale(entityAACube.getScale()); - // TODO: use motionState to update physics object } const float MIN_POSITION_DELTA = 0.0001f; diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index f8f0712d5e..46c67c0ec2 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -154,8 +154,6 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame, float subStep // NOTE: math in done the simulation-frame, which is NOT necessarily the same as the world-frame // due to _worldOffset. - // TODO: Andrew to reconcile Bullet and legacy damping coefficients. - // compute position error if (glm::length2(_sentVelocity) > 0.0f) { _sentVelocity += _sentAcceleration * dt; diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index c0d3d2cabf..cb19babc1d 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -111,7 +111,7 @@ protected: glm::vec3 _sentPosition; // in simulation-frame (not world-frame) glm::quat _sentRotation;; glm::vec3 _sentVelocity; - glm::vec3 _sentAngularVelocity; + glm::vec3 _sentAngularVelocity; // radians per second glm::vec3 _sentAcceleration; }; From 8d8352946b9d5b271477f4e1e81271dfaddc5211 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 9 Jan 2015 10:01:58 -0800 Subject: [PATCH 05/51] Add rescale button to edit properties window --- examples/editEntities.js | 13 +++++++++++++ examples/html/entityProperties.html | 15 +++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/examples/editEntities.js b/examples/editEntities.js index b65756e9b4..2462c30854 100644 --- a/examples/editEntities.js +++ b/examples/editEntities.js @@ -1077,6 +1077,19 @@ PropertiesTool = function(opts) { pushCommandForSelections(); selectionManager._update(); } + } else if (data.action == "rescaleDimensions") { + var multiplier = data.percentage / 100; + if (selectionManager.hasSelection()) { + selectionManager.saveProperties(); + for (var i = 0; i < selectionManager.selections.length; i++) { + var properties = selectionManager.savedProperties[selectionManager.selections[i].id]; + Entities.editEntity(selectionManager.selections[i], { + dimensions: Vec3.multiply(multiplier, properties.dimensions), + }); + } + pushCommandForSelections(); + selectionManager._update(); + } } } }); diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index a3644d8c3d..d7f097966a 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -84,6 +84,8 @@ var elDimensionsY = document.getElementById("property-dim-y"); var elDimensionsZ = document.getElementById("property-dim-z"); var elResetToNaturalDimensions = document.getElementById("reset-to-natural-dimensions"); + var elRescaleDimensionsPct = document.getElementById("dimension-rescale-pct"); + var elRescaleDimensionsButton = document.getElementById("dimension-rescale-button"); var elRegistrationX = document.getElementById("property-reg-x"); var elRegistrationY = document.getElementById("property-reg-y"); @@ -419,6 +421,13 @@ action: "resetToNaturalDimensions", })); }); + elRescaleDimensionsButton.addEventListener("click", function() { + EventBridge.emitWebEvent(JSON.stringify({ + type: "action", + action: "rescaleDimensions", + percentage: parseInt(elRescaleDimensionsPct.value), + })); + }); var resizing = false; @@ -537,6 +546,12 @@
+
+ % +
+ + + From 05d2887c9491e1fcdf640db8d4c9e2ccb85a0e9d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 9 Jan 2015 11:15:01 -0800 Subject: [PATCH 06/51] Move Torso twist to HeadData with Lean --- interface/src/avatar/Head.cpp | 1 - interface/src/avatar/Head.h | 5 ----- libraries/avatars/src/HeadData.cpp | 1 + libraries/avatars/src/HeadData.h | 3 +++ 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 32594a7225..296b4ab68a 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -54,7 +54,6 @@ Head::Head(Avatar* owningAvatar) : _deltaRoll(0.0f), _deltaLeanSideways(0.0f), _deltaLeanForward(0.0f), - _torsoTwist(0.0f), _isCameraMoving(false), _isLookingAtMe(false), _faceModel(this), diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index dece0a8565..255ea823e9 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -76,9 +76,6 @@ public: float getFinalLeanSideways() const { return _leanSideways + _deltaLeanSideways; } float getFinalLeanForward() const { return _leanForward + _deltaLeanForward; } - float getTorsoTwist() const { return _torsoTwist; } - void setTorsoTwist(float torsoTwist) { _torsoTwist = torsoTwist; } - glm::quat getEyeRotation(const glm::vec3& eyePosition) const; const glm::vec3& getRightEyePosition() const { return _rightEyePosition; } @@ -151,8 +148,6 @@ private: // delta lean angles for lean perturbations (driven by collisions) float _deltaLeanSideways; float _deltaLeanForward; - - float _torsoTwist; bool _isCameraMoving; bool _isLookingAtMe; diff --git a/libraries/avatars/src/HeadData.cpp b/libraries/avatars/src/HeadData.cpp index 511ab50c11..5bf33d1153 100644 --- a/libraries/avatars/src/HeadData.cpp +++ b/libraries/avatars/src/HeadData.cpp @@ -24,6 +24,7 @@ HeadData::HeadData(AvatarData* owningAvatar) : _baseRoll(0.0f), _leanSideways(0.0f), _leanForward(0.0f), + _torsoTwist(0.0f), _lookAtPosition(0.0f, 0.0f, 0.0f), _audioLoudness(0.0f), _isFaceshiftConnected(false), diff --git a/libraries/avatars/src/HeadData.h b/libraries/avatars/src/HeadData.h index 3a4eb3c808..cef5d5fbca 100644 --- a/libraries/avatars/src/HeadData.h +++ b/libraries/avatars/src/HeadData.h @@ -71,11 +71,13 @@ public: float getLeanSideways() const { return _leanSideways; } float getLeanForward() const { return _leanForward; } + float getTorsoTwist() const { return _torsoTwist; } virtual float getFinalLeanSideways() const { return _leanSideways; } virtual float getFinalLeanForward() const { return _leanForward; } void setLeanSideways(float leanSideways) { _leanSideways = leanSideways; } void setLeanForward(float leanForward) { _leanForward = leanForward; } + void setTorsoTwist(float torsoTwist) { _torsoTwist = torsoTwist; } friend class AvatarData; @@ -86,6 +88,7 @@ protected: float _baseRoll; float _leanSideways; float _leanForward; + float _torsoTwist; glm::vec3 _lookAtPosition; float _audioLoudness; From 16e1fc8c3a5f7d042574a195e8851aed3d45ae92 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 9 Jan 2015 11:16:05 -0800 Subject: [PATCH 07/51] Added isMyAvatar to AvatarData too --- libraries/avatars/src/AvatarData.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 84653ef673..a429a7af93 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -152,6 +152,8 @@ class AvatarData : public QObject { public: AvatarData(); virtual ~AvatarData(); + + virtual bool isMyAvatar() { return false; } const QUuid& getSessionUUID() const { return _sessionUUID; } From f2b7cb005a4b546482016d535194d5f9be3ade09 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 9 Jan 2015 11:16:49 -0800 Subject: [PATCH 08/51] Removed leans/Changed Head rotation in avatardata packets --- libraries/avatars/src/AvatarData.cpp | 50 ++++++++++------------------ 1 file changed, 17 insertions(+), 33 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index cc45da610f..22976be715 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -158,15 +158,18 @@ QByteArray AvatarData::toByteArray() { destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _targetScale); // Head rotation (NOTE: This needs to become a quaternion to save two bytes) - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getFinalYaw()); - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getFinalPitch()); - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getFinalRoll()); - - // Head lean X,Z (head lateral and fwd/back motion relative to torso) - memcpy(destinationBuffer, &_headData->_leanSideways, sizeof(_headData->_leanSideways)); - destinationBuffer += sizeof(_headData->_leanSideways); - memcpy(destinationBuffer, &_headData->_leanForward, sizeof(_headData->_leanForward)); - destinationBuffer += sizeof(_headData->_leanForward); + glm::vec3 pitchYawRoll = glm::vec3(_headData->getFinalPitch(), + _headData->getFinalYaw(), + _headData->getFinalRoll()); + if (this->isMyAvatar()) { + glm::vec3 lean = glm::radians(glm::vec3(_headData->getFinalLeanForward(), + _headData->getTorsoTwist(), + _headData->getFinalLeanSideways())); + pitchYawRoll -= lean; + } + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, pitchYawRoll.x); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, pitchYawRoll.y); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, pitchYawRoll.z); // Lookat Position memcpy(destinationBuffer, &_headData->_lookAtPosition, sizeof(_headData->_lookAtPosition)); @@ -287,18 +290,16 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { // bodyPitch = 2 (compressed float) // bodyRoll = 2 (compressed float) // targetScale = 2 (compressed float) - // headYaw = 2 (compressed float) // headPitch = 2 (compressed float) + // headYaw = 2 (compressed float) // headRoll = 2 (compressed float) - // leanSideways = 4 - // leanForward = 4 // lookAt = 12 // audioLoudness = 4 // } // + 1 byte for pupilSize // + 1 byte for numJoints (0) - // = 53 bytes - int minPossibleSize = 52; + // = 45 bytes + int minPossibleSize = 45; int maxAvailableSize = packet.size() - offset; if (minPossibleSize > maxAvailableSize) { @@ -356,8 +357,8 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { { // Head rotation //(NOTE: This needs to become a quaternion to save two bytes) float headYaw, headPitch, headRoll; - sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headYaw); sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headPitch); + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headYaw); sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headRoll); if (glm::isnan(headYaw) || glm::isnan(headPitch) || glm::isnan(headRoll)) { if (shouldLogError(now)) { @@ -365,27 +366,10 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { } return maxAvailableSize; } - _headData->setBaseYaw(headYaw); _headData->setBasePitch(headPitch); + _headData->setBaseYaw(headYaw); _headData->setBaseRoll(headRoll); } // 6 bytes - - // Head lean (relative to pelvis) - { - float leanSideways, leanForward; - memcpy(&leanSideways, sourceBuffer, sizeof(float)); - sourceBuffer += sizeof(float); - memcpy(&leanForward, sourceBuffer, sizeof(float)); - sourceBuffer += sizeof(float); - if (glm::isnan(leanSideways) || glm::isnan(leanForward)) { - if (shouldLogError(now)) { - qDebug() << "Discard nan AvatarData::leanSideways,leanForward; displayName = '" << _displayName << "'"; - } - return maxAvailableSize; - } - _headData->_leanSideways = leanSideways; - _headData->_leanForward = leanForward; - } // 8 bytes { // Lookat Position glm::vec3 lookAt; From 02b9aaacf829c1a2e11f8b99e5f3382a9fc457a0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 9 Jan 2015 11:16:58 -0800 Subject: [PATCH 09/51] Bump packet version --- libraries/networking/src/PacketHeaders.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index f2c292b528..54368b1423 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -57,7 +57,7 @@ PacketVersion versionForPacketType(PacketType type) { case PacketTypeInjectAudio: return 1; case PacketTypeAvatarData: - return 4; + return 5; case PacketTypeAvatarIdentity: return 1; case PacketTypeEnvironmentData: From 063e95bd79b1502351c13e29f169fbac0484c0a9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 9 Jan 2015 14:31:34 -0800 Subject: [PATCH 10/51] Clement doesn't know how to use radians --- libraries/avatars/src/AvatarData.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 22976be715..d2108c79e2 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -162,9 +162,9 @@ QByteArray AvatarData::toByteArray() { _headData->getFinalYaw(), _headData->getFinalRoll()); if (this->isMyAvatar()) { - glm::vec3 lean = glm::radians(glm::vec3(_headData->getFinalLeanForward(), - _headData->getTorsoTwist(), - _headData->getFinalLeanSideways())); + glm::vec3 lean = glm::vec3(_headData->getFinalLeanForward(), + _headData->getTorsoTwist(), + _headData->getFinalLeanSideways()); pitchYawRoll -= lean; } destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, pitchYawRoll.x); From 6d67b8e20c54505a61164cd5bf5f107a5bfc7447 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 9 Jan 2015 15:32:08 -0800 Subject: [PATCH 11/51] Don't call delete later unless you have to --- libraries/shared/src/DependencyManager.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/DependencyManager.h b/libraries/shared/src/DependencyManager.h index fdf8030199..2ccbe18dd8 100644 --- a/libraries/shared/src/DependencyManager.h +++ b/libraries/shared/src/DependencyManager.h @@ -13,6 +13,7 @@ #define hifi_DependencyManager_h #include +#include #include @@ -22,10 +23,12 @@ public:\ private:\ void customDeleter() {\ QObject* thisObject = dynamic_cast(this);\ - if (thisObject) {\ + if (thisObject && thisObject->parent()) {\ thisObject->deleteLater();\ + qDebug() << "Delete later:" << #T;\ } else {\ delete this;\ + qDebug() << "Deleted:" << #T;\ }\ }\ friend class DependencyManager; From e00b629133fa26c6454746b3c5d2622ba75e5d48 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 9 Jan 2015 16:11:17 -0800 Subject: [PATCH 12/51] Fix gl projection matrix stack overflow when rendering to HUD The projection matrix stack is considerably smaller than the modelview stack and was overflowing on Windows and Linux machines that were tested. --- interface/src/ui/ApplicationOverlay.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 1d710f29d4..106c74cdeb 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -197,19 +197,23 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { const float FAR_CLIP = 10000; glLoadIdentity(); glOrtho(0, glCanvas->width(), glCanvas->height(), 0, NEAR_CLIP, FAR_CLIP); - + + glMatrixMode(GL_MODELVIEW); + renderAudioMeter(); - + renderStatsAndLogs(); - + // give external parties a change to hook in emit application->renderingOverlay(); - + overlays.renderHUD(); - + renderPointers(); - + renderDomainConnectionStatusBorder(); + + glMatrixMode(GL_PROJECTION); } glPopMatrix(); glMatrixMode(GL_MODELVIEW); From 58b965c9a2b97eba1d8f3e6b022f1d4c9a1b673b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 9 Jan 2015 16:12:43 -0800 Subject: [PATCH 13/51] lock Octree higher when extracting things from bag --- assignment-client/src/octree/OctreeSendThread.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index ae34d54198..f0b4170cc6 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -404,6 +404,13 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus bool lastNodeDidntFit = false; // assume each node fits if (!nodeData->elementBag.isEmpty()) { + + quint64 lockWaitStart = usecTimestampNow(); + _myServer->getOctree()->lockForRead(); + quint64 lockWaitEnd = usecTimestampNow(); + lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); + quint64 encodeStart = usecTimestampNow(); + OctreeElement* subTree = nodeData->elementBag.extract(); /* TODO: Looking for a way to prevent locking and encoding a tree that is not @@ -447,12 +454,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // it seems like it may be a good idea to include the lock time as part of the encode time // are reported to client. Since you can encode without the lock nodeData->stats.encodeStarted(); - - quint64 lockWaitStart = usecTimestampNow(); - _myServer->getOctree()->lockForRead(); - quint64 lockWaitEnd = usecTimestampNow(); - lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); - quint64 encodeStart = usecTimestampNow(); bytesWritten = _myServer->getOctree()->encodeTreeBitstream(subTree, &_packetData, nodeData->elementBag, params); From 8bb69d0a9085256a82665ce09ab66c5bff992860 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 9 Jan 2015 16:22:52 -0800 Subject: [PATCH 14/51] Update std::string instances to QString --- interface/CMakeLists.txt | 2 +- libraries/entities/src/EntityTreeElement.cpp | 2 +- libraries/fbx/src/FBXReader.cpp | 90 ++++++++++---------- libraries/fbx/src/FBXReader.h | 2 +- libraries/render-utils/src/GeometryCache.cpp | 4 +- 5 files changed, 50 insertions(+), 50 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 8ddd1153ef..77a20201cb 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -2,7 +2,7 @@ set(TARGET_NAME interface) project(${TARGET_NAME}) # set a default root dir for each of our optional externals if it was not passed -set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "PrioVR" "Sixense" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "Gverb") +set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "PrioVR" "Sixense" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "Gverb" "Visage") foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE) if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR) diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 5f072164a0..a7e7b6fdb3 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -665,7 +665,7 @@ const EntityItem* EntityTreeElement::getEntityWithEntityItemID(const EntityItemI } return foundEntity; } - + EntityItem* EntityTreeElement::getEntityWithEntityItemID(const EntityItemID& id) { EntityItem* foundEntity = NULL; uint16_t numberOfEntities = _entityItems->size(); diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 9532f44acf..8363084d37 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -38,7 +38,7 @@ struct TextureParam { glm::vec2 UVTranslation; glm::vec2 UVScaling; glm::vec4 cropping; - std::string UVSet; + QString UVSet; glm::vec3 translation; glm::vec3 rotation; @@ -802,14 +802,14 @@ public: QVector > blendshapeIndexMaps; QVector > partMaterialTextures; QHash texcoordSetMap; - std::map texcoordSetMap2; + std::map texcoordSetMap2; }; class AttributeData { public: QVector texCoords; QVector texCoordIndices; - std::string name; + QString name; int index; }; @@ -945,12 +945,12 @@ ExtractedMesh extractMesh(const FBXNode& object) { data.texCoordIndices = getIntVector(subdata); attrib.texCoordIndices = getIntVector(subdata); } else if (subdata.name == "Name") { - attrib.name = subdata.properties.at(0).toString().toStdString(); + attrib.name = subdata.properties.at(0).toString(); } #if defined(DEBUG_FBXREADER) else { int unknown = 0; - std::string subname = subdata.name.data(); + QString subname = subdata.name.data(); if ( (subdata.name == "Version") || (subdata.name == "MappingInformationType") || (subdata.name == "ReferenceInformationType") ) { @@ -960,7 +960,7 @@ ExtractedMesh extractMesh(const FBXNode& object) { } #endif } - data.extracted.texcoordSetMap.insert(QString(attrib.name.c_str()), data.attributes.size()); + data.extracted.texcoordSetMap.insert(attrib.name, data.attributes.size()); data.attributes.push_back(attrib); } else { AttributeData attrib; @@ -971,12 +971,12 @@ ExtractedMesh extractMesh(const FBXNode& object) { } else if (subdata.name == "UVIndex") { attrib.texCoordIndices = getIntVector(subdata); } else if (subdata.name == "Name") { - attrib.name = subdata.properties.at(0).toString().toStdString(); + attrib.name = subdata.properties.at(0).toString(); } #if defined(DEBUG_FBXREADER) else { int unknown = 0; - std::string subname = subdata.name.data(); + QString subname = subdata.name.data(); if ( (subdata.name == "Version") || (subdata.name == "MappingInformationType") || (subdata.name == "ReferenceInformationType") ) { @@ -987,9 +987,9 @@ ExtractedMesh extractMesh(const FBXNode& object) { #endif } - QHash::iterator it = data.extracted.texcoordSetMap.find(QString(attrib.name.c_str())); + QHash::iterator it = data.extracted.texcoordSetMap.find(attrib.name); if (it == data.extracted.texcoordSetMap.end()) { - data.extracted.texcoordSetMap.insert(QString(attrib.name.c_str()), data.attributes.size()); + data.extracted.texcoordSetMap.insert(attrib.name, data.attributes.size()); data.attributes.push_back(attrib); } else { // WTF same names for different UVs? @@ -1198,11 +1198,11 @@ bool checkMaterialsHaveTextures(const QHash& materials, return false; } -int matchTextureUVSetToAttributeChannel(const std::string& texUVSetName, const QHash& texcoordChannels) { - if (texUVSetName.empty()) { +int matchTextureUVSetToAttributeChannel(const QString& texUVSetName, const QHash& texcoordChannels) { + if (texUVSetName.isEmpty()) { return 0; } else { - QHash::const_iterator tcUnit = texcoordChannels.find(QString(texUVSetName.c_str())); + QHash::const_iterator tcUnit = texcoordChannels.find(texUVSetName); if (tcUnit != texcoordChannels.end()) { int channel = (*tcUnit); if (channel >= 2) { @@ -1220,13 +1220,13 @@ FBXLight extractLight(const FBXNode& object) { FBXLight light; foreach (const FBXNode& subobject, object.children) { - std::string childname = QString(subobject.name).toStdString(); + QString childname = QString(subobject.name); if (subobject.name == "Properties70") { foreach (const FBXNode& property, subobject.children) { int valIndex = 4; - std::string propName = QString(property.name).toStdString(); + QString propName = QString(property.name); if (property.name == "P") { - std::string propname = property.properties.at(0).toString().toStdString(); + QString propname = property.properties.at(0).toString(); if (propname == "Intensity") { light.intensity = 0.01f * property.properties.at(valIndex).value(); } @@ -1238,13 +1238,13 @@ FBXLight extractLight(const FBXNode& object) { } #if defined(DEBUG_FBXREADER) - std::string type = object.properties.at(0).toString().toStdString(); - type = object.properties.at(1).toString().toStdString(); - type = object.properties.at(2).toString().toStdString(); + QString type = object.properties.at(0).toString(); + type = object.properties.at(1).toString(); + type = object.properties.at(2).toString(); foreach (const QVariant& prop, object.properties) { - std::string proptype = prop.typeName(); - std::string propval = prop.toString().toStdString(); + QString proptype = prop.typeName(); + QString propval = prop.toString(); if (proptype == "Properties70") { } } @@ -1281,7 +1281,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, QHash yComponents; QHash zComponents; - std::map lights; + std::map lights; QVariantHash joints = mapping.value("joint").toHash(); QString jointEyeLeftName = processID(getString(joints.value("jointEyeLeft", "jointEyeLeft"))); @@ -1369,7 +1369,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, int index = 4; foreach (const FBXNode& subobject, object.children) { if (subobject.name == propertyName) { - std::string subpropName = subobject.properties.at(0).toString().toStdString(); + QString subpropName = subobject.properties.at(0).toString(); if (subpropName == "UnitScaleFactor") { unitScaleFactor = subobject.properties.at(index).toFloat(); } else if (subpropName == "AmbientColor") { @@ -1393,8 +1393,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, QString id = getID(object.properties); modelIDsToNames.insert(id, name); - std::string modelname = name.toLower().toStdString(); - if (modelname.find("hifi") == 0) { + QString modelname = name.toLower(); + if (modelname.startsWith("hifi")) { hifiGlobalNodeID = id; } @@ -1527,19 +1527,19 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, } #if defined(DEBUG_FBXREADER) else if (subobject.name == "TypeFlags") { - std::string attributetype = subobject.properties.at(0).toString().toStdString(); + QString attributetype = subobject.properties.at(0).toString(); if (!attributetype.empty()) { if (attributetype == "Light") { - std::string lightprop; + QString lightprop; foreach (const QVariant& vprop, subobject.properties) { - lightprop = vprop.toString().toStdString(); + lightprop = vprop.toString(); } FBXLight light = extractLight(object); } } } else { - std::string whatisthat = subobject.name; + QString whatisthat = subobject.name; if (whatisthat == "Shape") { } } @@ -1604,7 +1604,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, if (property.name == propertyName) { QString v = property.properties.at(0).toString(); if (property.properties.at(0) == "UVSet") { - tex.assign(tex.UVSet, property.properties.at(index).toString().toStdString()); + tex.assign(tex.UVSet, property.properties.at(index).toString()); } else if (property.properties.at(0) == "CurrentTextureBlendMode") { tex.assign(tex.currentTextureBlendMode, property.properties.at(index).value()); } else if (property.properties.at(0) == "UseMaterial") { @@ -1618,7 +1618,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, } #if defined(DEBUG_FBXREADER) else { - std::string propName = v.toStdString(); + QString propName = v; unknown++; } #endif @@ -1632,7 +1632,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, } else if (subobject.name == "FileName") { } else if (subobject.name == "Media") { } else { - std::string subname = subobject.name.data(); + QString subname = subobject.name.data(); unknown++; } } @@ -1693,7 +1693,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, } #if defined(DEBUG_FBXREADER) else { - const std::string propname = property.properties.at(0).toString().toStdString(); + const QString propname = property.properties.at(0).toString(); if (propname == "EmissiveFactor") { } } @@ -1703,7 +1703,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, } #if defined(DEBUG_FBXREADER) else { - std::string propname = subobject.name.data(); + QString propname = subobject.name.data(); int unknown = 0; if ( (propname == "Version") ||(propname == "ShadingModel") @@ -1719,21 +1719,21 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, } else if (object.name == "NodeAttribute") { #if defined(DEBUG_FBXREADER) - std::vector properties; + std::vector properties; foreach(const QVariant& v, object.properties) { - properties.push_back(v.toString().toStdString()); + properties.push_back(v.toString()); } #endif - std::string attribID = getID(object.properties).toStdString(); - std::string attributetype; + QString attribID = getID(object.properties); + QString attributetype; foreach (const FBXNode& subobject, object.children) { if (subobject.name == "TypeFlags") { typeFlags.insert(getID(object.properties), subobject.properties.at(0).toString()); - attributetype = subobject.properties.at(0).toString().toStdString(); + attributetype = subobject.properties.at(0).toString(); } } - if (!attributetype.empty()) { + if (!attributetype.isEmpty()) { if (attributetype == "Light") { FBXLight light = extractLight(object); lights[attribID] = light; @@ -1781,7 +1781,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, } #if defined(DEBUG_FBXREADER) else { - std::string objectname = object.name.data(); + QString objectname = object.name.data(); if ( objectname == "Pose" || objectname == "AnimationStack" || objectname == "AnimationLayer" @@ -1800,7 +1800,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, QString parentID = getID(connection.properties, 2); ooChildToParent.insert(childID, parentID); if (!hifiGlobalNodeID.isEmpty() && (parentID == hifiGlobalNodeID)) { - std::map< std::string, FBXLight >::iterator lit = lights.find(childID.toStdString()); + std::map< QString, FBXLight >::iterator lit = lights.find(childID); if (lit != lights.end()) { lightmapLevel = (*lit).second.intensity; if (lightmapLevel <= 0.0f) { @@ -1842,7 +1842,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, } else if (loadLightmaps && type.contains("ambient")) { ambientTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else { - std::string typenam = type.data(); + QString typenam = type.data(); counter++; } } @@ -1853,7 +1853,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, } #if defined(DEBUG_FBXREADER) else { - std::string objectname = child.name.data(); + QString objectname = child.name.data(); if ( objectname == "Pose" || objectname == "CreationTime" || objectname == "FileId" @@ -1875,7 +1875,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, // TODO: check if is code is needed if (!lights.empty()) { if (hifiGlobalNodeID.isEmpty()) { - std::map< std::string, FBXLight >::iterator l = lights.begin(); + std::map< QString, FBXLight >::iterator l = lights.begin(); lightmapLevel = (*l).second.intensity; } } diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 44b2bfe4a5..98e4d60826 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -110,7 +110,7 @@ public: Transform transform; int texcoordSet; - std::string texcoordSetName; + QString texcoordSetName; }; /// A single part of a mesh (with the same material). diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 553e460a5c..f7bd56e3ca 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1871,9 +1871,9 @@ void GeometryReader::run() { if (!_reply) { throw QString("Reply is NULL ?!"); } - std::string urlname = _url.path().toLower().toStdString(); + QString urlname = _url.path().toLower(); bool urlValid = true; - urlValid &= !urlname.empty(); + urlValid &= !urlname.isEmpty(); urlValid &= !_url.path().isEmpty(); urlValid &= _url.path().toLower().endsWith(".fbx") || _url.path().toLower().endsWith(".svo"); From 99e1fdd46e227cde5412a21496db593ef6219648 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sat, 10 Jan 2015 07:44:26 -0800 Subject: [PATCH 15/51] fix for EntityServer crash adding EntityItem::_element backpointer for easier add/remove logic --- .../src/EntityTreeRenderer.cpp | 2 + libraries/entities/src/EntityItem.cpp | 3 + libraries/entities/src/EntityItem.h | 4 ++ libraries/entities/src/EntityTreeElement.cpp | 13 ++++- .../entities/src/MovingEntitiesOperator.cpp | 15 +++-- .../entities/src/UpdateEntityOperator.cpp | 57 ++++++++----------- 6 files changed, 55 insertions(+), 39 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 47e9237ddc..3518e7b75c 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -98,7 +98,9 @@ void EntityTreeRenderer::init() { } QScriptValue EntityTreeRenderer::loadEntityScript(const EntityItemID& entityItemID) { + _tree->lockForRead(); EntityItem* entity = static_cast(_tree)->findEntityByEntityItemID(entityItemID); + _tree->unlock(); return loadEntityScript(entity); } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index a744d39f05..6917dc1e7d 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -95,6 +95,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) { _physicsInfo = NULL; _dirtyFlags = 0; _changedOnServer = 0; + _element = NULL; initFromEntityItemID(entityItemID); } @@ -110,6 +111,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert _physicsInfo = NULL; _dirtyFlags = 0; _changedOnServer = 0; + _element = NULL; initFromEntityItemID(entityItemID); setProperties(properties); } @@ -117,6 +119,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert EntityItem::~EntityItem() { // be sure to clean up _physicsInfo before calling this dtor assert(_physicsInfo == NULL); + assert(_element == NULL); } EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& params) const { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index e52be1707a..6d422ab257 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -39,6 +39,7 @@ class EntityTreeElementExtraEncodeData; /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate /// one directly, instead you must only construct one of it's derived classes with additional features. class EntityItem { + friend class EntityTreeElement; public: enum EntityDirtyFlags { @@ -301,6 +302,7 @@ public: void* getPhysicsInfo() const { return _physicsInfo; } void setPhysicsInfo(void* data) { _physicsInfo = data; } + EntityTreeElement* getElement() const { return _element; } protected: virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init @@ -362,6 +364,8 @@ protected: // DirtyFlags are set whenever a property changes that the EntitySimulation needs to know about. uint32_t _dirtyFlags; // things that have changed from EXTERNAL changes (via script or packet) but NOT from simulation + + EntityTreeElement* _element; // back pointer to containing Element }; diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 5f072164a0..4ced5fe844 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -682,6 +682,7 @@ void EntityTreeElement::cleanupEntities() { uint16_t numberOfEntities = _entityItems->size(); for (uint16_t i = 0; i < numberOfEntities; i++) { EntityItem* entity = (*_entityItems)[i]; + entity->_element = NULL; delete entity; } _entityItems->clear(); @@ -693,6 +694,7 @@ bool EntityTreeElement::removeEntityWithEntityItemID(const EntityItemID& id) { for (uint16_t i = 0; i < numberOfEntities; i++) { if ((*_entityItems)[i]->getEntityItemID() == id) { foundEntity = true; + (*_entityItems)[i]->_element = NULL; _entityItems->removeAt(i); break; } @@ -701,7 +703,13 @@ bool EntityTreeElement::removeEntityWithEntityItemID(const EntityItemID& id) { } bool EntityTreeElement::removeEntityItem(EntityItem* entity) { - return _entityItems->removeAll(entity) > 0; + int numEntries = _entityItems->removeAll(entity); + if (numEntries > 0) { + assert(entity->_element == this); + entity->_element = NULL; + return true; + } + return false; } @@ -808,7 +816,10 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int } void EntityTreeElement::addEntityItem(EntityItem* entity) { + assert(entity); + assert(entity->_element == NULL); _entityItems->push_back(entity); + entity->_element = this; } // will average a "common reduced LOD view" from the the child elements... diff --git a/libraries/entities/src/MovingEntitiesOperator.cpp b/libraries/entities/src/MovingEntitiesOperator.cpp index 1ec67967b6..48ba8e4ec2 100644 --- a/libraries/entities/src/MovingEntitiesOperator.cpp +++ b/libraries/entities/src/MovingEntitiesOperator.cpp @@ -179,7 +179,7 @@ bool MovingEntitiesOperator::preRecursion(OctreeElement* element) { // If this is one of the old elements we're looking for, then ask it to remove the old entity if (!details.oldFound && entityTreeElement == details.oldContainingElement) { - entityTreeElement->removeEntityItem(details.entity); + // DO NOT remove the entity here. It will be removed when added to the destination element. _foundOldCount++; //details.oldFound = true; // TODO: would be nice to add this optimization if (_wantDebug) { @@ -193,8 +193,15 @@ bool MovingEntitiesOperator::preRecursion(OctreeElement* element) { // If this element is the best fit for the new bounds of this entity then add the entity to the element if (!details.newFound && entityTreeElement->bestFitBounds(details.newCube)) { EntityItemID entityItemID = details.entity->getEntityItemID(); - entityTreeElement->addEntityItem(details.entity); - _tree->setContainingElement(entityItemID, entityTreeElement); + // remove from the old before adding + EntityTreeElement* oldElement = details.entity->getElement(); + if (oldElement != entityTreeElement) { + if (oldElement) { + oldElement->removeEntityItem(details.entity); + } + entityTreeElement->addEntityItem(details.entity); + _tree->setContainingElement(entityItemID, entityTreeElement); + } _foundNewCount++; //details.newFound = true; // TODO: would be nice to add this optimization if (_wantDebug) { @@ -227,7 +234,7 @@ bool MovingEntitiesOperator::postRecursion(OctreeElement* element) { - // It's not OK to prune if we have the potential of deleting the original containig element. + // It's not OK to prune if we have the potential of deleting the original containing element // because if we prune the containing element then new might end up reallocating the same memory later // and that will confuse our logic. // diff --git a/libraries/entities/src/UpdateEntityOperator.cpp b/libraries/entities/src/UpdateEntityOperator.cpp index 9cee11d73c..c85c4235de 100644 --- a/libraries/entities/src/UpdateEntityOperator.cpp +++ b/libraries/entities/src/UpdateEntityOperator.cpp @@ -231,18 +231,19 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) { qDebug() << " *** REMOVING from ELEMENT ***"; } - entityTreeElement->removeEntityItem(_existingEntity); // NOTE: only removes the entity, doesn't delete it + // the entity knows what element it's in, so we remove it from that one + // NOTE: we know we haven't yet added it to its new element because _removeOld is true + EntityTreeElement* oldElement = _existingEntity->getElement(); + oldElement->removeEntityItem(_existingEntity); + _tree->setContainingElement(_entityItemID, NULL); - // If we haven't yet found the new location, then we need to - // make sure to remove our entity to element map, because for - // now we're not in that map - if (!_foundNew) { - _tree->setContainingElement(_entityItemID, NULL); - - if (_wantDebug) { - qDebug() << " *** REMOVING from MAP ***"; - } + if (oldElement != _containingElement) { + qDebug() << "WARNING entity moved during UpdateEntityOperator recursion"; + assert(! _containingElement->removeEntityItem(_existingEntity)); + } + if (_wantDebug) { + qDebug() << " *** REMOVING from MAP ***"; } } _foundOld = true; @@ -263,7 +264,6 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) { qDebug() << " entityTreeElement->bestFitBounds(_newEntityBox)=" << entityTreeElement->bestFitBounds(_newEntityBox); } - // If this element is the best fit for the new entity properties, then add/or update it if (entityTreeElement->bestFitBounds(_newEntityBox)) { @@ -271,33 +271,14 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) { qDebug() << " *** THIS ELEMENT IS BEST FIT ***"; } + EntityTreeElement* oldElement = _existingEntity->getElement(); // if we are the existing containing element, then we can just do the update of the entity properties - if (entityTreeElement == _containingElement) { + if (entityTreeElement == oldElement) { if (_wantDebug) { qDebug() << " *** This is the same OLD ELEMENT ***"; } - // TODO: We shouldn't be in a remove old case and also be the new best fit. This indicates that - // we have some kind of a logic error in this operator. But, it can handle it properly by setting - // the new properties for the entity and moving on. Still going to output a warning that if we - // see consistently we will want to address this. - if (_removeOld) { - qDebug() << "UNEXPECTED - UpdateEntityOperator - " - "we thought we needed to removeOld, but the old entity is our best fit."; - _removeOld = false; - - // if we thought we were supposed to remove the old item, and we already did, then we need - // to repair this case. - if (_foundOld) { - if (_wantDebug) { - qDebug() << " *** REPAIRING PREVIOUS REMOVAL from ELEMENT and MAP ***"; - } - entityTreeElement->addEntityItem(_existingEntity); - _tree->setContainingElement(_entityItemID, entityTreeElement); - } - } - // set the entity properties and mark our element as changed. _existingEntity->setProperties(_properties); if (_wantDebug) { @@ -305,14 +286,22 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) { } } else { // otherwise, this is an add case. + if (oldElement) { + oldElement->removeEntityItem(_existingEntity); + if (oldElement != _containingElement) { + qDebug() << "WARNING entity moved during UpdateEntityOperator recursion"; + } + } entityTreeElement->addEntityItem(_existingEntity); - _existingEntity->setProperties(_properties); // still need to update the properties! _tree->setContainingElement(_entityItemID, entityTreeElement); + + _existingEntity->setProperties(_properties); // still need to update the properties! if (_wantDebug) { qDebug() << " *** ADDING ENTITY to ELEMENT and MAP and SETTING PROPERTIES ***"; } } - _foundNew = true; // we found the new item! + _foundNew = true; // we found the new element + _removeOld = false; // and it has already been removed from the old } else { keepSearching = true; } From 25e64d619ca9041b54dc9fd98449db8c0953ae01 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sat, 10 Jan 2015 11:46:42 -0800 Subject: [PATCH 16/51] move statics out of EntityItem This makes for much more readable core dumps --- libraries/entities/src/EntityItem.cpp | 2 + libraries/entities/src/EntityItem.h | 49 ++++++++++--------- .../entities/src/EntityItemProperties.cpp | 30 ++++++------ 3 files changed, 42 insertions(+), 39 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 48ceed863e..73509305ed 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -21,6 +21,7 @@ #include "EntityItem.h" #include "EntityTree.h" +/* const float EntityItem::IMMORTAL = -1.0f; /// special lifetime which means the entity lives for ever. default lifetime const float EntityItem::DEFAULT_GLOW_LEVEL = 0.0f; const float EntityItem::DEFAULT_LOCAL_RENDER_ALPHA = 1.0f; @@ -45,6 +46,7 @@ const bool EntityItem::DEFAULT_VISIBLE = true; const bool EntityItem::DEFAULT_IGNORE_FOR_COLLISIONS = false; const bool EntityItem::DEFAULT_COLLISIONS_WILL_MOVE = false; const bool EntityItem::DEFAULT_LOCKED = false; +*/ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { _id = entityItemID.id; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index e52be1707a..365bc1b0f5 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -35,6 +35,31 @@ class EntityTreeElementExtraEncodeData; #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; #define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { }; +const glm::vec3 DEFAULT_DIMENSIONS = glm::vec3(0.1f); +const glm::quat DEFAULT_ROTATION; +const float DEFAULT_GLOW_LEVEL = 0.0f; +const float DEFAULT_LOCAL_RENDER_ALPHA = 1.0f; +const float DEFAULT_MASS = 1.0f; +const glm::vec3 NO_VELOCITY= glm::vec3(0.0f); +const glm::vec3 DEFAULT_VELOCITY = NO_VELOCITY; +const float EPSILON_VELOCITY_LENGTH = 0.001f / (float)TREE_SCALE; +const glm::vec3 NO_GRAVITY = glm::vec3(0.0f); +const glm::vec3 DEFAULT_GRAVITY = NO_GRAVITY; +const glm::vec3 REGULAR_GRAVITY = glm::vec3(0, -9.8f / (float)TREE_SCALE, 0); +const float DEFAULT_DAMPING = 0.39347f; // approx timescale = 2.0 sec (see damping timescale formula in header) +const float IMMORTAL = -1.0f; /// special lifetime which means the entity lives for ever. default lifetime +const float DEFAULT_LIFETIME = IMMORTAL; +const QString DEFAULT_SCRIPT = QString(""); +const glm::vec3 DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f, 0.5f, 0.5f); // center +const glm::vec3 NO_ANGULAR_VELOCITY = glm::vec3(0.0f); +const glm::vec3 DEFAULT_ANGULAR_VELOCITY = NO_ANGULAR_VELOCITY; +const float DEFAULT_ANGULAR_DAMPING = 0.39347f; // approx timescale = 2.0 sec (see damping timescale formula in header) +const bool DEFAULT_VISIBLE = true; +const bool DEFAULT_IGNORE_FOR_COLLISIONS = false; +const bool DEFAULT_COLLISIONS_WILL_MOVE = false; +const bool DEFAULT_LOCKED = false; +const QString DEFAULT_USER_DATA = QString(""); + /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate /// one directly, instead you must only construct one of it's derived classes with additional features. @@ -148,7 +173,6 @@ public: glm::vec3 getCenter() const; /// calculates center of the entity in domain scale units (0.0 - 1.0) glm::vec3 getCenterInMeters() const { return getCenter() * (float) TREE_SCALE; } - static const glm::vec3 DEFAULT_DIMENSIONS; const glm::vec3& getDimensions() const { return _dimensions; } /// get dimensions in domain scale units (0.0 - 1.0) glm::vec3 getDimensionsInMeters() const { return _dimensions * (float) TREE_SCALE; } /// get dimensions in meters float getDistanceToBottomOfEntity() const; /// get the distance from the position of the entity to its "bottom" in y axis @@ -160,34 +184,24 @@ public: /// set dimensions in meter units (0.0 - TREE_SCALE) this will also reset radius appropriately void setDimensionsInMeters(const glm::vec3& value) { setDimensions(value / (float) TREE_SCALE); } - static const glm::quat DEFAULT_ROTATION; const glm::quat& getRotation() const { return _rotation; } void setRotation(const glm::quat& rotation) { _rotation = rotation; recalculateCollisionShape(); } - static const float DEFAULT_GLOW_LEVEL; float getGlowLevel() const { return _glowLevel; } void setGlowLevel(float glowLevel) { _glowLevel = glowLevel; } - static const float DEFAULT_LOCAL_RENDER_ALPHA; float getLocalRenderAlpha() const { return _localRenderAlpha; } void setLocalRenderAlpha(float localRenderAlpha) { _localRenderAlpha = localRenderAlpha; } - static const float DEFAULT_MASS; float getMass() const { return _mass; } void setMass(float value) { _mass = value; } - static const glm::vec3 DEFAULT_VELOCITY; - static const glm::vec3 NO_VELOCITY; - static const float EPSILON_VELOCITY_LENGTH; const glm::vec3& getVelocity() const { return _velocity; } /// velocity in domain scale units (0.0-1.0) per second glm::vec3 getVelocityInMeters() const { return _velocity * (float) TREE_SCALE; } /// get velocity in meters void setVelocity(const glm::vec3& value) { _velocity = value; } /// velocity in domain scale units (0.0-1.0) per second void setVelocityInMeters(const glm::vec3& value) { _velocity = value / (float) TREE_SCALE; } /// velocity in meters bool hasVelocity() const { return _velocity != NO_VELOCITY; } - static const glm::vec3 DEFAULT_GRAVITY; - static const glm::vec3 REGULAR_GRAVITY; - static const glm::vec3 NO_GRAVITY; const glm::vec3& getGravity() const { return _gravity; } /// gravity in domain scale units (0.0-1.0) per second squared glm::vec3 getGravityInMeters() const { return _gravity * (float) TREE_SCALE; } /// get gravity in meters void setGravity(const glm::vec3& value) { _gravity = value; } /// gravity in domain scale units (0.0-1.0) per second squared @@ -197,13 +211,10 @@ public: // TODO: this should eventually be updated to support resting on collisions with other surfaces bool isRestingOnSurface() const; - static const float DEFAULT_DAMPING; float getDamping() const { return _damping; } void setDamping(float value) { _damping = value; } // lifetime related properties. - static const float IMMORTAL; /// special lifetime which means the entity lives for ever. default lifetime - static const float DEFAULT_LIFETIME; float getLifetime() const { return _lifetime; } /// get the lifetime in seconds for the entity void setLifetime(float value) { _lifetime = value; } /// set the lifetime in seconds for the entity @@ -224,46 +235,36 @@ public: AACube getMinimumAACube() const; AABox getAABox() const; /// axis aligned bounding box in domain scale units (0.0 - 1.0) - static const QString DEFAULT_SCRIPT; const QString& getScript() const { return _script; } void setScript(const QString& value) { _script = value; } - static const glm::vec3 DEFAULT_REGISTRATION_POINT; const glm::vec3& getRegistrationPoint() const { return _registrationPoint; } /// registration point as ratio of entity /// registration point as ratio of entity void setRegistrationPoint(const glm::vec3& value) { _registrationPoint = glm::clamp(value, 0.0f, 1.0f); recalculateCollisionShape(); } - static const glm::vec3 NO_ANGULAR_VELOCITY; - static const glm::vec3 DEFAULT_ANGULAR_VELOCITY; const glm::vec3& getAngularVelocity() const { return _angularVelocity; } void setAngularVelocity(const glm::vec3& value) { _angularVelocity = value; } bool hasAngularVelocity() const { return _angularVelocity != NO_ANGULAR_VELOCITY; } - static const float DEFAULT_ANGULAR_DAMPING; float getAngularDamping() const { return _angularDamping; } void setAngularDamping(float value) { _angularDamping = value; } - static const bool DEFAULT_VISIBLE; bool getVisible() const { return _visible; } void setVisible(bool value) { _visible = value; } bool isVisible() const { return _visible; } bool isInvisible() const { return !_visible; } - static const bool DEFAULT_IGNORE_FOR_COLLISIONS; bool getIgnoreForCollisions() const { return _ignoreForCollisions; } void setIgnoreForCollisions(bool value) { _ignoreForCollisions = value; } - static const bool DEFAULT_COLLISIONS_WILL_MOVE; bool getCollisionsWillMove() const { return _collisionsWillMove; } void setCollisionsWillMove(bool value) { _collisionsWillMove = value; } - static const bool DEFAULT_LOCKED; bool getLocked() const { return _locked; } void setLocked(bool value) { _locked = value; } - static const QString DEFAULT_USER_DATA; const QString& getUserData() const { return _userData; } void setUserData(const QString& value) { _userData = value; } diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 58b110c4b0..be6fe01841 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -24,27 +24,27 @@ EntityItemProperties::EntityItemProperties() : - CONSTRUCT_PROPERTY(visible, EntityItem::DEFAULT_VISIBLE), + CONSTRUCT_PROPERTY(visible, DEFAULT_VISIBLE), CONSTRUCT_PROPERTY(position, 0), - CONSTRUCT_PROPERTY(dimensions, EntityItem::DEFAULT_DIMENSIONS), - CONSTRUCT_PROPERTY(rotation, EntityItem::DEFAULT_ROTATION), - CONSTRUCT_PROPERTY(mass, EntityItem::DEFAULT_MASS), - CONSTRUCT_PROPERTY(velocity, EntityItem::DEFAULT_VELOCITY), - CONSTRUCT_PROPERTY(gravity, EntityItem::DEFAULT_GRAVITY), - CONSTRUCT_PROPERTY(damping, EntityItem::DEFAULT_DAMPING), - CONSTRUCT_PROPERTY(lifetime, EntityItem::DEFAULT_LIFETIME), - CONSTRUCT_PROPERTY(script, EntityItem::DEFAULT_SCRIPT), + CONSTRUCT_PROPERTY(dimensions, DEFAULT_DIMENSIONS), + CONSTRUCT_PROPERTY(rotation, DEFAULT_ROTATION), + CONSTRUCT_PROPERTY(mass, DEFAULT_MASS), + CONSTRUCT_PROPERTY(velocity, DEFAULT_VELOCITY), + CONSTRUCT_PROPERTY(gravity, DEFAULT_GRAVITY), + CONSTRUCT_PROPERTY(damping, DEFAULT_DAMPING), + CONSTRUCT_PROPERTY(lifetime, DEFAULT_LIFETIME), + CONSTRUCT_PROPERTY(script, DEFAULT_SCRIPT), CONSTRUCT_PROPERTY(color, ), CONSTRUCT_PROPERTY(modelURL, ""), CONSTRUCT_PROPERTY(animationURL, ""), CONSTRUCT_PROPERTY(animationFPS, ModelEntityItem::DEFAULT_ANIMATION_FPS), CONSTRUCT_PROPERTY(animationFrameIndex, ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX), CONSTRUCT_PROPERTY(animationIsPlaying, ModelEntityItem::DEFAULT_ANIMATION_IS_PLAYING), - CONSTRUCT_PROPERTY(registrationPoint, EntityItem::DEFAULT_REGISTRATION_POINT), - CONSTRUCT_PROPERTY(angularVelocity, EntityItem::DEFAULT_ANGULAR_VELOCITY), - CONSTRUCT_PROPERTY(angularDamping, EntityItem::DEFAULT_ANGULAR_DAMPING), - CONSTRUCT_PROPERTY(ignoreForCollisions, EntityItem::DEFAULT_IGNORE_FOR_COLLISIONS), - CONSTRUCT_PROPERTY(collisionsWillMove, EntityItem::DEFAULT_COLLISIONS_WILL_MOVE), + CONSTRUCT_PROPERTY(registrationPoint, DEFAULT_REGISTRATION_POINT), + CONSTRUCT_PROPERTY(angularVelocity, DEFAULT_ANGULAR_VELOCITY), + CONSTRUCT_PROPERTY(angularDamping, DEFAULT_ANGULAR_DAMPING), + CONSTRUCT_PROPERTY(ignoreForCollisions, DEFAULT_IGNORE_FOR_COLLISIONS), + CONSTRUCT_PROPERTY(collisionsWillMove, DEFAULT_COLLISIONS_WILL_MOVE), CONSTRUCT_PROPERTY(isSpotlight, false), CONSTRUCT_PROPERTY(diffuseColor, ), CONSTRUCT_PROPERTY(ambientColor, ), @@ -57,7 +57,7 @@ EntityItemProperties::EntityItemProperties() : CONSTRUCT_PROPERTY(locked, false), CONSTRUCT_PROPERTY(textures, ""), CONSTRUCT_PROPERTY(animationSettings, ""), - CONSTRUCT_PROPERTY(userData, EntityItem::DEFAULT_USER_DATA), + CONSTRUCT_PROPERTY(userData, DEFAULT_USER_DATA), CONSTRUCT_PROPERTY(text, TextEntityItem::DEFAULT_TEXT), CONSTRUCT_PROPERTY(lineHeight, TextEntityItem::DEFAULT_LINE_HEIGHT), CONSTRUCT_PROPERTY(textColor, TextEntityItem::DEFAULT_TEXT_COLOR), From e711b86519e99eaf855a33788468689b3f434da1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sat, 10 Jan 2015 19:07:58 -0800 Subject: [PATCH 17/51] scale DEFAULT_DIMENSIONS correctly also remove a block of commented out cruft --- libraries/entities/src/EntityItem.cpp | 27 --------------------------- libraries/entities/src/EntityItem.h | 2 +- 2 files changed, 1 insertion(+), 28 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index b89f5fedc0..4bf394314b 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -21,33 +21,6 @@ #include "EntityItem.h" #include "EntityTree.h" -/* -const float EntityItem::IMMORTAL = -1.0f; /// special lifetime which means the entity lives for ever. default lifetime -const float EntityItem::DEFAULT_GLOW_LEVEL = 0.0f; -const float EntityItem::DEFAULT_LOCAL_RENDER_ALPHA = 1.0f; -const float EntityItem::DEFAULT_MASS = 1.0f; -const float EntityItem::DEFAULT_LIFETIME = EntityItem::IMMORTAL; -const QString EntityItem::DEFAULT_USER_DATA = QString(""); -const float EntityItem::DEFAULT_DAMPING = 0.39347f; // approx timescale = 2.0 sec (see damping timescale formula in header) -const glm::vec3 EntityItem::NO_VELOCITY = glm::vec3(0, 0, 0); -const float EntityItem::EPSILON_VELOCITY_LENGTH = (1.0f / 1000.0f) / (float)TREE_SCALE; // really small: 1mm/second -const glm::vec3 EntityItem::DEFAULT_VELOCITY = EntityItem::NO_VELOCITY; -const glm::vec3 EntityItem::NO_GRAVITY = glm::vec3(0, 0, 0); -const glm::vec3 EntityItem::REGULAR_GRAVITY = glm::vec3(0, (-9.8f / TREE_SCALE), 0); -const glm::vec3 EntityItem::DEFAULT_GRAVITY = EntityItem::NO_GRAVITY; -const QString EntityItem::DEFAULT_SCRIPT = QString(""); -const glm::quat EntityItem::DEFAULT_ROTATION; -const glm::vec3 EntityItem::DEFAULT_DIMENSIONS = glm::vec3(0.1f, 0.1f, 0.1f); -const glm::vec3 EntityItem::DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f, 0.5f, 0.5f); // center -const glm::vec3 EntityItem::NO_ANGULAR_VELOCITY = glm::vec3(0.0f, 0.0f, 0.0f); -const glm::vec3 EntityItem::DEFAULT_ANGULAR_VELOCITY = NO_ANGULAR_VELOCITY; -const float EntityItem::DEFAULT_ANGULAR_DAMPING = 2.0f; -const bool EntityItem::DEFAULT_VISIBLE = true; -const bool EntityItem::DEFAULT_IGNORE_FOR_COLLISIONS = false; -const bool EntityItem::DEFAULT_COLLISIONS_WILL_MOVE = false; -const bool EntityItem::DEFAULT_LOCKED = false; -*/ - void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { _id = entityItemID.id; _creatorTokenID = entityItemID.creatorTokenID; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 9bdd73c503..1b8afa930b 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -35,7 +35,7 @@ class EntityTreeElementExtraEncodeData; #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; #define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { }; -const glm::vec3 DEFAULT_DIMENSIONS = glm::vec3(0.1f); +const glm::vec3 DEFAULT_DIMENSIONS = glm::vec3(0.1f) / (float)TREE_SCALE; const glm::quat DEFAULT_ROTATION; const float DEFAULT_GLOW_LEVEL = 0.0f; const float DEFAULT_LOCAL_RENDER_ALPHA = 1.0f; From 5309fb6a43dbf9183f55087a1a5393dfe8e2f9fc Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sun, 11 Jan 2015 10:44:36 -0800 Subject: [PATCH 18/51] remove lock at EntityTreeRenderer::loadEntityScript --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 3518e7b75c..47e9237ddc 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -98,9 +98,7 @@ void EntityTreeRenderer::init() { } QScriptValue EntityTreeRenderer::loadEntityScript(const EntityItemID& entityItemID) { - _tree->lockForRead(); EntityItem* entity = static_cast(_tree)->findEntityByEntityItemID(entityItemID); - _tree->unlock(); return loadEntityScript(entity); } From 968a34f9669103e372b407a3f163ade1e33b1ead Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 11 Jan 2015 11:44:16 -0800 Subject: [PATCH 19/51] Add instructions for building with SDL2 --- interface/external/sdl2/readme.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 interface/external/sdl2/readme.txt diff --git a/interface/external/sdl2/readme.txt b/interface/external/sdl2/readme.txt new file mode 100644 index 0000000000..9f3bd40e15 --- /dev/null +++ b/interface/external/sdl2/readme.txt @@ -0,0 +1,13 @@ + +Instructions for adding the SDL library (SDL2) to Interface +David Rowe, 11 Jan 2015 + +You can download the SDL development library from https://www.libsdl.org/. Interface has been tested with version 2.0.3. + +1. Copy the include and lib folders into the interface/externals/sdl2 folder. + This readme.txt should be there as well. + + You may optionally choose to copy the SDK folders to a location outside the repository (so you can re-use with different checkouts and different projects). + If so our CMake find module expects you to set the ENV variable 'HIFI_LIB_DIR' to a directory containing a subfolder 'sdl2' that contains the two folders mentioned above. + +2. Clear your build directory, run cmake and build, and you should be all set. From 60f55c7f3fd3f4dcaa1a30a3e5ffd6dd33753423 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 11 Jan 2015 12:07:16 -0800 Subject: [PATCH 20/51] remove important code from assert so it still runs in release build --- libraries/entities/src/DeleteEntityOperator.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/DeleteEntityOperator.cpp b/libraries/entities/src/DeleteEntityOperator.cpp index 890c301682..698ef18936 100644 --- a/libraries/entities/src/DeleteEntityOperator.cpp +++ b/libraries/entities/src/DeleteEntityOperator.cpp @@ -92,7 +92,8 @@ bool DeleteEntityOperator::preRecursion(OctreeElement* element) { // and we can stop searching. if (entityTreeElement == details.containingElement) { EntityItem* theEntity = details.entity; - assert(entityTreeElement->removeEntityItem(theEntity)); // remove it from the element + bool entityDeleted = entityTreeElement->removeEntityItem(theEntity); // remove it from the element + assert(entityDeleted); _tree->setContainingElement(details.entity->getEntityItemID(), NULL); // update or id to element lookup _foundCount++; } From 89a782c55a70701d58101c1b6131e8787bc6b7f6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sun, 11 Jan 2015 13:31:37 -0800 Subject: [PATCH 21/51] remove functional code from inside assert --- libraries/entities/src/UpdateEntityOperator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/UpdateEntityOperator.cpp b/libraries/entities/src/UpdateEntityOperator.cpp index c85c4235de..29ed430f7a 100644 --- a/libraries/entities/src/UpdateEntityOperator.cpp +++ b/libraries/entities/src/UpdateEntityOperator.cpp @@ -239,7 +239,7 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) { if (oldElement != _containingElement) { qDebug() << "WARNING entity moved during UpdateEntityOperator recursion"; - assert(! _containingElement->removeEntityItem(_existingEntity)); + _containingElement->removeEntityItem(_existingEntity); } if (_wantDebug) { From 5cdc76ad35569d584412a0e2a35e13ae3e61c36b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Sun, 11 Jan 2015 22:48:42 -0800 Subject: [PATCH 22/51] Put cache max size/count as class members --- libraries/networking/src/ResourceCache.cpp | 14 +++++--------- libraries/networking/src/ResourceCache.h | 6 +++--- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 4b769c9a28..962e256e02 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -73,22 +73,18 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& } void ResourceCache::addUnusedResource(const QSharedPointer& resource) { - static const int BYTES_PER_MEGABYTES = 1024 * 1024; - const int RETAINED_RESOURCE_COUNT = 50; - const int RETAINED_RESOURCE_SIZE = 100 * BYTES_PER_MEGABYTES; - - while (_unusedResourcesTotalBytes + resource->getBytesTotal() > RETAINED_RESOURCE_SIZE && + while (_unusedResourcesSize + resource->getBytesTotal() > _unusedResourcesMaxSize && !_unusedResources.empty()) { // unload the oldest resource QMap >::iterator it = _unusedResources.begin(); - _unusedResourcesTotalBytes -= it.value()->getBytesTotal(); + _unusedResourcesSize -= it.value()->getBytesTotal(); it.value()->setCache(NULL); _unusedResources.erase(it); } - if (_unusedResources.size() > RETAINED_RESOURCE_COUNT) { + if (_unusedResources.size() > _unusedResourcesMaxCount) { // unload the oldest resource QMap >::iterator it = _unusedResources.begin(); it.value()->setCache(NULL); @@ -96,13 +92,13 @@ void ResourceCache::addUnusedResource(const QSharedPointer& resource) } resource->setLRUKey(++_lastLRUKey); _unusedResources.insert(resource->getLRUKey(), resource); - _unusedResourcesTotalBytes += resource->getBytesTotal(); + _unusedResourcesSize += resource->getBytesTotal(); } void ResourceCache::removeUnusedResource(const QSharedPointer& resource) { if (_unusedResources.contains(resource->getLRUKey())) { _unusedResources.remove(resource->getLRUKey()); - _unusedResourcesTotalBytes -= resource->getBytesTotal(); + _unusedResourcesSize -= resource->getBytesTotal(); } } diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 0a4121ca5e..ca1a8a04d9 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -45,8 +45,9 @@ public: void refresh(const QUrl& url); protected: - - qint64 _unusedResourcesTotalBytes = 0; + int _unusedResourcesMaxCount = 50; + qint64 _unusedResourcesMaxSize = 100 * 1024 * 1024; + qint64 _unusedResourcesSize = 0; QMap > _unusedResources; /// Loads a resource from the specified URL. @@ -67,7 +68,6 @@ protected: static void requestCompleted(Resource* resource); private: - friend class Resource; QHash > _resources; From bf71aa6163af4b411d28f0a54991976f4205d025 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 12 Jan 2015 09:15:14 -0800 Subject: [PATCH 23/51] Remove Visage dependency from cmaklists --- interface/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 77a20201cb..8ddd1153ef 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -2,7 +2,7 @@ set(TARGET_NAME interface) project(${TARGET_NAME}) # set a default root dir for each of our optional externals if it was not passed -set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "PrioVR" "Sixense" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "Gverb" "Visage") +set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "PrioVR" "Sixense" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "Gverb") foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE) if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR) From 69f5c769b8c4f930e3b02c19e644223adee9203b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jan 2015 10:07:20 -0800 Subject: [PATCH 24/51] don't play muzak from lobby to avoid error --- examples/lobby.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/lobby.js b/examples/lobby.js index b03be7c29b..e34d119502 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -139,10 +139,10 @@ function drawLobby() { MyAvatar.attach(HELMET_ATTACHMENT_URL, "Neck", {x: 0, y: 0, z: 0}, Quat.fromPitchYawRollDegrees(0, 0, 0), 1.15); // start the drone sound - currentDrone = Audio.playSound(droneSound, { stereo: true, loop: true, localOnly: true, volume: DRONE_VOLUME }); + // currentDrone = Audio.playSound(droneSound, { stereo: true, loop: true, localOnly: true, volume: DRONE_VOLUME }); // start one of our muzak sounds - playRandomMuzak(); + // playRandomMuzak(); } } @@ -353,9 +353,9 @@ function update(deltaTime) { Overlays.editOverlay(descriptionText, { position: textOverlayPosition() }); // if the reticle is up then we may need to play the next muzak - if (!Audio.isInjectorPlaying(currentMuzakInjector)) { - playNextMuzak(); - } + // if (!Audio.isInjectorPlaying(currentMuzakInjector)) { +// playNextMuzak(); +// } } } From 98dd401ea363fa333cc696a4e8df6cb5e513fa76 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 11:12:19 -0800 Subject: [PATCH 25/51] Remove duplicate definition --- interface/src/ModelUploader.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/ModelUploader.cpp b/interface/src/ModelUploader.cpp index 89b6a4c9c0..7e9d857306 100644 --- a/interface/src/ModelUploader.cpp +++ b/interface/src/ModelUploader.cpp @@ -55,7 +55,6 @@ static const QString MODEL_URL = "/api/v1/models"; static const QString SETTING_NAME = "LastModelUploadLocation"; -static const long long BYTES_PER_MEGABYTES = 1024 * 1024; static const unsigned long long MAX_SIZE = 50 * 1024 * BYTES_PER_MEGABYTES; // 50 GB (Virtually remove limit) static const int MAX_TEXTURE_SIZE = 1024; static const int TIMEOUT = 1000; From 08317b51daaae2b3470b0357894e2e7709126636 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 11:12:50 -0800 Subject: [PATCH 26/51] Use removeUnusedResources --- libraries/render-utils/src/TextureCache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index df860338ab..0f34282162 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -203,7 +203,7 @@ NetworkTexturePointer TextureCache::getTexture(const QUrl& url, TextureType type texture->setCache(this); _dilatableNetworkTextures.insert(url, texture); } else { - _unusedResources.remove(texture->getLRUKey()); + removeUnusedResource(texture); } return texture; } From cb3f07e6f53758ef4b2c0263ce86ef9fe0d2c7e3 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 11:18:55 -0800 Subject: [PATCH 27/51] Remove unusedResourcesMaxCount --- libraries/networking/src/ResourceCache.cpp | 7 ------- libraries/networking/src/ResourceCache.h | 6 ++++-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 962e256e02..1b3d4cc232 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -83,13 +83,6 @@ void ResourceCache::addUnusedResource(const QSharedPointer& resource) _unusedResources.erase(it); } - - if (_unusedResources.size() > _unusedResourcesMaxCount) { - // unload the oldest resource - QMap >::iterator it = _unusedResources.begin(); - it.value()->setCache(NULL); - _unusedResources.erase(it); - } resource->setLRUKey(++_lastLRUKey); _unusedResources.insert(resource->getLRUKey(), resource); _unusedResourcesSize += resource->getBytesTotal(); diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index ca1a8a04d9..90d228fb07 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -27,6 +27,9 @@ class QTimer; class Resource; +static constexpr qint64 BYTES_PER_MEGABYTES = 1024 * 1024; +static constexpr qint64 DEFAULT_MAX_SIZE = 100 * BYTES_PER_MEGABYTES; + /// Base class for resource caches. class ResourceCache : public QObject { Q_OBJECT @@ -45,8 +48,7 @@ public: void refresh(const QUrl& url); protected: - int _unusedResourcesMaxCount = 50; - qint64 _unusedResourcesMaxSize = 100 * 1024 * 1024; + qint64 _unusedResourcesMaxSize = DEFAULT_MAX_SIZE; qint64 _unusedResourcesSize = 0; QMap > _unusedResources; From ea0ffd01256b22468e9e46d1afe2fcfd81ab8dcb Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 11:37:00 -0800 Subject: [PATCH 28/51] Introduce reserveUnusedResource --- libraries/networking/src/ResourceCache.cpp | 25 +++++++++++++++------- libraries/networking/src/ResourceCache.h | 1 + 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 1b3d4cc232..e2fef26b22 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -73,15 +73,12 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& } void ResourceCache::addUnusedResource(const QSharedPointer& resource) { - while (_unusedResourcesSize + resource->getBytesTotal() > _unusedResourcesMaxSize && - !_unusedResources.empty()) { - // unload the oldest resource - QMap >::iterator it = _unusedResources.begin(); - - _unusedResourcesSize -= it.value()->getBytesTotal(); - it.value()->setCache(NULL); - _unusedResources.erase(it); + if (resource->getBytesTotal() > _unusedResourcesMaxSize) { + // If it doesn't fit anyway, let's leave whatever is already in the cache. + resource->setCache(nullptr); + return; } + reserveUnusedResource(resource->getBytesTotal()); resource->setLRUKey(++_lastLRUKey); _unusedResources.insert(resource->getLRUKey(), resource); @@ -95,6 +92,18 @@ void ResourceCache::removeUnusedResource(const QSharedPointer& resourc } } +void ResourceCache::reserveUnusedResource(qint64 resourceSize) { + while (!_unusedResources.empty() && + _unusedResourcesSize + resourceSize > _unusedResourcesMaxSize) { + // unload the oldest resource + QMap >::iterator it = _unusedResources.begin(); + + _unusedResourcesSize -= it.value()->getBytesTotal(); + it.value()->setCache(NULL); + _unusedResources.erase(it); + } +} + void ResourceCache::attemptRequest(Resource* resource) { if (_requestLimit <= 0) { // wait until a slot becomes available diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 90d228fb07..6ae8b22445 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -65,6 +65,7 @@ protected: void addUnusedResource(const QSharedPointer& resource); void removeUnusedResource(const QSharedPointer& resource); + void reserveUnusedResource(qint64 resourceSize); static void attemptRequest(Resource* resource); static void requestCompleted(Resource* resource); From bad96e0ba40e4be3b158b16b917a07949c315da5 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 11:37:42 -0800 Subject: [PATCH 29/51] cache size getter/setter --- libraries/networking/src/ResourceCache.cpp | 5 +++++ libraries/networking/src/ResourceCache.h | 3 +++ 2 files changed, 8 insertions(+) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index e2fef26b22..63f4a658d1 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -72,6 +72,11 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& return resource; } +void ResourceCache::setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize) { + _unusedResourcesMaxSize = unusedResourcesMaxSize; + reserveUnusedResource(0); +} + void ResourceCache::addUnusedResource(const QSharedPointer& resource) { if (resource->getBytesTotal() > _unusedResourcesMaxSize) { // If it doesn't fit anyway, let's leave whatever is already in the cache. diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 6ae8b22445..b2bb8b5a39 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -37,6 +37,9 @@ class ResourceCache : public QObject { public: static void setRequestLimit(int limit) { _requestLimit = limit; } static int getRequestLimit() { return _requestLimit; } + + void setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize); + qint64 getUnusedResourceCacheSize() const { return _unusedResourcesMaxSize; } static const QList& getLoadingRequests() { return _loadingRequests; } From 81bf1e4f53a47f8ab490c574c3c20e509fd47d11 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 11:46:38 -0800 Subject: [PATCH 30/51] Some code maintainance --- libraries/networking/src/ResourceCache.cpp | 25 +++++++++------------- libraries/networking/src/ResourceCache.h | 21 +++++++++--------- 2 files changed, 20 insertions(+), 26 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 63f4a658d1..089cdc5607 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -21,10 +21,7 @@ #include "ResourceCache.h" ResourceCache::ResourceCache(QObject* parent) : - QObject(parent), - _lastLRUKey(0) -{ - + QObject(parent) { } ResourceCache::~ResourceCache() { @@ -32,7 +29,7 @@ ResourceCache::~ResourceCache() { // list on destruction, so keep clearing until there are no references left while (!_unusedResources.isEmpty()) { foreach (const QSharedPointer& resource, _unusedResources) { - resource->setCache(NULL); + resource->setCache(nullptr); } _unusedResources.clear(); } @@ -104,7 +101,7 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) { QMap >::iterator it = _unusedResources.begin(); _unusedResourcesSize -= it.value()->getBytesTotal(); - it.value()->setCache(NULL); + it.value()->setCache(nullptr); _unusedResources.erase(it); } } @@ -153,9 +150,7 @@ QList ResourceCache::_loadingRequests; Resource::Resource(const QUrl& url, bool delayLoad) : _url(url), - _request(url), - _lruKey(0), - _reply(NULL) { + _request(url) { init(); @@ -216,13 +211,13 @@ float Resource::getLoadPriority() { } void Resource::refresh() { - if (_reply == NULL && !(_loaded || _failedToLoad)) { + if (_reply == nullptr && !(_loaded || _failedToLoad)) { return; } if (_reply) { ResourceCache::requestCompleted(this); delete _reply; - _reply = NULL; + _reply = nullptr; } init(); _request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); @@ -298,10 +293,10 @@ void Resource::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { } _reply->disconnect(this); QNetworkReply* reply = _reply; - _reply = NULL; + _reply = nullptr; _replyTimer->disconnect(this); _replyTimer->deleteLater(); - _replyTimer = NULL; + _replyTimer = nullptr; ResourceCache::requestCompleted(this); downloadFinished(reply); @@ -333,10 +328,10 @@ void Resource::makeRequest() { void Resource::handleReplyError(QNetworkReply::NetworkError error, QDebug debug) { _reply->disconnect(this); _reply->deleteLater(); - _reply = NULL; + _reply = nullptr; _replyTimer->disconnect(this); _replyTimer->deleteLater(); - _replyTimer = NULL; + _replyTimer = nullptr; ResourceCache::requestCompleted(this); // retry for certain types of failures diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index b2bb8b5a39..8b5f1abc75 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -77,7 +77,7 @@ private: friend class Resource; QHash > _resources; - int _lastLRUKey; + int _lastLRUKey = 0; static int _requestLimit; static QList > _pendingRequests; @@ -158,9 +158,9 @@ protected: QUrl _url; QNetworkRequest _request; - bool _startedLoading; - bool _failedToLoad; - bool _loaded; + bool _startedLoading = false; + bool _failedToLoad = false; + bool _loaded = false; QHash, float> _loadPriorities; QWeakPointer _self; QPointer _cache; @@ -182,13 +182,12 @@ private: friend class ResourceCache; - int _lruKey; - QNetworkReply* _reply; - QTimer* _replyTimer; - int _index; - qint64 _bytesReceived; - qint64 _bytesTotal; - int _attempts; + int _lruKey = 0; + QNetworkReply* _reply = nullptr; + QTimer* _replyTimer = nullptr; + qint64 _bytesReceived = 0; + qint64 _bytesTotal = 0; + int _attempts = 0; }; uint qHash(const QPointer& value, uint seed = 0); From e70e435dcca6e7ad21656e90af083da9b60609d8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 12:45:13 -0800 Subject: [PATCH 31/51] Added Min/Max values for cache size --- libraries/networking/src/ResourceCache.cpp | 1 + libraries/networking/src/ResourceCache.h | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 089cdc5607..1187b311fc 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -166,6 +166,7 @@ Resource::~Resource() { if (_reply) { ResourceCache::requestCompleted(this); delete _reply; + _reply = nullptr; } } diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 8b5f1abc75..0c2b6d2ce8 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -28,7 +28,10 @@ class QTimer; class Resource; static constexpr qint64 BYTES_PER_MEGABYTES = 1024 * 1024; -static constexpr qint64 DEFAULT_MAX_SIZE = 100 * BYTES_PER_MEGABYTES; +static constexpr qint64 BYTES_PER_GIGABYTES = 1024 * BYTES_PER_MEGABYTES; +static constexpr qint64 DEFAULT_UNUSED_MAX_SIZE = 100 * BYTES_PER_MEGABYTES; +static constexpr qint64 MIN_UNUSED_MAX_SIZE = 0; +static constexpr qint64 MAX_UNUSED_MAX_SIZE = 10 * BYTES_PER_GIGABYTES; /// Base class for resource caches. class ResourceCache : public QObject { @@ -51,7 +54,7 @@ public: void refresh(const QUrl& url); protected: - qint64 _unusedResourcesMaxSize = DEFAULT_MAX_SIZE; + qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE; qint64 _unusedResourcesSize = 0; QMap > _unusedResources; From 5be5dc716f50de4f264405603e34c41721045b3f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 12:45:50 -0800 Subject: [PATCH 32/51] Make sure every widget has diolog has a parent --- interface/src/ui/LodToolsDialog.cpp | 26 ++++++++++---------------- interface/src/ui/LodToolsDialog.h | 7 +++---- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/interface/src/ui/LodToolsDialog.cpp b/interface/src/ui/LodToolsDialog.cpp index d9f2d788cd..8ff9eadc51 100644 --- a/interface/src/ui/LodToolsDialog.cpp +++ b/interface/src/ui/LodToolsDialog.cpp @@ -30,9 +30,9 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) : this->setWindowTitle("LOD Tools"); // Create layouter - QFormLayout* form = new QFormLayout(); + QFormLayout* form = new QFormLayout(this); - _lodSize = new QSlider(Qt::Horizontal); + _lodSize = new QSlider(Qt::Horizontal, this); const int MAX_LOD_SIZE = MAX_LOD_SIZE_MULTIPLIER; const int MIN_LOD_SIZE = 0; const int STEP_LOD_SIZE = 1; @@ -50,7 +50,7 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) : form->addRow("LOD Size Scale:", _lodSize); connect(_lodSize,SIGNAL(valueChanged(int)),this,SLOT(sizeScaleValueChanged(int))); - _boundaryLevelAdjust = new QSlider(Qt::Horizontal); + _boundaryLevelAdjust = new QSlider(Qt::Horizontal, this); const int MAX_ADJUST = 10; const int MIN_ADJUST = 0; const int STEP_ADJUST = 1; @@ -66,7 +66,7 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) : connect(_boundaryLevelAdjust,SIGNAL(valueChanged(int)),this,SLOT(boundaryLevelValueChanged(int))); // Create a label with feedback... - _feedback = new QLabel(); + _feedback = new QLabel(this); QPalette palette = _feedback->palette(); const unsigned redish = 0xfff00000; palette.setColor(QPalette::WindowText, QColor::fromRgb(redish)); @@ -76,21 +76,21 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) : _feedback->setFixedWidth(FEEDBACK_WIDTH); form->addRow("You can see... ", _feedback); - form->addRow("Automatic Avatar LOD Adjustment:", _automaticAvatarLOD = new QCheckBox()); + form->addRow("Automatic Avatar LOD Adjustment:", _automaticAvatarLOD = new QCheckBox(this)); _automaticAvatarLOD->setChecked(Menu::getInstance()->getAutomaticAvatarLOD()); connect(_automaticAvatarLOD, SIGNAL(toggled(bool)), SLOT(updateAvatarLODControls())); - form->addRow("Decrease Avatar LOD Below FPS:", _avatarLODDecreaseFPS = new QDoubleSpinBox()); + form->addRow("Decrease Avatar LOD Below FPS:", _avatarLODDecreaseFPS = new QDoubleSpinBox(this)); _avatarLODDecreaseFPS->setValue(Menu::getInstance()->getAvatarLODDecreaseFPS()); _avatarLODDecreaseFPS->setDecimals(0); connect(_avatarLODDecreaseFPS, SIGNAL(valueChanged(double)), SLOT(updateAvatarLODValues())); - form->addRow("Increase Avatar LOD Above FPS:", _avatarLODIncreaseFPS = new QDoubleSpinBox()); + form->addRow("Increase Avatar LOD Above FPS:", _avatarLODIncreaseFPS = new QDoubleSpinBox(this)); _avatarLODIncreaseFPS->setValue(Menu::getInstance()->getAvatarLODIncreaseFPS()); _avatarLODIncreaseFPS->setDecimals(0); connect(_avatarLODIncreaseFPS, SIGNAL(valueChanged(double)), SLOT(updateAvatarLODValues())); - form->addRow("Avatar LOD:", _avatarLOD = new QDoubleSpinBox()); + form->addRow("Avatar LOD:", _avatarLOD = new QDoubleSpinBox(this)); _avatarLOD->setDecimals(3); _avatarLOD->setRange(1.0 / MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER, 1.0 / MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER); _avatarLOD->setSingleStep(0.001); @@ -98,21 +98,15 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) : connect(_avatarLOD, SIGNAL(valueChanged(double)), SLOT(updateAvatarLODValues())); // Add a button to reset - QPushButton* resetButton = new QPushButton("Reset"); + QPushButton* resetButton = new QPushButton("Reset", this); form->addRow("", resetButton); - connect(resetButton,SIGNAL(clicked(bool)),this,SLOT(resetClicked(bool))); + connect(resetButton, SIGNAL(clicked(bool)), this, SLOT(resetClicked(bool))); this->QDialog::setLayout(form); updateAvatarLODControls(); } -LodToolsDialog::~LodToolsDialog() { - delete _feedback; - delete _lodSize; - delete _boundaryLevelAdjust; -} - void LodToolsDialog::reloadSliders() { _lodSize->setValue(Menu::getInstance()->getOctreeSizeScale() / TREE_SCALE); _boundaryLevelAdjust->setValue(Menu::getInstance()->getBoundaryLevelAdjust()); diff --git a/interface/src/ui/LodToolsDialog.h b/interface/src/ui/LodToolsDialog.h index 5b34a5efd0..772027790c 100644 --- a/interface/src/ui/LodToolsDialog.h +++ b/interface/src/ui/LodToolsDialog.h @@ -13,18 +13,17 @@ #define hifi_LodToolsDialog_h #include -#include -#include class QCheckBox; class QDoubleSpinBox; +class QLabel; +class QSlider; class LodToolsDialog : public QDialog { Q_OBJECT public: // Sets up the UI LodToolsDialog(QWidget* parent); - ~LodToolsDialog(); signals: void closed(); @@ -41,7 +40,7 @@ public slots: protected: // Emits a 'closed' signal when this dialog is closed. - void closeEvent(QCloseEvent*); + void closeEvent(QCloseEvent* event); private: QSlider* _lodSize; From 38dc1643ef9ed139c9a0418286eec905dd6dbd64 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 12:46:11 -0800 Subject: [PATCH 33/51] New Caches size dialog --- interface/src/ui/CachesSizeDialog.cpp | 83 +++++++++++++++++++++++++++ interface/src/ui/CachesSizeDialog.h | 45 +++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 interface/src/ui/CachesSizeDialog.cpp create mode 100644 interface/src/ui/CachesSizeDialog.h diff --git a/interface/src/ui/CachesSizeDialog.cpp b/interface/src/ui/CachesSizeDialog.cpp new file mode 100644 index 0000000000..9e5d1fd9e0 --- /dev/null +++ b/interface/src/ui/CachesSizeDialog.cpp @@ -0,0 +1,83 @@ +// +// CachesSizeDialog.cpp +// +// +// Created by Clement on 1/12/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "CachesSizeDialog.h" + + +QDoubleSpinBox* createDoubleSpinBox(QWidget* parent) { + QDoubleSpinBox* box = new QDoubleSpinBox(parent); + box->setDecimals(0); + box->setRange(MIN_UNUSED_MAX_SIZE / BYTES_PER_MEGABYTES, MAX_UNUSED_MAX_SIZE / BYTES_PER_MEGABYTES); + + return box; +} + +CachesSizeDialog::CachesSizeDialog(QWidget* parent) : + QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint) +{ + setWindowTitle("Caches Size"); + + // Create layouter + QFormLayout* form = new QFormLayout(this); + setLayout(form); + + form->addRow("Animations cache size (MB):", _animations = createDoubleSpinBox(this)); + form->addRow("Geometries cache size (MB):", _geometries = createDoubleSpinBox(this)); + form->addRow("Scripts cache size (MB):", _scripts = createDoubleSpinBox(this)); + form->addRow("Sounds cache size (MB):", _sounds = createDoubleSpinBox(this)); + form->addRow("Textures cache size (MB):", _textures = createDoubleSpinBox(this)); + + resetClicked(true); + + // Add a button to reset + QPushButton* confirmButton = new QPushButton("Confirm", this); + QPushButton* resetButton = new QPushButton("Reset", this); + form->addRow(confirmButton, resetButton); + connect(confirmButton, SIGNAL(clicked(bool)), this, SLOT(confirmClicked(bool))); + connect(resetButton, SIGNAL(clicked(bool)), this, SLOT(resetClicked(bool))); +} + +void CachesSizeDialog::confirmClicked(bool checked) { + DependencyManager::get()->setUnusedResourceCacheSize(_animations->value() * BYTES_PER_MEGABYTES); + DependencyManager::get()->setUnusedResourceCacheSize(_geometries->value() * BYTES_PER_MEGABYTES); + DependencyManager::get()->setUnusedResourceCacheSize(_scripts->value() * BYTES_PER_MEGABYTES); + DependencyManager::get()->setUnusedResourceCacheSize(_sounds->value() * BYTES_PER_MEGABYTES); + DependencyManager::get()->setUnusedResourceCacheSize(_textures->value() * BYTES_PER_MEGABYTES); +} + +void CachesSizeDialog::resetClicked(bool checked) { + _animations->setValue(DependencyManager::get()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES); + _geometries->setValue(DependencyManager::get()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES); + _scripts->setValue(DependencyManager::get()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES); + _sounds->setValue(DependencyManager::get()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES); + _textures->setValue(DependencyManager::get()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES); +} + +void CachesSizeDialog::reject() { + // Just regularly close upon ESC + this->QDialog::close(); +} + +void CachesSizeDialog::closeEvent(QCloseEvent* event) { + this->QDialog::closeEvent(event); + emit closed(); +} \ No newline at end of file diff --git a/interface/src/ui/CachesSizeDialog.h b/interface/src/ui/CachesSizeDialog.h new file mode 100644 index 0000000000..fa01ce4534 --- /dev/null +++ b/interface/src/ui/CachesSizeDialog.h @@ -0,0 +1,45 @@ +// +// CachesSizeDialog.h +// +// +// Created by Clement on 1/12/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_CachesSizeDialog_h +#define hifi_CachesSizeDialog_h + +#include + +class QDoubleSpinBox; + +class CachesSizeDialog : public QDialog { + Q_OBJECT +public: + // Sets up the UI + CachesSizeDialog(QWidget* parent); + +signals: + void closed(); + +public slots: + void reject(); + void confirmClicked(bool checked); + void resetClicked(bool checked); + +protected: + // Emits a 'closed' signal when this dialog is closed. + void closeEvent(QCloseEvent* event); + +private: + QDoubleSpinBox* _animations = nullptr; + QDoubleSpinBox* _geometries = nullptr; + QDoubleSpinBox* _scripts = nullptr; + QDoubleSpinBox* _sounds = nullptr; + QDoubleSpinBox* _textures = nullptr; +}; + +#endif // hifi_CachesSizeDialog_h \ No newline at end of file From 19f321c171ce1d8cd679b8df2c850d2cab265321 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 13:56:41 -0800 Subject: [PATCH 34/51] Fixed caches not in DM --- interface/src/ui/CachesSizeDialog.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/ui/CachesSizeDialog.cpp b/interface/src/ui/CachesSizeDialog.cpp index 9e5d1fd9e0..12e88f5100 100644 --- a/interface/src/ui/CachesSizeDialog.cpp +++ b/interface/src/ui/CachesSizeDialog.cpp @@ -59,16 +59,16 @@ CachesSizeDialog::CachesSizeDialog(QWidget* parent) : void CachesSizeDialog::confirmClicked(bool checked) { DependencyManager::get()->setUnusedResourceCacheSize(_animations->value() * BYTES_PER_MEGABYTES); DependencyManager::get()->setUnusedResourceCacheSize(_geometries->value() * BYTES_PER_MEGABYTES); - DependencyManager::get()->setUnusedResourceCacheSize(_scripts->value() * BYTES_PER_MEGABYTES); - DependencyManager::get()->setUnusedResourceCacheSize(_sounds->value() * BYTES_PER_MEGABYTES); + ScriptCache::getInstance()->setUnusedResourceCacheSize(_scripts->value() * BYTES_PER_MEGABYTES); + SoundCache::getInstance().setUnusedResourceCacheSize(_sounds->value() * BYTES_PER_MEGABYTES); DependencyManager::get()->setUnusedResourceCacheSize(_textures->value() * BYTES_PER_MEGABYTES); } void CachesSizeDialog::resetClicked(bool checked) { _animations->setValue(DependencyManager::get()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES); _geometries->setValue(DependencyManager::get()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES); - _scripts->setValue(DependencyManager::get()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES); - _sounds->setValue(DependencyManager::get()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES); + _scripts->setValue(ScriptCache::getInstance()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES); + _sounds->setValue(SoundCache::getInstance().getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES); _textures->setValue(DependencyManager::get()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES); } From 894c4c9d59c0692e6b93a64a5a5c9781057e04aa Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 14:00:23 -0800 Subject: [PATCH 35/51] All dialogs in Menu are QPointers --- interface/src/Menu.cpp | 10 ++-------- interface/src/Menu.h | 12 ++++++------ 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index c50c722d4a..d4b4671ac1 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -93,17 +93,11 @@ const int CONSOLE_HEIGHT = 200; Menu::Menu() : _actionHash(), _receivedAudioStreamSettings(), - _bandwidthDialog(NULL), _fieldOfView(DEFAULT_FIELD_OF_VIEW_DEGREES), _realWorldFieldOfView(DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES), _faceshiftEyeDeflection(DEFAULT_FACESHIFT_EYE_DEFLECTION), _faceshiftHostname(DEFAULT_FACESHIFT_HOSTNAME), _jsConsole(NULL), - _octreeStatsDialog(NULL), - _lodToolsDialog(NULL), - _hmdToolsDialog(NULL), - _newLocationDialog(NULL), - _userLocationsDialog(NULL), #if defined(Q_OS_MAC) || defined(Q_OS_WIN) _speechRecognizer(), #endif @@ -122,8 +116,8 @@ Menu::Menu() : _fpsAverage(FIVE_SECONDS_OF_FRAMES), _fastFPSAverage(ONE_SECOND_OF_FRAMES), _loginAction(NULL), - _preferencesDialog(NULL), - _loginDialog(NULL), + _newLocationDialog(NULL), + _userLocationsDialog(NULL), _hasLoginDialogDisplayed(false), _snapshotsLocation(), _scriptsLocation(), diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 20408f1406..20a7e7ebb8 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -242,7 +242,6 @@ private: QHash _actionHash; InboundAudioStream::Settings _receivedAudioStreamSettings; - BandwidthDialog* _bandwidthDialog; float _fieldOfView; /// in Degrees, doesn't apply to HMD like Oculus float _realWorldFieldOfView; // The actual FOV set by the user's monitor size and view distance float _faceshiftEyeDeflection; @@ -252,11 +251,6 @@ private: QPointer _ScriptEditor; QPointer _chatWindow; QDialog* _jsConsole; - OctreeStatsDialog* _octreeStatsDialog; - LodToolsDialog* _lodToolsDialog; - HMDToolsDialog* _hmdToolsDialog; - QPointer _newLocationDialog; - QPointer _userLocationsDialog; #if defined(Q_OS_MAC) || defined(Q_OS_WIN) SpeechRecognizer _speechRecognizer; #endif @@ -276,6 +270,12 @@ private: SimpleMovingAverage _fpsAverage; SimpleMovingAverage _fastFPSAverage; QAction* _loginAction; + QPointer _bandwidthDialog; + QPointer _octreeStatsDialog; + QPointer _lodToolsDialog; + QPointer _hmdToolsDialog; + QPointer _newLocationDialog; + QPointer _userLocationsDialog; QPointer _preferencesDialog; QPointer _attachmentsDialog; QPointer _animationsDialog; From fd2b0edf7a65c1d977b94350ac9e07f89bc3cfdb Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 14:01:56 -0800 Subject: [PATCH 36/51] Alphabetical order --- interface/src/Menu.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 20a7e7ebb8..502ab01633 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -270,17 +270,17 @@ private: SimpleMovingAverage _fpsAverage; SimpleMovingAverage _fastFPSAverage; QAction* _loginAction; + QPointer _addressBarDialog; + QPointer _animationsDialog; + QPointer _attachmentsDialog; QPointer _bandwidthDialog; - QPointer _octreeStatsDialog; - QPointer _lodToolsDialog; - QPointer _hmdToolsDialog; QPointer _newLocationDialog; QPointer _userLocationsDialog; - QPointer _preferencesDialog; - QPointer _attachmentsDialog; - QPointer _animationsDialog; - QPointer _addressBarDialog; + QPointer _hmdToolsDialog; + QPointer _lodToolsDialog; QPointer _loginDialog; + QPointer _octreeStatsDialog; + QPointer _preferencesDialog; bool _hasLoginDialogDisplayed; QAction* _chatAction; QString _snapshotsLocation; From e62fbe25579b385619abe8dd934859f79f4c497c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 14:09:26 -0800 Subject: [PATCH 37/51] Cleanup some headers --- interface/src/Menu.cpp | 32 ++++++++------------------------ interface/src/Menu.h | 11 +++++------ 2 files changed, 13 insertions(+), 30 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d4b4671ac1..c25ab67db5 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -51,13 +51,20 @@ #include "scripting/LocationScriptingInterface.h" #include "scripting/MenuScriptingInterface.h" #include "Util.h" +#include "ui/AddressBarDialog.h" #include "ui/AnimationsDialog.h" #include "ui/AttachmentsDialog.h" +#include "ui/BandwidthDialog" +#include "ui/DataWebDialog" +#include "ui/HMDToolsDialog" +#include "ui/LodToolsDialog" +#include "ui/LoginDialog.h" +#include "ui/OctreeStatsDialog" +#include "ui/PreferencesDialog" #include "ui/InfoView.h" #include "ui/MetavoxelEditor.h" #include "ui/MetavoxelNetworkSimulator.h" #include "ui/ModelsBrowser.h" -#include "ui/LoginDialog.h" #include "ui/NodeBounds.h" Menu* Menu::_instance = NULL; @@ -613,15 +620,6 @@ Menu::Menu() : #endif } -Menu::~Menu() { - bandwidthDetailsClosed(); - octreeStatsDetailsClosed(); - if (_hmdToolsDialog) { - delete _hmdToolsDialog; - _hmdToolsDialog = NULL; - } -} - void Menu::loadSettings(QSettings* settings) { bool lockedSettings = false; if (!settings) { @@ -1247,13 +1245,6 @@ void Menu::audioMuteToggled() { } } -void Menu::bandwidthDetailsClosed() { - if (_bandwidthDialog) { - delete _bandwidthDialog; - _bandwidthDialog = NULL; - } -} - void Menu::octreeStatsDetails() { if (!_octreeStatsDialog) { _octreeStatsDialog = new OctreeStatsDialog(DependencyManager::get().data(), @@ -1267,13 +1258,6 @@ void Menu::octreeStatsDetails() { _octreeStatsDialog->raise(); } -void Menu::octreeStatsDetailsClosed() { - if (_octreeStatsDialog) { - delete _octreeStatsDialog; - _octreeStatsDialog = NULL; - } -} - QString Menu::getLODFeedbackText() { // determine granularity feedback int boundaryLevelAdjust = getBoundaryLevelAdjust(); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 502ab01633..2cd9c8ecf2 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -27,12 +27,8 @@ #include "SpeechRecognizer.h" #endif -#include "ui/AddressBarDialog.h" #include "ui/ChatWindow.h" -#include "ui/DataWebDialog.h" #include "ui/JSConsole.h" -#include "ui/LoginDialog.h" -#include "ui/PreferencesDialog.h" #include "ui/ScriptEditorWindow.h" const float ADJUST_LOD_DOWN_FPS = 40.0; @@ -54,22 +50,25 @@ const float MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 15.0f; const QString SETTINGS_ADDRESS_KEY = "address"; class QSettings; +class AddressBarDialog; class AnimationsDialog; class AttachmentsDialog; class BandwidthDialog; +class DataWebDialog; class HMDToolsDialog; class LodToolsDialog; +class LoginDialog; +class OctreeStatsDialog; +class PreferencesDialog; class MetavoxelEditor; class MetavoxelNetworkSimulator; class ChatWindow; -class OctreeStatsDialog; class MenuItemProperties; class Menu : public QMenuBar { Q_OBJECT public: static Menu* getInstance(); - ~Menu(); void triggerOption(const QString& menuOption); QAction* getActionForOption(const QString& menuOption); From 7bf57b3cca68b09d75fc83d87ecb618b2241a175 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 14:53:31 -0800 Subject: [PATCH 38/51] Removed unecessary method/cleanup header --- interface/src/Menu.cpp | 32 ++++++++++---------------------- interface/src/Menu.h | 10 ++++------ 2 files changed, 14 insertions(+), 28 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index c25ab67db5..3e4f2c212a 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -54,13 +54,14 @@ #include "ui/AddressBarDialog.h" #include "ui/AnimationsDialog.h" #include "ui/AttachmentsDialog.h" -#include "ui/BandwidthDialog" -#include "ui/DataWebDialog" -#include "ui/HMDToolsDialog" -#include "ui/LodToolsDialog" +#include "ui/BandwidthDialog.h" +#include "ui/CachesSizeDialog.h" +#include "ui/DataWebDialog.h" +#include "ui/HMDToolsDialog.h" +#include "ui/LodToolsDialog.h" #include "ui/LoginDialog.h" -#include "ui/OctreeStatsDialog" -#include "ui/PreferencesDialog" +#include "ui/OctreeStatsDialog.h" +#include "ui/PreferencesDialog.h" #include "ui/InfoView.h" #include "ui/MetavoxelEditor.h" #include "ui/MetavoxelNetworkSimulator.h" @@ -122,13 +123,7 @@ Menu::Menu() : _lastAvatarDetailDrop(usecTimestampNow()), _fpsAverage(FIVE_SECONDS_OF_FRAMES), _fastFPSAverage(ONE_SECOND_OF_FRAMES), - _loginAction(NULL), - _newLocationDialog(NULL), - _userLocationsDialog(NULL), _hasLoginDialogDisplayed(false), - _snapshotsLocation(), - _scriptsLocation(), - _walletPrivateKey(), _shouldRenderTableNeedsRebuilding(true) { Application *appInstance = Application::getInstance(); @@ -1145,7 +1140,7 @@ void Menu::bandwidthDetails() { if (! _bandwidthDialog) { _bandwidthDialog = new BandwidthDialog(DependencyManager::get().data(), Application::getInstance()->getBandwidthMeter()); - connect(_bandwidthDialog, SIGNAL(closed()), SLOT(bandwidthDetailsClosed())); + connect(_bandwidthDialog, SIGNAL(closed()), _bandwidthDialog, SLOT(deleteLater())); _bandwidthDialog->show(); @@ -1249,7 +1244,7 @@ void Menu::octreeStatsDetails() { if (!_octreeStatsDialog) { _octreeStatsDialog = new OctreeStatsDialog(DependencyManager::get().data(), Application::getInstance()->getOcteeSceneStats()); - connect(_octreeStatsDialog, SIGNAL(closed()), SLOT(octreeStatsDetailsClosed())); + connect(_octreeStatsDialog, SIGNAL(closed()), _octreeStatsDialog, SLOT(deleteLater())); _octreeStatsDialog->show(); if (_hmdToolsDialog) { _hmdToolsDialog->watchWindow(_octreeStatsDialog->windowHandle()); @@ -1425,7 +1420,7 @@ bool Menu::shouldRenderMesh(float largestDimension, float distanceToCamera) { void Menu::lodTools() { if (!_lodToolsDialog) { _lodToolsDialog = new LodToolsDialog(DependencyManager::get().data()); - connect(_lodToolsDialog, SIGNAL(closed()), SLOT(lodToolsClosed())); + connect(_lodToolsDialog, SIGNAL(closed()), _lodToolsDialog, SLOT(deleteLater())); _lodToolsDialog->show(); if (_hmdToolsDialog) { _hmdToolsDialog->watchWindow(_lodToolsDialog->windowHandle()); @@ -1434,13 +1429,6 @@ void Menu::lodTools() { _lodToolsDialog->raise(); } -void Menu::lodToolsClosed() { - if (_lodToolsDialog) { - delete _lodToolsDialog; - _lodToolsDialog = NULL; - } -} - void Menu::hmdTools(bool showTools) { if (showTools) { if (!_hmdToolsDialog) { diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 2cd9c8ecf2..3bc15fd99a 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -53,6 +53,7 @@ class QSettings; class AddressBarDialog; class AnimationsDialog; class AttachmentsDialog; +class CachesSizeDialog; class BandwidthDialog; class DataWebDialog; class HMDToolsDialog; @@ -190,9 +191,6 @@ private slots: void changePrivateKey(); void nameLocation(); void toggleLocationList(); - void bandwidthDetailsClosed(); - void octreeStatsDetailsClosed(); - void lodToolsClosed(); void hmdToolsClosed(); void runTests(); void showMetavoxelEditor(); @@ -263,16 +261,15 @@ private: float _avatarLODDistanceMultiplier; int _boundaryLevelAdjust; int _maxOctreePacketsPerSecond; - QString replaceLastOccurrence(QChar search, QChar replace, QString string); quint64 _lastAdjust; quint64 _lastAvatarDetailDrop; SimpleMovingAverage _fpsAverage; SimpleMovingAverage _fastFPSAverage; - QAction* _loginAction; QPointer _addressBarDialog; QPointer _animationsDialog; QPointer _attachmentsDialog; QPointer _bandwidthDialog; + QPointer _cachesSizeDialog; QPointer _newLocationDialog; QPointer _userLocationsDialog; QPointer _hmdToolsDialog; @@ -281,7 +278,8 @@ private: QPointer _octreeStatsDialog; QPointer _preferencesDialog; bool _hasLoginDialogDisplayed; - QAction* _chatAction; + QAction* _loginAction = nullptr; + QAction* _chatAction = nullptr; QString _snapshotsLocation; QString _scriptsLocation; QByteArray _walletPrivateKey; From 208af5cbca5cd62e3ea4fce00aeeea68b1a59ed4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jan 2015 15:14:49 -0800 Subject: [PATCH 39/51] Revert "don't play muzak from lobby to avoid error" This reverts commit 69f5c769b8c4f930e3b02c19e644223adee9203b. --- examples/lobby.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/lobby.js b/examples/lobby.js index e34d119502..b03be7c29b 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -139,10 +139,10 @@ function drawLobby() { MyAvatar.attach(HELMET_ATTACHMENT_URL, "Neck", {x: 0, y: 0, z: 0}, Quat.fromPitchYawRollDegrees(0, 0, 0), 1.15); // start the drone sound - // currentDrone = Audio.playSound(droneSound, { stereo: true, loop: true, localOnly: true, volume: DRONE_VOLUME }); + currentDrone = Audio.playSound(droneSound, { stereo: true, loop: true, localOnly: true, volume: DRONE_VOLUME }); // start one of our muzak sounds - // playRandomMuzak(); + playRandomMuzak(); } } @@ -353,9 +353,9 @@ function update(deltaTime) { Overlays.editOverlay(descriptionText, { position: textOverlayPosition() }); // if the reticle is up then we may need to play the next muzak - // if (!Audio.isInjectorPlaying(currentMuzakInjector)) { -// playNextMuzak(); -// } + if (!Audio.isInjectorPlaying(currentMuzakInjector)) { + playNextMuzak(); + } } } From 59c9e0bb50aa08925921a5e56d1d783942255b8f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 15:19:36 -0800 Subject: [PATCH 40/51] Wire CachesSizeDialog in Menu --- interface/src/Menu.cpp | 13 +++++++++++++ interface/src/Menu.h | 2 ++ interface/src/ui/CachesSizeDialog.cpp | 6 ++++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 3e4f2c212a..2cc16102b0 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -488,6 +488,7 @@ Menu::Menu() : false, &UserActivityLogger::getInstance(), SLOT(disable(bool))); + addActionToQMenuAndActionHash(networkMenu, MenuOption::CachesSize, 0, this, SLOT(cachesSizeDialog())); addActionToQMenuAndActionHash(developerMenu, MenuOption::WalletPrivateKey, 0, this, SLOT(changePrivateKey())); @@ -1416,6 +1417,18 @@ bool Menu::shouldRenderMesh(float largestDimension, float distanceToCamera) { return (distanceToCamera <= visibleDistanceAtClosestScale); } +void Menu::cachesSizeDialog() { + qDebug() << "Caches size:" << _cachesSizeDialog.isNull(); + if (!_cachesSizeDialog) { + _cachesSizeDialog = new CachesSizeDialog(DependencyManager::get().data()); + connect(_cachesSizeDialog, SIGNAL(closed()), _cachesSizeDialog, SLOT(deleteLater())); + _cachesSizeDialog->show(); + if (_hmdToolsDialog) { + _hmdToolsDialog->watchWindow(_cachesSizeDialog->windowHandle()); + } + } + _cachesSizeDialog->raise(); +} void Menu::lodTools() { if (!_lodToolsDialog) { diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 3bc15fd99a..c23559229d 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -159,6 +159,7 @@ public slots: void showLoginForCurrentDomain(); void bandwidthDetails(); void octreeStatsDetails(); + void cachesSizeDialog(); void lodTools(); void hmdTools(bool showTools); void loadSettings(QSettings* settings = NULL); @@ -315,6 +316,7 @@ namespace MenuOption { const QString BandwidthDetails = "Bandwidth Details"; const QString BlueSpeechSphere = "Blue Sphere While Speaking"; const QString CascadedShadows = "Cascaded"; + const QString CachesSize = "Caches Size"; const QString Chat = "Chat..."; const QString ChatCircling = "Chat Circling"; const QString CollideAsRagdoll = "Collide With Self (Ragdoll)"; diff --git a/interface/src/ui/CachesSizeDialog.cpp b/interface/src/ui/CachesSizeDialog.cpp index 12e88f5100..4d4457c922 100644 --- a/interface/src/ui/CachesSizeDialog.cpp +++ b/interface/src/ui/CachesSizeDialog.cpp @@ -62,6 +62,8 @@ void CachesSizeDialog::confirmClicked(bool checked) { ScriptCache::getInstance()->setUnusedResourceCacheSize(_scripts->value() * BYTES_PER_MEGABYTES); SoundCache::getInstance().setUnusedResourceCacheSize(_sounds->value() * BYTES_PER_MEGABYTES); DependencyManager::get()->setUnusedResourceCacheSize(_textures->value() * BYTES_PER_MEGABYTES); + + QDialog::close(); } void CachesSizeDialog::resetClicked(bool checked) { @@ -74,10 +76,10 @@ void CachesSizeDialog::resetClicked(bool checked) { void CachesSizeDialog::reject() { // Just regularly close upon ESC - this->QDialog::close(); + QDialog::close(); } void CachesSizeDialog::closeEvent(QCloseEvent* event) { - this->QDialog::closeEvent(event); + QDialog::closeEvent(event); emit closed(); } \ No newline at end of file From 8415098fc2ef0a22735d7662af3c6d1ae4c287e2 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 15:36:36 -0800 Subject: [PATCH 41/51] Set different caches size depending on cache type --- libraries/animation/src/AnimationCache.cpp | 5 ++++- libraries/audio/src/SoundCache.cpp | 3 ++- libraries/metavoxels/src/ScriptCache.cpp | 7 +++++-- libraries/networking/src/ResourceCache.cpp | 4 +++- libraries/networking/src/ResourceCache.h | 7 +++++++ libraries/render-utils/src/GeometryCache.cpp | 2 ++ libraries/render-utils/src/TextureCache.cpp | 2 ++ 7 files changed, 25 insertions(+), 5 deletions(-) diff --git a/libraries/animation/src/AnimationCache.cpp b/libraries/animation/src/AnimationCache.cpp index 1a68aeb908..6c02ccbd2b 100644 --- a/libraries/animation/src/AnimationCache.cpp +++ b/libraries/animation/src/AnimationCache.cpp @@ -17,7 +17,10 @@ static int animationPointerMetaTypeId = qRegisterMetaType(); AnimationCache::AnimationCache(QObject* parent) : - ResourceCache(parent) { + ResourceCache(parent) +{ + const qint64 ANIMATION_DEFAULT_UNUSED_MAX_SIZE = 50 * BYTES_PER_MEGABYTES; + setUnusedResourceCacheSize(ANIMATION_DEFAULT_UNUSED_MAX_SIZE); } AnimationPointer AnimationCache::getAnimation(const QUrl& url) { diff --git a/libraries/audio/src/SoundCache.cpp b/libraries/audio/src/SoundCache.cpp index 4fbd98fea0..fe05372ce5 100644 --- a/libraries/audio/src/SoundCache.cpp +++ b/libraries/audio/src/SoundCache.cpp @@ -23,7 +23,8 @@ SoundCache& SoundCache::getInstance() { SoundCache::SoundCache(QObject* parent) : ResourceCache(parent) { - + const qint64 SOUND_DEFAULT_UNUSED_MAX_SIZE = 50 * BYTES_PER_MEGABYTES; + setUnusedResourceCacheSize(SOUND_DEFAULT_UNUSED_MAX_SIZE); } SharedSoundPointer SoundCache::getSound(const QUrl& url) { diff --git a/libraries/metavoxels/src/ScriptCache.cpp b/libraries/metavoxels/src/ScriptCache.cpp index ffd5200a2e..7e8dbc4bae 100644 --- a/libraries/metavoxels/src/ScriptCache.cpp +++ b/libraries/metavoxels/src/ScriptCache.cpp @@ -109,9 +109,12 @@ ScriptCache* ScriptCache::getInstance() { } ScriptCache::ScriptCache() : - _engine(NULL) { - + _engine(NULL) +{ setEngine(new QScriptEngine(this)); + + const qint64 SCRIPT_DEFAULT_UNUSED_MAX_SIZE = 50 * BYTES_PER_MEGABYTES; + setUnusedResourceCacheSize(SCRIPT_DEFAULT_UNUSED_MAX_SIZE); } void ScriptCache::setEngine(QScriptEngine* engine) { diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 1187b311fc..f4d9a2909d 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -16,6 +16,8 @@ #include #include +#include + #include "NetworkAccessManager.h" #include "ResourceCache.h" @@ -70,7 +72,7 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& } void ResourceCache::setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize) { - _unusedResourcesMaxSize = unusedResourcesMaxSize; + _unusedResourcesMaxSize = glm::clamp(unusedResourcesMaxSize, MIN_UNUSED_MAX_SIZE, MAX_UNUSED_MAX_SIZE); reserveUnusedResource(0); } diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 0c2b6d2ce8..7b8ffc392b 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -29,7 +29,14 @@ class Resource; static constexpr qint64 BYTES_PER_MEGABYTES = 1024 * 1024; static constexpr qint64 BYTES_PER_GIGABYTES = 1024 * BYTES_PER_MEGABYTES; + +// Windows can have troubles allocating that much memory in ram sometimes +// so default cache size at 100 MB on windows (1GB otherwise) +#ifdef Q_OS_WIN32 static constexpr qint64 DEFAULT_UNUSED_MAX_SIZE = 100 * BYTES_PER_MEGABYTES; +#else +static constexpr qint64 DEFAULT_UNUSED_MAX_SIZE = 1024 * BYTES_PER_MEGABYTES; +#endif static constexpr qint64 MIN_UNUSED_MAX_SIZE = 0; static constexpr qint64 MAX_UNUSED_MAX_SIZE = 10 * BYTES_PER_GIGABYTES; diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 553e460a5c..25f988472f 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -30,6 +30,8 @@ const int GeometryCache::UNKNOWN_ID = -1; GeometryCache::GeometryCache() : _nextID(0) { + const qint64 GEOMETRY_DEFAULT_UNUSED_MAX_SIZE = DEFAULT_UNUSED_MAX_SIZE; + setUnusedResourceCacheSize(GEOMETRY_DEFAULT_UNUSED_MAX_SIZE); } GeometryCache::~GeometryCache() { diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index 0f34282162..3bd05a14ee 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -39,6 +39,8 @@ TextureCache::TextureCache() : _frameBufferSize(100, 100), _associatedWidget(NULL) { + const qint64 TEXTURE_DEFAULT_UNUSED_MAX_SIZE = DEFAULT_UNUSED_MAX_SIZE; + setUnusedResourceCacheSize(TEXTURE_DEFAULT_UNUSED_MAX_SIZE); } TextureCache::~TextureCache() { From e30b119464303707dc29ce64fe88c54ceeeee673 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 15:55:25 -0800 Subject: [PATCH 42/51] Some simple code cleanup --- interface/src/Menu.cpp | 37 +------------- interface/src/Menu.h | 65 +++++++++++++++---------- interface/src/ui/JSConsole.h | 5 ++ interface/src/ui/ScriptEditorWindow.cpp | 2 - 4 files changed, 46 insertions(+), 63 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 2cc16102b0..48403b7511 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -87,44 +87,9 @@ Menu* Menu::getInstance() { return _instance; } -const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f; -const QString DEFAULT_FACESHIFT_HOSTNAME = "localhost"; -const float DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER = 1.0f; -const int ONE_SECOND_OF_FRAMES = 60; -const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES; - -const QString CONSOLE_TITLE = "Scripting Console"; -const float CONSOLE_WINDOW_OPACITY = 0.95f; -const int CONSOLE_WIDTH = 800; -const int CONSOLE_HEIGHT = 200; - Menu::Menu() : - _actionHash(), - _receivedAudioStreamSettings(), - _fieldOfView(DEFAULT_FIELD_OF_VIEW_DEGREES), - _realWorldFieldOfView(DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES), - _faceshiftEyeDeflection(DEFAULT_FACESHIFT_EYE_DEFLECTION), - _faceshiftHostname(DEFAULT_FACESHIFT_HOSTNAME), - _jsConsole(NULL), -#if defined(Q_OS_MAC) || defined(Q_OS_WIN) - _speechRecognizer(), -#endif - _octreeSizeScale(DEFAULT_OCTREE_SIZE_SCALE), - _oculusUIAngularSize(DEFAULT_OCULUS_UI_ANGULAR_SIZE), - _sixenseReticleMoveSpeed(DEFAULT_SIXENSE_RETICLE_MOVE_SPEED), - _invertSixenseButtons(DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS), - _automaticAvatarLOD(true), - _avatarLODDecreaseFPS(DEFAULT_ADJUST_AVATAR_LOD_DOWN_FPS), - _avatarLODIncreaseFPS(ADJUST_LOD_UP_FPS), - _avatarLODDistanceMultiplier(DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER), - _boundaryLevelAdjust(0), - _maxOctreePacketsPerSecond(DEFAULT_MAX_OCTREE_PPS), _lastAdjust(usecTimestampNow()), - _lastAvatarDetailDrop(usecTimestampNow()), - _fpsAverage(FIVE_SECONDS_OF_FRAMES), - _fastFPSAverage(ONE_SECOND_OF_FRAMES), - _hasLoginDialogDisplayed(false), - _shouldRenderTableNeedsRebuilding(true) + _lastAvatarDetailDrop(usecTimestampNow()) { Application *appInstance = Application::getInstance(); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index c23559229d..563ed42d30 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -48,6 +48,13 @@ const float MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 0.1f; const float MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 15.0f; const QString SETTINGS_ADDRESS_KEY = "address"; + +const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f; +const QString DEFAULT_FACESHIFT_HOSTNAME = "localhost"; +const float DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER = 1.0f; +const int ONE_SECOND_OF_FRAMES = 60; +const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES; + class QSettings; class AddressBarDialog; @@ -240,32 +247,37 @@ private: QHash _actionHash; InboundAudioStream::Settings _receivedAudioStreamSettings; - float _fieldOfView; /// in Degrees, doesn't apply to HMD like Oculus - float _realWorldFieldOfView; // The actual FOV set by the user's monitor size and view distance - float _faceshiftEyeDeflection; - QString _faceshiftHostname; - QPointer _MetavoxelEditor; - QPointer _metavoxelNetworkSimulator; - QPointer _ScriptEditor; - QPointer _chatWindow; - QDialog* _jsConsole; + // in Degrees, doesn't apply to HMD like Oculus + float _fieldOfView = DEFAULT_FIELD_OF_VIEW_DEGREES; + // The actual FOV set by the user's monitor size and view distance + float _realWorldFieldOfView = DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES; + float _faceshiftEyeDeflection = DEFAULT_FACESHIFT_EYE_DEFLECTION; + QString _faceshiftHostname = DEFAULT_FACESHIFT_HOSTNAME; + + QDialog* _jsConsole = nullptr; #if defined(Q_OS_MAC) || defined(Q_OS_WIN) SpeechRecognizer _speechRecognizer; #endif - float _octreeSizeScale; - float _oculusUIAngularSize; - float _sixenseReticleMoveSpeed; - bool _invertSixenseButtons; - bool _automaticAvatarLOD; - float _avatarLODDecreaseFPS; - float _avatarLODIncreaseFPS; - float _avatarLODDistanceMultiplier; - int _boundaryLevelAdjust; - int _maxOctreePacketsPerSecond; + float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE; + float _oculusUIAngularSize;// = DEFAULT_OCULUS_UI_ANGULAR_SIZE; + float _sixenseReticleMoveSpeed;// = DEFAULT_SIXENSE_RETICLE_MOVE_SPEED; + bool _invertSixenseButtons;// = DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS; + bool _hasLoginDialogDisplayed = false; + + bool _automaticAvatarLOD = true; + float _avatarLODDecreaseFPS = DEFAULT_ADJUST_AVATAR_LOD_DOWN_FPS; + float _avatarLODIncreaseFPS = ADJUST_LOD_UP_FPS; + float _avatarLODDistanceMultiplier = DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER; + + int _boundaryLevelAdjust = 0; + int _maxOctreePacketsPerSecond = DEFAULT_MAX_OCTREE_PPS; + quint64 _lastAdjust; quint64 _lastAvatarDetailDrop; - SimpleMovingAverage _fpsAverage; - SimpleMovingAverage _fastFPSAverage; + + SimpleMovingAverage _fpsAverage = FIVE_SECONDS_OF_FRAMES; + SimpleMovingAverage _fastFPSAverage = ONE_SECOND_OF_FRAMES; + QPointer _addressBarDialog; QPointer _animationsDialog; QPointer _attachmentsDialog; @@ -278,16 +290,20 @@ private: QPointer _loginDialog; QPointer _octreeStatsDialog; QPointer _preferencesDialog; - bool _hasLoginDialogDisplayed; + + QPointer _MetavoxelEditor; + QPointer _metavoxelNetworkSimulator; + QPointer _ScriptEditor; + QPointer _chatWindow; + QAction* _loginAction = nullptr; QAction* _chatAction = nullptr; QString _snapshotsLocation; QString _scriptsLocation; QByteArray _walletPrivateKey; - bool _shouldRenderTableNeedsRebuilding; + bool _shouldRenderTableNeedsRebuilding = true; QMap _shouldRenderTable; - }; namespace MenuOption { @@ -405,7 +421,6 @@ namespace MenuOption { const QString RenderTargetFramerate40 = "40"; const QString RenderTargetFramerate30 = "30"; const QString RenderTargetFramerateVSyncOn = "V-Sync On"; - const QString RenderResolution = "Scale Resolution"; const QString RenderResolutionOne = "1"; const QString RenderResolutionTwoThird = "2/3"; diff --git a/interface/src/ui/JSConsole.h b/interface/src/ui/JSConsole.h index f28132a1f5..daeba8ea15 100644 --- a/interface/src/ui/JSConsole.h +++ b/interface/src/ui/JSConsole.h @@ -20,6 +20,11 @@ #include "ui_console.h" #include "ScriptEngine.h" +const QString CONSOLE_TITLE = "Scripting Console"; +const float CONSOLE_WINDOW_OPACITY = 0.95f; +const int CONSOLE_WIDTH = 800; +const int CONSOLE_HEIGHT = 200; + class JSConsole : public QWidget { Q_OBJECT public: diff --git a/interface/src/ui/ScriptEditorWindow.cpp b/interface/src/ui/ScriptEditorWindow.cpp index 0496040724..f5cd6de49a 100644 --- a/interface/src/ui/ScriptEditorWindow.cpp +++ b/interface/src/ui/ScriptEditorWindow.cpp @@ -31,8 +31,6 @@ #include "FlowLayout.h" #include "JSConsole.h" -const int CONSOLE_HEIGHT = 150; - ScriptEditorWindow::ScriptEditorWindow() : _ScriptEditorWindowUI(new Ui::ScriptEditorWindow), _loadMenu(new QMenu), From 934d8d58ef43f25ee36c4a3a7a28c3620ccf4bee Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 15:59:27 -0800 Subject: [PATCH 43/51] Move some constants out of Menu class files --- interface/src/Menu.cpp | 3 --- interface/src/Menu.h | 18 ++++++++++-------- interface/src/devices/Faceshift.h | 3 +++ 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 48403b7511..12671ef6e3 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -11,7 +11,6 @@ #include - #include #include #include @@ -44,8 +43,6 @@ #include "Audio.h" #include "audio/AudioIOStatsRenderer.h" #include "audio/AudioScope.h" -#include "devices/Faceshift.h" -#include "devices/OculusManager.h" #include "devices/Visage.h" #include "Menu.h" #include "scripting/LocationScriptingInterface.h" diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 563ed42d30..95436a5b8b 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -27,10 +27,14 @@ #include "SpeechRecognizer.h" #endif +#include "devices/Faceshift.h" +#include "devices/OculusManager.h" +#include "devices/SixenseManager.h" #include "ui/ChatWindow.h" #include "ui/JSConsole.h" #include "ui/ScriptEditorWindow.h" +// Make an LOD handler class and move everything overthere const float ADJUST_LOD_DOWN_FPS = 40.0; const float ADJUST_LOD_UP_FPS = 55.0; const float DEFAULT_ADJUST_AVATAR_LOD_DOWN_FPS = 30.0f; @@ -46,15 +50,13 @@ const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE; const float MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 0.1f; const float MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 15.0f; - -const QString SETTINGS_ADDRESS_KEY = "address"; - -const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f; -const QString DEFAULT_FACESHIFT_HOSTNAME = "localhost"; const float DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER = 1.0f; + const int ONE_SECOND_OF_FRAMES = 60; const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES; +////////////////////////////////////////////////////////// +const QString SETTINGS_ADDRESS_KEY = "address"; class QSettings; class AddressBarDialog; @@ -259,9 +261,9 @@ private: SpeechRecognizer _speechRecognizer; #endif float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE; - float _oculusUIAngularSize;// = DEFAULT_OCULUS_UI_ANGULAR_SIZE; - float _sixenseReticleMoveSpeed;// = DEFAULT_SIXENSE_RETICLE_MOVE_SPEED; - bool _invertSixenseButtons;// = DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS; + float _oculusUIAngularSize = DEFAULT_OCULUS_UI_ANGULAR_SIZE; + float _sixenseReticleMoveSpeed = DEFAULT_SIXENSE_RETICLE_MOVE_SPEED; + bool _invertSixenseButtons = DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS; bool _hasLoginDialogDisplayed = false; bool _automaticAvatarLOD = true; diff --git a/interface/src/devices/Faceshift.h b/interface/src/devices/Faceshift.h index b6b942dfee..9ed23ddb9f 100644 --- a/interface/src/devices/Faceshift.h +++ b/interface/src/devices/Faceshift.h @@ -23,6 +23,9 @@ #include "FaceTracker.h" +const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f; +const QString DEFAULT_FACESHIFT_HOSTNAME = "localhost"; + /// Handles interaction with the Faceshift software, which provides head position/orientation and facial features. class Faceshift : public FaceTracker { Q_OBJECT From 661221a189cb946598d214430253766d6a8c0f1c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jan 2015 16:04:00 -0800 Subject: [PATCH 44/51] repairs to AudioScriptingInterface playSound --- examples/lobby.js | 8 +++++--- interface/src/Audio.cpp | 2 +- libraries/audio/src/AudioScriptingInterface.cpp | 3 ++- libraries/audio/src/Sound.cpp | 15 ++++++++++++--- libraries/audio/src/Sound.h | 8 ++++++-- 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/examples/lobby.js b/examples/lobby.js index b03be7c29b..15a8aca328 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -138,8 +138,10 @@ function drawLobby() { // add an attachment on this avatar so other people see them in the lobby MyAvatar.attach(HELMET_ATTACHMENT_URL, "Neck", {x: 0, y: 0, z: 0}, Quat.fromPitchYawRollDegrees(0, 0, 0), 1.15); - // start the drone sound - currentDrone = Audio.playSound(droneSound, { stereo: true, loop: true, localOnly: true, volume: DRONE_VOLUME }); + if (droneSound.downloaded) { + // start the drone sound + currentDrone = Audio.playSound(droneSound, { stereo: true, loop: true, localOnly: true, volume: DRONE_VOLUME }); + } // start one of our muzak sounds playRandomMuzak(); @@ -353,7 +355,7 @@ function update(deltaTime) { Overlays.editOverlay(descriptionText, { position: textOverlayPosition() }); // if the reticle is up then we may need to play the next muzak - if (!Audio.isInjectorPlaying(currentMuzakInjector)) { + if (currentMuzakInjector && !Audio.isInjectorPlaying(currentMuzakInjector)) { playNextMuzak(); } } diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index bd106d9bc6..844386c9e5 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -880,7 +880,7 @@ bool Audio::outputLocalInjector(bool isStereo, qreal volume, AudioInjector* inje localFormat.setChannelCount(isStereo ? 2 : 1); QAudioOutput* localOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName), - localFormat, this); + localFormat); localOutput->setVolume(volume); // move the localOutput to the same thread as the local injector buffer diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/audio/src/AudioScriptingInterface.cpp index 8cd133ad40..120c7a6b5a 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/audio/src/AudioScriptingInterface.cpp @@ -13,7 +13,8 @@ void registerAudioMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, injectorOptionsToScriptValue, injectorOptionsFromScriptValue); - qScriptRegisterMetaType(engine, soundToScriptValue, soundFromScriptValue); + qScriptRegisterMetaType(engine, soundSharedPointerToScriptValue, soundSharedPointerFromScriptValue); + qScriptRegisterMetaType(engine, soundPointerToScriptValue, soundPointerFromScriptValue); } AudioScriptingInterface& AudioScriptingInterface::getInstance() { diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 54ff61d66a..cc41a849e7 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -29,13 +29,22 @@ #include "AudioEditBuffer.h" #include "Sound.h" -QScriptValue soundToScriptValue(QScriptEngine* engine, SharedSoundPointer const& in) { +static int soundMetaTypeId = qRegisterMetaType(); + +QScriptValue soundSharedPointerToScriptValue(QScriptEngine* engine, SharedSoundPointer const& in) { return engine->newQObject(in.data()); } -void soundFromScriptValue(const QScriptValue &object, SharedSoundPointer &out) { +void soundSharedPointerFromScriptValue(const QScriptValue& object, SharedSoundPointer &out) { out = SharedSoundPointer(qobject_cast(object.toQObject())); - qDebug() << "Sound from script value" << out.data(); +} + +QScriptValue soundPointerToScriptValue(QScriptEngine* engine, Sound* const& in) { + return engine->newQObject(in); +} + +void soundPointerFromScriptValue(const QScriptValue &object, Sound* &out) { + out = qobject_cast(object.toQObject()); } Sound::Sound(const QUrl& url, bool isStereo) : diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index 02b75417e8..9aa92feea1 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -45,8 +45,12 @@ private: typedef QSharedPointer SharedSoundPointer; Q_DECLARE_METATYPE(SharedSoundPointer) +QScriptValue soundSharedPointerToScriptValue(QScriptEngine* engine, SharedSoundPointer const& in); +void soundSharedPointerFromScriptValue(const QScriptValue& object, SharedSoundPointer &out); + +Q_DECLARE_METATYPE(Sound*) +QScriptValue soundPointerToScriptValue(QScriptEngine* engine, Sound* const& in); +void soundPointerFromScriptValue(const QScriptValue& object, Sound* &out); -QScriptValue soundToScriptValue(QScriptEngine* engine, SharedSoundPointer const& in); -void soundFromScriptValue(const QScriptValue& object, SharedSoundPointer& out); #endif // hifi_Sound_h From 80af2adf128a1a92bbd96067b3f7229dc4847c57 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 16:42:27 -0800 Subject: [PATCH 45/51] Remove constexpr because windows can't handle them --- libraries/networking/src/ResourceCache.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 7b8ffc392b..519b205d46 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -27,18 +27,18 @@ class QTimer; class Resource; -static constexpr qint64 BYTES_PER_MEGABYTES = 1024 * 1024; -static constexpr qint64 BYTES_PER_GIGABYTES = 1024 * BYTES_PER_MEGABYTES; +static const qint64 BYTES_PER_MEGABYTES = 1024 * 1024; +static const qint64 BYTES_PER_GIGABYTES = 1024 * BYTES_PER_MEGABYTES; // Windows can have troubles allocating that much memory in ram sometimes // so default cache size at 100 MB on windows (1GB otherwise) #ifdef Q_OS_WIN32 -static constexpr qint64 DEFAULT_UNUSED_MAX_SIZE = 100 * BYTES_PER_MEGABYTES; +static const qint64 DEFAULT_UNUSED_MAX_SIZE = 100 * BYTES_PER_MEGABYTES; #else -static constexpr qint64 DEFAULT_UNUSED_MAX_SIZE = 1024 * BYTES_PER_MEGABYTES; +static const qint64 DEFAULT_UNUSED_MAX_SIZE = 1024 * BYTES_PER_MEGABYTES; #endif -static constexpr qint64 MIN_UNUSED_MAX_SIZE = 0; -static constexpr qint64 MAX_UNUSED_MAX_SIZE = 10 * BYTES_PER_GIGABYTES; +static const qint64 MIN_UNUSED_MAX_SIZE = 0; +static const qint64 MAX_UNUSED_MAX_SIZE = 10 * BYTES_PER_GIGABYTES; /// Base class for resource caches. class ResourceCache : public QObject { From b6ba82653f4e355759b0af20d9390ccfa2c7da29 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 17:00:39 -0800 Subject: [PATCH 46/51] Remove glm dependency --- libraries/networking/src/ResourceCache.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index f4d9a2909d..5a95bd6028 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -16,12 +16,14 @@ #include #include -#include - #include "NetworkAccessManager.h" #include "ResourceCache.h" +#define clamp(x, min, max) (((x) < (min)) ? (min) :\ + (((x) > (max)) ? (max) :\ + (x))) + ResourceCache::ResourceCache(QObject* parent) : QObject(parent) { } @@ -72,7 +74,7 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& } void ResourceCache::setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize) { - _unusedResourcesMaxSize = glm::clamp(unusedResourcesMaxSize, MIN_UNUSED_MAX_SIZE, MAX_UNUSED_MAX_SIZE); + _unusedResourcesMaxSize = clamp(unusedResourcesMaxSize, MIN_UNUSED_MAX_SIZE, MAX_UNUSED_MAX_SIZE); reserveUnusedResource(0); } From 7d39b45f16d9487cb6701f424118e749b3c5c332 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 17:34:07 -0800 Subject: [PATCH 47/51] Hopefully fixes the windows compile error --- interface/src/devices/OculusManager.cpp | 1 + interface/src/devices/OculusManager.h | 2 -- libraries/script-engine/src/EventTypes.h | 2 +- libraries/script-engine/src/KeyEvent.h | 2 +- libraries/shared/src/SharedUtil.h | 2 +- 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index f59ce639a0..2b444c4a25 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -13,6 +13,7 @@ #include "InterfaceConfig.h" #include "OculusManager.h" +#include "ui/overlays/Text3DOverlay.h" #include #include diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index d9700d9530..b9b5d81c68 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -19,8 +19,6 @@ #include -#include "ui/overlays/Text3DOverlay.h" - const float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f; class Camera; diff --git a/libraries/script-engine/src/EventTypes.h b/libraries/script-engine/src/EventTypes.h index fc808ea560..906006e4f4 100644 --- a/libraries/script-engine/src/EventTypes.h +++ b/libraries/script-engine/src/EventTypes.h @@ -12,7 +12,7 @@ #ifndef hifi_EventTypes_h #define hifi_EventTypes_h -#include +#include void registerEventTypes(QScriptEngine* engine); diff --git a/libraries/script-engine/src/KeyEvent.h b/libraries/script-engine/src/KeyEvent.h index bdadcec374..350b733eaf 100644 --- a/libraries/script-engine/src/KeyEvent.h +++ b/libraries/script-engine/src/KeyEvent.h @@ -13,7 +13,7 @@ #define hifi_KeyEvent_h #include -#include +#include class KeyEvent { public: diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 61b7365877..01dcd7ff02 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -19,7 +19,7 @@ #include // not on windows, not needed for mac or windows #endif -#include +#include const int BYTES_PER_COLOR = 3; const int BYTES_PER_FLAGS = 1; From 9ce405a7444475027e358bcf7af19d2f2987b895 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 17:46:38 -0800 Subject: [PATCH 48/51] Text3DOverlay forward definition --- interface/src/devices/OculusManager.h | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index b9b5d81c68..591ba53239 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -23,6 +23,7 @@ const float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f; class Camera; class PalmData; +class Text3DOverlay; /// Handles interaction with the Oculus Rift. class OculusManager { From 2b48d31cbb23bd3938eba9f68cc92af2d674cd1a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 17:48:54 -0800 Subject: [PATCH 49/51] Move scripts to correct directory --- examples/{ => controllers/hydra}/hydraGrab.js | 0 examples/{ => controllers/hydra}/hydraMove.js | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename examples/{ => controllers/hydra}/hydraGrab.js (100%) rename examples/{ => controllers/hydra}/hydraMove.js (100%) diff --git a/examples/hydraGrab.js b/examples/controllers/hydra/hydraGrab.js similarity index 100% rename from examples/hydraGrab.js rename to examples/controllers/hydra/hydraGrab.js diff --git a/examples/hydraMove.js b/examples/controllers/hydra/hydraMove.js similarity index 100% rename from examples/hydraMove.js rename to examples/controllers/hydra/hydraMove.js From cf7089e145cb5209cf0b54c4a0282866d67a2732 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jan 2015 18:49:05 -0800 Subject: [PATCH 50/51] Move constant back to Menu --- interface/src/Menu.h | 3 ++- interface/src/devices/OculusManager.h | 2 -- interface/src/devices/SixenseManager.h | 2 ++ interface/src/ui/ApplicationOverlay.h | 1 + 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 95436a5b8b..6f30ca983b 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -28,7 +28,6 @@ #endif #include "devices/Faceshift.h" -#include "devices/OculusManager.h" #include "devices/SixenseManager.h" #include "ui/ChatWindow.h" #include "ui/JSConsole.h" @@ -56,6 +55,8 @@ const int ONE_SECOND_OF_FRAMES = 60; const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES; ////////////////////////////////////////////////////////// +const float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f; + const QString SETTINGS_ADDRESS_KEY = "address"; class QSettings; diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index 591ba53239..71fc08c8f9 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -19,8 +19,6 @@ #include -const float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f; - class Camera; class PalmData; class Text3DOverlay; diff --git a/interface/src/devices/SixenseManager.h b/interface/src/devices/SixenseManager.h index 0a7ab78c0e..4082edd153 100644 --- a/interface/src/devices/SixenseManager.h +++ b/interface/src/devices/SixenseManager.h @@ -25,6 +25,8 @@ #endif +class PalmData; + const unsigned int BUTTON_0 = 1U << 0; // the skinny button between 1 and 2 const unsigned int BUTTON_1 = 1U << 5; const unsigned int BUTTON_2 = 1U << 6; diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index e2094f2a8e..33dcea67a3 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -12,6 +12,7 @@ #ifndef hifi_ApplicationOverlay_h #define hifi_ApplicationOverlay_h +class Camera; class Overlays; class QOpenGLFramebufferObject; From 30f898109d34a1278fda97d27eb081acf428acc0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 13 Jan 2015 09:40:55 -0800 Subject: [PATCH 51/51] don't warn about c++11 for MSVC12 --- CMakeLists.txt | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a0d463b766..367fb88a26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,17 +38,19 @@ elseif (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fno-strict-aliasing") endif(WIN32) -include(CheckCXXCompilerFlag) -CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) -CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X) +if (NOT MSVC12) + include(CheckCXXCompilerFlag) + CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) + CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X) -if (COMPILER_SUPPORTS_CXX11) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") -elseif(COMPILER_SUPPORTS_CXX0X) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") -else() - message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.") -endif() + if (COMPILER_SUPPORTS_CXX11) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + elseif(COMPILER_SUPPORTS_CXX0X) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") + else() + message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.") + endif() +endif () if (APPLE) set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++0x")