diff --git a/examples/controllers/hydra/gun.js b/examples/controllers/hydra/gun.js
index 8bea5d623e..f2ed50733d 100644
--- a/examples/controllers/hydra/gun.js
+++ b/examples/controllers/hydra/gun.js
@@ -4,6 +4,7 @@
//
// Created by Brad Hefta-Gaub on 12/31/13.
// Modified by Philip on 3/3/14
+// Modified by Thijs Wenker on 3/31/15
// Copyright 2013 High Fidelity, Inc.
//
// This is an example script that turns the hydra controllers and mouse into a entity gun.
@@ -66,7 +67,7 @@ var impactSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/BulletIm
var targetHitSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/hit.raw");
var targetLaunchSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/shoot.raw");
-var gunModel = "http://public.highfidelity.io/models/attachments/HaloGun.fst";
+var gunModel = "https://s3.amazonaws.com/hifi-public/cozza13/gun/m1911-handgun+1.fbx?v=4";
var audioOptions = {
volume: 0.9
@@ -90,44 +91,49 @@ var score = 0;
var bulletID = false;
var targetID = false;
-// Create a reticle image in center of screen
+// Create overlay buttons and reticle
+
+var BUTTON_SIZE = 32;
+var PADDING = 3;
+var NUM_BUTTONS = 3;
+
var screenSize = Controller.getViewportDimensions();
+var startX = screenSize.x / 2 - (NUM_BUTTONS * (BUTTON_SIZE + PADDING)) / 2;
var reticle = Overlays.addOverlay("image", {
- x: screenSize.x / 2 - 16,
- y: screenSize.y / 2 - 16,
- width: 32,
- height: 32,
- imageURL: HIFI_PUBLIC_BUCKET + "images/billiardsReticle.png",
- color: { red: 255, green: 255, blue: 255},
+ x: screenSize.x / 2 - (BUTTON_SIZE / 2),
+ y: screenSize.y / 2 - (BUTTON_SIZE / 2),
+ width: BUTTON_SIZE,
+ height: BUTTON_SIZE,
+ imageURL: HIFI_PUBLIC_BUCKET + "images/gun/crosshairs.svg",
alpha: 1
});
var offButton = Overlays.addOverlay("image", {
- x: screenSize.x - 48,
- y: 96,
- width: 32,
- height: 32,
- imageURL: HIFI_PUBLIC_BUCKET + "images/close.png",
- color: { red: 255, green: 255, blue: 255},
+ x: startX,
+ y: screenSize.y - (BUTTON_SIZE + PADDING),
+ width: BUTTON_SIZE,
+ height: BUTTON_SIZE,
+ imageURL: HIFI_PUBLIC_BUCKET + "images/gun/close.svg",
alpha: 1
});
+startX += BUTTON_SIZE + PADDING;
var platformButton = Overlays.addOverlay("image", {
- x: screenSize.x - 48,
- y: 130,
- width: 32,
- height: 32,
- imageURL: HIFI_PUBLIC_BUCKET + "images/city.png",
- color: { red: 255, green: 255, blue: 255},
+ x: startX,
+ y: screenSize.y - (BUTTON_SIZE + PADDING),
+ width: BUTTON_SIZE,
+ height: BUTTON_SIZE,
+ imageURL: HIFI_PUBLIC_BUCKET + "images/gun/platform-targets.svg",
alpha: 1
});
+
+startX += BUTTON_SIZE + PADDING;
var gridButton = Overlays.addOverlay("image", {
- x: screenSize.x - 48,
- y: 164,
- width: 32,
- height: 32,
- imageURL: HIFI_PUBLIC_BUCKET + "images/blocks.png",
- color: { red: 255, green: 255, blue: 255},
+ x: startX,
+ y: screenSize.y - (BUTTON_SIZE + PADDING),
+ width: BUTTON_SIZE,
+ height: BUTTON_SIZE,
+ imageURL: HIFI_PUBLIC_BUCKET + "images/gun/floating-targets.svg",
alpha: 1
});
@@ -163,7 +169,7 @@ function shootBullet(position, velocity, grenade) {
{ type: "Sphere",
position: position,
dimensions: { x: bSize, y: bSize, z: bSize },
- color: { red: 255, green: 0, blue: 0 },
+ color: { red: 0, green: 0, blue: 0 },
velocity: bVelocity,
lifetime: BULLET_LIFETIME,
gravity: { x: 0, y: bGravity, z: 0 },
@@ -260,6 +266,7 @@ function makeGrid(type, scale, size) {
}
}
}
+
function makePlatform(gravity, scale, size) {
var separation = scale * 2;
var pos = Vec3.sum(Camera.getPosition(), Vec3.multiply(10.0 * scale * separation, Quat.getFront(Camera.getOrientation())));
@@ -282,7 +289,7 @@ function makePlatform(gravity, scale, size) {
z: pos.z - (separation * size / 2.0) + z * separation },
dimensions: dimensions,
color: { red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255 },
- velocity: { x: 0, y: 0, z: 0 },
+ velocity: { x: 0, y: 0.05, z: 0 },
gravity: { x: 0, y: gravity, z: 0 },
lifetime: TARGET_LIFE,
damping: 0.1,
@@ -297,7 +304,7 @@ function makePlatform(gravity, scale, size) {
type: "Box",
position: { x: pos.x, y: pos.y - separation / 2.0, z: pos.z },
dimensions: { x: 2.0 * separation * size, y: separation / 2.0, z: 2.0 * separation * size },
- color: { red: 128, green: 128, blue: 128 },
+ color: { red: 100, green: 100, blue: 100 },
lifetime: TARGET_LIFE
});
@@ -372,8 +379,8 @@ function takeFiringPose() {
}
}
-MyAvatar.attach(gunModel, "RightHand", {x:0.02, y: 0.11, z: 0.04}, Quat.fromPitchYawRollDegrees(-0, -160, -79), 0.20);
-MyAvatar.attach(gunModel, "LeftHand", {x:-0.02, y: 0.11, z: 0.04}, Quat.fromPitchYawRollDegrees(0, 0, 79), 0.20);
+MyAvatar.attach(gunModel, "RightHand", {x:0.04, y: 0.22, z: 0.02}, Quat.fromPitchYawRollDegrees(-172, -85, 79), 0.40);
+MyAvatar.attach(gunModel, "LeftHand", {x:-0.04, y: 0.22, z: 0.02}, Quat.fromPitchYawRollDegrees(-172, 85, -79), 0.40);
// Give a bit of time to load before playing sound
Script.setTimeout(playLoadSound, 2000);
diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js
index 05ffb0bd3f..9d2a74fe56 100644
--- a/examples/defaultScripts.js
+++ b/examples/defaultScripts.js
@@ -14,7 +14,6 @@ Script.load("selectAudioDevice.js");
Script.load("controllers/hydra/hydraMove.js");
Script.load("headMove.js");
Script.load("inspect.js");
-Script.load("lobby.js");
Script.load("notifications.js");
Script.load("look.js");
Script.load("users.js");
diff --git a/examples/dice.js b/examples/dice.js
index 6943c926ae..b118a6b289 100644
--- a/examples/dice.js
+++ b/examples/dice.js
@@ -26,20 +26,24 @@ var rollSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/dice/diceRoll.w
var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to create new objects."
var screenSize = Controller.getViewportDimensions();
+
+var BUTTON_SIZE = 32;
+var PADDING = 3;
+
var offButton = Overlays.addOverlay("image", {
- x: screenSize.x - 48,
- y: 96,
- width: 32,
- height: 32,
+ x: screenSize.x / 2 - BUTTON_SIZE,
+ y: screenSize.y- (BUTTON_SIZE + PADDING),
+ width: BUTTON_SIZE,
+ height: BUTTON_SIZE,
imageURL: HIFI_PUBLIC_BUCKET + "images/close.png",
color: { red: 255, green: 255, blue: 255},
alpha: 1
});
var diceButton = Overlays.addOverlay("image", {
- x: screenSize.x - 48,
- y: 130,
- width: 32,
- height: 32,
+ x: screenSize.x / 2 + PADDING,
+ y: screenSize.y - (BUTTON_SIZE + PADDING),
+ width: BUTTON_SIZE,
+ height: BUTTON_SIZE,
imageURL: HIFI_PUBLIC_BUCKET + "images/die.png",
color: { red: 255, green: 255, blue: 255},
alpha: 1
@@ -50,6 +54,7 @@ var LIFETIME = 300;
// NOTE: angularVelocity is in radians/sec
var MAX_ANGULAR_SPEED = Math.PI;
+
function shootDice(position, velocity) {
if (!Entities.canRez()) {
Window.alert(INSUFFICIENT_PERMISSIONS_ERROR_MSG);
@@ -100,7 +105,7 @@ function mousePressEvent(event) {
var clickedText = false;
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
if (clickedOverlay == offButton) {
- deleteDice();
+ Script.stop();
} else if (clickedOverlay == diceButton) {
var HOW_HARD = 2.0;
var position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
diff --git a/examples/edit.js b/examples/edit.js
index 08a2c4f3f7..156cf44fa0 100644
--- a/examples/edit.js
+++ b/examples/edit.js
@@ -16,8 +16,6 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
Script.include([
"libraries/stringHelpers.js",
"libraries/dataviewHelpers.js",
- "libraries/httpMultiPart.js",
- "libraries/modelUploader.js",
"libraries/toolBars.js",
"libraries/progressDialog.js",
diff --git a/examples/example/misc/sunLightExample.js b/examples/example/misc/sunLightExample.js
index 42837c6836..e6c06bb1ae 100644
--- a/examples/example/misc/sunLightExample.js
+++ b/examples/example/misc/sunLightExample.js
@@ -8,27 +8,82 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
-var intensity = 1.0;
-var day = 0.0;
-var hour = 12.0;
-var longitude = 115.0;
-var latitude = 31.0;
-var stageOrientation = Quat.fromPitchYawRollDegrees(0.0, 180.0, 0.0);
+Script.include("../../utilities/tools/cookies.js");
-Scene.setStageDayTime(hour);
-Scene.setStageOrientation(stageOrientation);
-Scene.setStageLocation(longitude, latitude, 0.0);
-/*
-function ticktack() {
- hour += 0.1;
- //Scene.setSunIntensity(Math.cos(time));
- if (hour > 24.0) {
- hour = 0.0;
- day++;
- Scene.setStageYearTime(day);
+var panel = new Panel(10, 400);
+
+panel.newSlider("Origin Longitude", -180, 180,
+ function(value) { Scene.setStageLocation(value, Scene.getStageLocationLatitude(), Scene.getStageLocationAltitude()); },
+ function() { return Scene.getStageLocationLongitude(); },
+ function(value) { return value.toFixed(0) + " deg"; }
+);
+
+panel.newSlider("Origin Latitude", -90, 90,
+ function(value) { Scene.setStageLocation(Scene.getStageLocationLongitude(), value, Scene.getStageLocationAltitude()); },
+ function() { return Scene.getStageLocationLatitude(); },
+ function(value) { return value.toFixed(0) + " deg"; }
+);
+
+panel.newSlider("Origin Altitude", 0, 1000,
+ function(value) { Scene.setStageLocation(Scene.getStageLocationLongitude(), Scene.getStageLocationLatitude(), value); },
+ function() { return Scene.getStageLocationAltitude(); },
+ function(value) { return (value).toFixed(0) + " km"; }
+);
+
+panel.newSlider("Year Time", 0, 364,
+ function(value) { Scene.setStageYearTime(value); },
+ function() { return Scene.getStageYearTime(); },
+ function(value) {
+ var numDaysPerMonth = 365.0 / 12.0;
+ var monthly = (value / numDaysPerMonth);
+ var month = Math.floor(monthly);
+ return (month + 1).toFixed(0) + "/" + Math.ceil(0.5 + (monthly - month)*Math.ceil(numDaysPerMonth)).toFixed(0); }
+);
+
+panel.newSlider("Day Time", 0, 24,
+ function(value) { Scene.setStageDayTime(value); },
+ function() { return Scene.getStageDayTime(); },
+ function(value) {
+ var hour = Math.floor(value);
+ return (hour).toFixed(0) + ":" + ((value - hour)*60.0).toFixed(0);
}
- Scene.setStageDayTime(hour);
-}
+);
-Script.setInterval(ticktack, 41);
-*/
\ No newline at end of file
+var tickTackPeriod = 50;
+var tickTackSpeed = 0.0;
+panel.newSlider("Tick tack time", -1.0, 1.0,
+ function(value) { tickTackSpeed = value; },
+ function() { return tickTackSpeed; },
+ function(value) { return (value).toFixed(2); }
+);
+
+function runStageTime() {
+ if (tickTackSpeed != 0.0) {
+ var hour = panel.get("Day Time");
+ hour += tickTackSpeed;
+ panel.set("Day Time", hour);
+
+ if (hour >= 24.0) {
+ panel.set("Year Time", panel.get("Year Time") + 1);
+ } else if (hour < 0.0) {
+ panel.set("Year Time", panel.get("Year Time") - 1);
+ }
+ }
+}
+Script.setInterval(runStageTime, tickTackPeriod);
+
+panel.newSlider("Light Intensity", 0.0, 5,
+ function(value) { Scene.setSunIntensity(value); },
+ function() { return Scene.getSunIntensity(); },
+ function(value) { return (value).toFixed(2); }
+);
+
+Controller.mouseMoveEvent.connect(function panelMouseMoveEvent(event) { return panel.mouseMoveEvent(event); });
+Controller.mousePressEvent.connect( function panelMousePressEvent(event) { return panel.mousePressEvent(event); });
+Controller.mouseReleaseEvent.connect(function(event) { return panel.mouseReleaseEvent(event); });
+
+function scriptEnding() {
+ Menu.removeMenu("Developer > Scene");
+ panel.destroy();
+}
+Script.scriptEnding.connect(scriptEnding);
diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html
index 1c5fd58084..0c2e09ef16 100644
--- a/examples/html/entityProperties.html
+++ b/examples/html/entityProperties.html
@@ -312,7 +312,7 @@
}
elTextText.value = properties.text;
- elTextLineHeight.value = properties.lineHeight;
+ elTextLineHeight.value = properties.lineHeight.toFixed(4);
elTextTextColorRed.value = properties.textColor.red;
elTextTextColorGreen.value = properties.textColor.green;
elTextTextColorBlue.value = properties.textColor.blue;
@@ -477,6 +477,28 @@
ev.initEvent("change", true, true);
document.activeElement.dispatchEvent(ev);
}
+
+ // For input and textarea elements, select all of the text on focus
+ // WebKit-based browsers, such as is used with QWebView, have a quirk
+ // where the mouseup event comes after the focus event, causing the
+ // text to be deselected immediately after selecting all of the text.
+ // To make this work we block the first mouseup event after the elements
+ // received focus. If we block all mouseup events the user will not
+ // be able to click within the selected text.
+ var els = document.querySelectorAll("input, textarea");
+ for (var i = 0; i < els.length; i++) {
+ var clicked = false;
+ els[i].onfocus = function() {
+ this.select();
+ clicked = false;
+ };
+ els[i].onmouseup = function(e) {
+ if (!clicked) {
+ e.preventDefault();
+ clicked = true;
+ }
+ };
+ }
}
@@ -723,7 +745,7 @@
diff --git a/examples/libraries/modelUploader.js b/examples/libraries/modelUploader.js
deleted file mode 100644
index 64a9e91203..0000000000
--- a/examples/libraries/modelUploader.js
+++ /dev/null
@@ -1,693 +0,0 @@
-//
-// modelUploader.js
-// examples/libraries
-//
-// Copyright 2014 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-
-modelUploader = (function () {
- var that = {},
- modelFile,
- modelName,
- modelURL,
- modelCallback,
- isProcessing,
- fstBuffer,
- fbxBuffer,
- //svoBuffer,
- mapping,
- geometry,
- API_URL = "https://metaverse.highfidelity.com/api/v1/models",
- MODEL_URL = "http://public.highfidelity.com/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;
- }
- }
- }
- }
- }
-
-
-
- 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;
-}());
diff --git a/examples/utilities/diagnostics/XMLHttpRequest.js b/examples/utilities/diagnostics/XMLHttpRequest.js
index fb25cb4fad..76374749ac 100644
--- a/examples/utilities/diagnostics/XMLHttpRequest.js
+++ b/examples/utilities/diagnostics/XMLHttpRequest.js
@@ -145,98 +145,3 @@ test("Test timeout", function() {
this.assertEquals(0, req.status, "status should be `0`");
this.assertEquals(4, req.errorCode, "4 is the timeout error code for QNetworkReply::NetworkError");
});
-
-
-var localFile = Window.browse("Find defaultScripts.js file ...", "", "defaultScripts.js (defaultScripts.js)");
-
-if (localFile !== null) {
-
- localFile = "file:///" + localFile;
-
- test("Test GET local file synchronously", function () {
- var req = new XMLHttpRequest();
-
- var statesVisited = [true, false, false, false, false]
- req.onreadystatechange = function () {
- statesVisited[req.readyState] = true;
- };
-
- req.open("GET", localFile, false);
- req.send();
-
- this.assertEquals(req.DONE, req.readyState, "readyState should be DONE");
- this.assertEquals(200, req.status, "status should be `200`");
- this.assertEquals("OK", req.statusText, "statusText should be `OK`");
- this.assertEquals(0, req.errorCode);
- this.assertNotEquals("", req.getAllResponseHeaders(), "headers should not be null");
- this.assertContains("High Fidelity", req.response.substring(0, 100), "expected text not found in response")
-
- for (var i = 0; i <= req.DONE; i++) {
- this.assertEquals(true, statesVisited[i], i + " should be set");
- }
- });
-
- test("Test GET nonexistent local file", function () {
- var nonexistentFile = localFile.replace(".js", "NoExist.js");
-
- var req = new XMLHttpRequest();
- req.open("GET", nonexistentFile, false);
- req.send();
-
- this.assertEquals(req.DONE, req.readyState, "readyState should be DONE");
- this.assertEquals(404, req.status, "status should be `404`");
- this.assertEquals("Not Found", req.statusText, "statusText should be `Not Found`");
- this.assertNotEquals(0, req.errorCode);
- });
-
- test("Test GET local file already open", function () {
- // Can't open file exclusively in order to test.
- });
-
- test("Test GET local file with data not implemented", function () {
- var req = new XMLHttpRequest();
- req.open("GET", localFile, true);
- req.send("data");
-
- this.assertEquals(req.DONE, req.readyState, "readyState should be DONE");
- this.assertEquals(501, req.status, "status should be `501`");
- this.assertEquals("Not Implemented", req.statusText, "statusText should be `Not Implemented`");
- this.assertNotEquals(0, req.errorCode);
- });
-
- test("Test GET local file asynchronously not implemented", function () {
- var req = new XMLHttpRequest();
- req.open("GET", localFile, true);
- req.send();
-
- this.assertEquals(req.DONE, req.readyState, "readyState should be DONE");
- this.assertEquals(501, req.status, "status should be `501`");
- this.assertEquals("Not Implemented", req.statusText, "statusText should be `Not Implemented`");
- this.assertNotEquals(0, req.errorCode);
- });
-
- test("Test POST local file not implemented", function () {
- var req = new XMLHttpRequest();
- req.open("POST", localFile, false);
- req.send();
-
- this.assertEquals(req.DONE, req.readyState, "readyState should be DONE");
- this.assertEquals(501, req.status, "status should be `501`");
- this.assertEquals("Not Implemented", req.statusText, "statusText should be `Not Implemented`");
- this.assertNotEquals(0, req.errorCode);
- });
-
- test("Test local file username and password not implemented", function () {
- var req = new XMLHttpRequest();
- req.open("GET", localFile, false, "username", "password");
- req.send();
-
- this.assertEquals(req.DONE, req.readyState, "readyState should be DONE");
- this.assertEquals(501, req.status, "status should be `501`");
- this.assertEquals("Not Implemented", req.statusText, "statusText should be `Not Implemented`");
- this.assertNotEquals(0, req.errorCode);
- });
-
-} else {
- print("Local file operation not tested");
-}
diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js
new file mode 100755
index 0000000000..205b19c9f9
--- /dev/null
+++ b/examples/utilities/tools/cookies.js
@@ -0,0 +1,278 @@
+//
+// cookies.js
+//
+// version 1.0
+//
+// Created by Sam Gateau, 4/1/2015
+// A simple ui panel that present a list of porperties and the proper widget to edit it
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+// The Slider class
+Slider = function(x,y,width,thumbSize) {
+
+ this.thumb = Overlays.addOverlay("text", {
+ backgroundColor: { red: 255, green: 255, blue: 255 },
+ x: x,
+ y: y,
+ width: thumbSize,
+ height: thumbSize,
+ alpha: 1.0,
+ backgroundAlpha: 1.0,
+ visible: true
+ });
+ this.background = Overlays.addOverlay("text", {
+ backgroundColor: { red: 125, green: 125, blue: 255 },
+ x: x,
+ y: y,
+ width: width,
+ height: thumbSize,
+ alpha: 1.0,
+ backgroundAlpha: 0.5,
+ visible: true
+ });
+
+ this.thumbSize = thumbSize;
+ this.thumbHalfSize = 0.5 * thumbSize;
+
+ this.minThumbX = x + this.thumbHalfSize;
+ this.maxThumbX = x + width - this.thumbHalfSize;
+ this.thumbX = this.minThumbX;
+
+ this.minValue = 0.0;
+ this.maxValue = 1.0;
+
+ this.clickOffsetX = 0;
+ this.isMoving = false;
+
+ this.updateThumb = function() {
+ thumbTruePos = this.thumbX - 0.5 * this.thumbSize;
+ Overlays.editOverlay(this.thumb, { x: thumbTruePos } );
+ };
+
+ this.onMouseMoveEvent = function(event) {
+ if (this.isMoving) {
+ newThumbX = event.x - this.clickOffsetX;
+ if (newThumbX < this.minThumbX) {
+ newThumbX = this.minThumbX;
+ }
+ if (newThumbX > this.maxThumbX) {
+ newThumbX = this.maxThumbX;
+ }
+ this.thumbX = newThumbX;
+ this.updateThumb();
+ this.onValueChanged(this.getValue());
+ }
+ };
+
+ this.onMousePressEvent = function(event) {
+ this.isMoving = true;
+ var clickOffset = event.x - this.thumbX;
+ if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) {
+ this.clickOffsetX = clickOffset;
+ } else {
+ this.clickOffsetX = 0;
+ this.thumbX = event.x;
+ this.updateThumb();
+ this.onValueChanged(this.getValue());
+ }
+
+ };
+
+ this.onMouseReleaseEvent = function(event) {
+ this.isMoving = false;
+ };
+
+ // Public members:
+
+ this.setNormalizedValue = function(value) {
+ if (value < 0.0) {
+ this.thumbX = this.minThumbX;
+ } else if (value > 1.0) {
+ this.thumbX = this.maxThumbX;
+ } else {
+ this.thumbX = value * (this.maxThumbX - this.minThumbX) + this.minThumbX;
+ }
+ this.updateThumb();
+ };
+ this.getNormalizedValue = function() {
+ return (this.thumbX - this.minThumbX) / (this.maxThumbX - this.minThumbX);
+ };
+
+ this.setValue = function(value) {
+ var normValue = (value - this.minValue) / (this.maxValue - this.minValue);
+ this.setNormalizedValue(normValue);
+ };
+
+ this.getValue = function() {
+ return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue;
+ };
+
+ this.onValueChanged = function(value) {};
+
+ this.destroy = function() {
+ Overlays.deleteOverlay(this.background);
+ Overlays.deleteOverlay(this.thumb);
+ };
+}
+
+
+var textFontSize = 16;
+
+function PanelItem(name, setter, getter, displayer, x, y, textWidth, valueWidth, height) {
+ this.name = name;
+
+
+ this.displayer = typeof displayer !== 'undefined' ? displayer : function(value) { return value.toFixed(2); };
+
+ var topMargin = (height - textFontSize);
+ this.title = Overlays.addOverlay("text", {
+ backgroundColor: { red: 255, green: 255, blue: 255 },
+ x: x,
+ y: y,
+ width: textWidth,
+ height: height,
+ alpha: 1.0,
+ backgroundAlpha: 0.5,
+ visible: true,
+ text: name,
+ font: {size: textFontSize},
+ topMargin: topMargin,
+ });
+
+ this.value = Overlays.addOverlay("text", {
+ backgroundColor: { red: 255, green: 255, blue: 255 },
+ x: x + textWidth,
+ y: y,
+ width: valueWidth,
+ height: height,
+ alpha: 1.0,
+ backgroundAlpha: 0.5,
+ visible: true,
+ text: this.displayer(getter()),
+ font: {size: textFontSize},
+ topMargin: topMargin
+
+ });
+ this.getter = getter;
+
+ this.setter = function(value) {
+ setter(value);
+ Overlays.editOverlay(this.value, {text: this.displayer(getter())});
+ if (this.widget) {
+ this.widget.setValue(value);
+ }
+ };
+ this.setterFromWidget = function(value) {
+ setter(value);
+ Overlays.editOverlay(this.value, {text: this.displayer(getter())});
+ };
+
+
+ this.widget = null;
+
+ this.destroy = function() {
+ Overlays.deleteOverlay(this.title);
+ Overlays.deleteOverlay(this.value);
+ if (this.widget != null) {
+ this.widget.destroy();
+ }
+ }
+}
+
+var textWidth = 180;
+var valueWidth = 100;
+var widgetWidth = 300;
+var rawHeight = 20;
+var rawYDelta = rawHeight * 1.5;
+
+Panel = function(x, y) {
+
+ this.x = x;
+ this.y = y;
+ this.nextY = y;
+
+ this.widgetX = x + textWidth + valueWidth;
+
+ this.items = new Array();
+ this.activeWidget = null;
+
+ this.mouseMoveEvent = function(event) {
+ if (this.activeWidget) {
+ this.activeWidget.onMouseMoveEvent(event);
+ }
+ };
+
+ // we also handle click detection in our mousePressEvent()
+ this.mousePressEvent = function(event) {
+ // Make sure we quitted previous widget
+ if (this.activeWidget) {
+ this.activeWidget.onMouseReleaseEvent(event);
+ }
+ this.activeWidget = null;
+
+ var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
+
+ // If the user clicked any of the slider background then...
+ for (var i in this.items) {
+ var widget = this.items[i].widget;
+
+ if (clickedOverlay == widget.background) {
+ this.activeWidget = widget;
+ this.activeWidget.onMousePressEvent(event);
+ // print("clicked... widget=" + i);
+ break;
+ }
+ }
+ };
+
+ this.mouseReleaseEvent = function(event) {
+ if (this.activeWidget) {
+ this.activeWidget.onMouseReleaseEvent(event);
+ }
+ this.activeWidget = null;
+ };
+
+ this.newSlider = function(name, minValue, maxValue, setValue, getValue, displayValue) {
+
+ var sliderItem = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight);
+
+ var slider = new Slider(this.widgetX, this.nextY, widgetWidth, rawHeight);
+ slider.minValue = minValue;
+ slider.maxValue = maxValue;
+ slider.onValueChanged = function(value) { sliderItem.setterFromWidget(value); };
+
+
+ sliderItem.widget = slider;
+ sliderItem.setter(getValue());
+ this.items[name] = sliderItem;
+ this.nextY += rawYDelta;
+ // print("created Item... slider=" + name);
+ };
+
+ this.destroy = function() {
+ for (var i in this.items) {
+ this.items[i].destroy();
+ }
+ }
+
+ this.set = function(name, value) {
+ var item = this.items[name];
+ if (item != null) {
+ return item.setter(value);
+ }
+ return null;
+ }
+
+ this.get = function(name) {
+ var item = this.items[name];
+ if (item != null) {
+ return item.getter();
+ }
+ return null;
+ }
+};
+
+
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 875b0ef8c6..3a835d4f9e 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -256,7 +256,8 @@ bool setupEssentials(int& argc, char** argv) {
auto speechRecognizer = DependencyManager::set
();
#endif
auto discoverabilityManager = DependencyManager::set();
-
+ auto sceneScriptingInterface = DependencyManager::set();
+
return true;
}
@@ -3587,6 +3588,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
scriptEngine->registerFunction(hmdInterface, "getHUDLookAtPosition2D", HMDScriptingInterface::getHUDLookAtPosition2D, 0);
scriptEngine->registerFunction(hmdInterface, "getHUDLookAtPosition3D", HMDScriptingInterface::getHUDLookAtPosition3D, 0);
+ scriptEngine->registerGlobalObject("Scene", DependencyManager::get().data());
+
#ifdef HAVE_RTMIDI
scriptEngine->registerGlobalObject("MIDI", &MIDIManager::getInstance());
#endif
@@ -3738,22 +3741,27 @@ bool Application::askToSetAvatarUrl(const QString& url) {
_myAvatar->setFaceModelURL(url);
UserActivityLogger::getInstance().changedModel("head", url);
_myAvatar->sendIdentityPacket();
+ emit faceURLChanged(url);
} else if (msgBox.clickedButton() == bodyButton) {
qDebug() << "Chose to use for body: " << url;
_myAvatar->setSkeletonModelURL(url);
// if the head is empty, reset it to the default head.
if (_myAvatar->getFaceModelURLString().isEmpty()) {
_myAvatar->setFaceModelURL(DEFAULT_HEAD_MODEL_URL);
+ emit faceURLChanged(DEFAULT_HEAD_MODEL_URL.toString());
UserActivityLogger::getInstance().changedModel("head", DEFAULT_HEAD_MODEL_URL.toString());
}
UserActivityLogger::getInstance().changedModel("skeleton", url);
_myAvatar->sendIdentityPacket();
+ emit skeletonURLChanged(url);
} else if (msgBox.clickedButton() == bodyAndHeadButton) {
qDebug() << "Chose to use for body + head: " << url;
_myAvatar->setFaceModelURL(QString());
_myAvatar->setSkeletonModelURL(url);
UserActivityLogger::getInstance().changedModel("skeleton", url);
_myAvatar->sendIdentityPacket();
+ emit faceURLChanged(QString());
+ emit skeletonURLChanged(url);
} else {
qDebug() << "Declined to use the avatar: " << url;
}
diff --git a/interface/src/Application.h b/interface/src/Application.h
index 1c281a6a13..a92031d570 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -336,6 +336,9 @@ signals:
void checkBackgroundDownloads();
void domainConnectionRefused(const QString& reason);
+ void faceURLChanged(const QString& newValue);
+ void skeletonURLChanged(const QString& newValue);
+
public slots:
void domainChanged(const QString& domainHostname);
void updateWindowTitle();
diff --git a/interface/src/scripting/WebWindowClass.cpp b/interface/src/scripting/WebWindowClass.cpp
index 61b3ce225f..31bd4029ac 100644
--- a/interface/src/scripting/WebWindowClass.cpp
+++ b/interface/src/scripting/WebWindowClass.cpp
@@ -54,6 +54,7 @@ WebWindowClass::WebWindowClass(const QString& title, const QString& url, int wid
_windowWidget = dockWidget;
} else {
+
_windowWidget = new QWidget(Application::getInstance()->getWindow(), Qt::Window);
_windowWidget->setWindowTitle(title);
_windowWidget->setMinimumSize(width, height);
@@ -89,24 +90,24 @@ void WebWindowClass::setVisible(bool visible) {
if (visible) {
if (_isToolWindow) {
QMetaObject::invokeMethod(
- Application::getInstance()->getToolWindow(), "setVisible", Qt::BlockingQueuedConnection, Q_ARG(bool, visible));
+ Application::getInstance()->getToolWindow(), "setVisible", Qt::AutoConnection, Q_ARG(bool, visible));
} else {
- QMetaObject::invokeMethod(_windowWidget, "raise", Qt::BlockingQueuedConnection);
+ QMetaObject::invokeMethod(_windowWidget, "raise", Qt::AutoConnection);
}
}
- QMetaObject::invokeMethod(_windowWidget, "setVisible", Qt::BlockingQueuedConnection, Q_ARG(bool, visible));
+ QMetaObject::invokeMethod(_windowWidget, "setVisible", Qt::AutoConnection, Q_ARG(bool, visible));
}
void WebWindowClass::setURL(const QString& url) {
if (QThread::currentThread() != thread()) {
- QMetaObject::invokeMethod(this, "setURL", Qt::BlockingQueuedConnection, Q_ARG(QString, url));
+ QMetaObject::invokeMethod(this, "setURL", Qt::AutoConnection, Q_ARG(QString, url));
return;
}
_webView->setUrl(url);
}
void WebWindowClass::raise() {
- QMetaObject::invokeMethod(_windowWidget, "raise", Qt::BlockingQueuedConnection);
+ QMetaObject::invokeMethod(_windowWidget, "raise", Qt::AutoConnection);
}
QScriptValue WebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) {
diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp
index 690489fdb2..b134f7f230 100644
--- a/interface/src/ui/LoginDialog.cpp
+++ b/interface/src/ui/LoginDialog.cpp
@@ -24,6 +24,7 @@
#include "LoginDialog.h"
#include "UIUtil.h"
+const QString CREATE_ACCOUNT_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/signup";
const QString FORGOT_PASSWORD_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/users/password/new";
LoginDialog::LoginDialog(QWidget* parent) :
@@ -45,6 +46,7 @@ LoginDialog::LoginDialog(QWidget* parent) :
this, &LoginDialog::close);
UIUtil::scaleWidgetFontSizes(this);
+ _ui->accountLabel->setText(_ui->accountLabel->text().arg(CREATE_ACCOUNT_URL, FORGOT_PASSWORD_URL));
// Initialize toggle connection
toggleQAction();
diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp
index 4a9165ae44..bd32fc7c34 100644
--- a/interface/src/ui/PreferencesDialog.cpp
+++ b/interface/src/ui/PreferencesDialog.cpp
@@ -16,17 +16,18 @@
#include
#include
#include
+#include
#include "Application.h"
#include "MainWindow.h"
#include "LODManager.h"
#include "Menu.h"
-#include "ModelsBrowser.h"
#include "PreferencesDialog.h"
#include "Snapshot.h"
#include "UserActivityLogger.h"
#include "UIUtil.h"
+
const int PREFERENCES_HEIGHT_PADDING = 20;
PreferencesDialog::PreferencesDialog(QWidget* parent) :
@@ -46,6 +47,11 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) :
connect(ui.buttonBrowseScriptsLocation, &QPushButton::clicked, this, &PreferencesDialog::openScriptsLocationBrowser);
connect(ui.buttonReloadDefaultScripts, &QPushButton::clicked,
Application::getInstance(), &Application::loadDefaultScripts);
+
+
+ connect(Application::getInstance(), &Application::faceURLChanged, this, &PreferencesDialog::faceURLChanged);
+ connect(Application::getInstance(), &Application::skeletonURLChanged, this, &PreferencesDialog::skeletonURLChanged);
+
// move dialog to left side
move(parentWidget()->geometry().topLeft());
setFixedHeight(parentWidget()->size().height() - PREFERENCES_HEIGHT_PADDING);
@@ -53,9 +59,19 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) :
UIUtil::scaleWidgetFontSizes(this);
}
+void PreferencesDialog::faceURLChanged(const QString& newValue) {
+ ui.faceURLEdit->setText(newValue);
+}
+
+void PreferencesDialog::skeletonURLChanged(const QString& newValue) {
+ ui.skeletonURLEdit->setText(newValue);
+}
+
void PreferencesDialog::accept() {
savePreferences();
close();
+ delete _marketplaceWindow;
+ _marketplaceWindow = NULL;
}
void PreferencesDialog::setHeadUrl(QString modelUrl) {
@@ -67,15 +83,23 @@ void PreferencesDialog::setSkeletonUrl(QString modelUrl) {
}
void PreferencesDialog::openHeadModelBrowser() {
- ModelsBrowser modelBrowser(FSTReader::HEAD_MODEL);
- connect(&modelBrowser, &ModelsBrowser::selected, this, &PreferencesDialog::setHeadUrl);
- modelBrowser.browse();
+ auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars";
+ auto WIDTH = 900;
+ auto HEIGHT = 700;
+ if (!_marketplaceWindow) {
+ _marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false);
+ }
+ _marketplaceWindow->setVisible(true);
}
void PreferencesDialog::openBodyModelBrowser() {
- ModelsBrowser modelBrowser(FSTReader::HEAD_AND_BODY_MODEL);
- connect(&modelBrowser, &ModelsBrowser::selected, this, &PreferencesDialog::setSkeletonUrl);
- modelBrowser.browse();
+ auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars";
+ auto WIDTH = 900;
+ auto HEIGHT = 700;
+ if (!_marketplaceWindow) {
+ _marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false);
+ }
+ _marketplaceWindow->setVisible(true);
}
void PreferencesDialog::openSnapshotLocationBrowser() {
@@ -192,11 +216,13 @@ void PreferencesDialog::savePreferences() {
UserActivityLogger::getInstance().changedDisplayName(displayNameStr);
shouldDispatchIdentityPacket = true;
}
+
+ auto AVATAR_FILE_EXTENSION = ".fst";
QUrl faceModelURL(ui.faceURLEdit->text());
QString faceModelURLString = faceModelURL.toString();
if (faceModelURLString != _faceURLString) {
- if (faceModelURLString.isEmpty() || faceModelURLString.toLower().endsWith(".fst")) {
+ if (faceModelURLString.isEmpty() || faceModelURLString.toLower().contains(AVATAR_FILE_EXTENSION)) {
// change the faceModelURL in the profile, it will also update this user's BlendFace
myAvatar->setFaceModelURL(faceModelURL);
UserActivityLogger::getInstance().changedModel("head", faceModelURLString);
@@ -209,7 +235,7 @@ void PreferencesDialog::savePreferences() {
QUrl skeletonModelURL(ui.skeletonURLEdit->text());
QString skeletonModelURLString = skeletonModelURL.toString();
if (skeletonModelURLString != _skeletonURLString) {
- if (skeletonModelURLString.isEmpty() || skeletonModelURLString.toLower().endsWith(".fst")) {
+ if (skeletonModelURLString.isEmpty() || skeletonModelURLString.toLower().contains(AVATAR_FILE_EXTENSION)) {
// change the skeletonModelURL in the profile, it will also update this user's Body
myAvatar->setSkeletonModelURL(skeletonModelURL);
UserActivityLogger::getInstance().changedModel("skeleton", skeletonModelURLString);
diff --git a/interface/src/ui/PreferencesDialog.h b/interface/src/ui/PreferencesDialog.h
index ddacaa7127..4daa2d9696 100644
--- a/interface/src/ui/PreferencesDialog.h
+++ b/interface/src/ui/PreferencesDialog.h
@@ -17,6 +17,8 @@
#include
#include
+#include "scripting/WebWindowClass.h"
+
class PreferencesDialog : public QDialog {
Q_OBJECT
@@ -36,6 +38,8 @@ private:
QString _faceURLString;
QString _skeletonURLString;
QString _displayNameString;
+
+ WebWindowClass* _marketplaceWindow = NULL;
private slots:
void accept();
@@ -43,6 +47,8 @@ private slots:
void setSkeletonUrl(QString modelUrl);
void openSnapshotLocationBrowser();
void openScriptsLocationBrowser();
+ void faceURLChanged(const QString& newValue);
+ void skeletonURLChanged(const QString& newValue);
};
diff --git a/interface/ui/loginDialog.ui b/interface/ui/loginDialog.ui
index 58ff353a16..e203699155 100644
--- a/interface/ui/loginDialog.ui
+++ b/interface/ui/loginDialog.ui
@@ -447,7 +447,7 @@ border-radius: 4px; padding-top: 1px;
-
-
+
Helvetica,Arial,sans-serif
@@ -456,9 +456,12 @@ border-radius: 4px; padding-top: 1px;
<style type="text/css">
- a { text-decoration: none; color: #267077;}
+a { text-decoration: none; color: #267077; margin:0;padding:0;}
+#create {font-weight:bold;}
+p {margin:5px 0;}
</style>
-<a href="https://metaverse.highfidelity.com/password/new">Recover password?</a>
+<p><a id="create" href="%1">Create account</a></p>
+<p><a href="%2">Recover password</a></p>
true
diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp
index c87a942baa..7e71ba07f7 100644
--- a/libraries/fbx/src/OBJReader.cpp
+++ b/libraries/fbx/src/OBJReader.cpp
@@ -21,9 +21,12 @@
#include "Shape.h"
+QHash COMMENT_SCALE_HINTS;
+
+
class OBJTokenizer {
public:
- OBJTokenizer(QIODevice* device) : _device(device), _pushedBackToken(-1) { }
+ OBJTokenizer(QIODevice* device);
enum SpecialToken {
NO_TOKEN = -1,
NO_PUSHBACKED_TOKEN = -1,
@@ -46,6 +49,15 @@ private:
};
+OBJTokenizer::OBJTokenizer(QIODevice* device) : _device(device), _pushedBackToken(-1) {
+ // This is a list of comments that exports use to hint at scaling
+ if (COMMENT_SCALE_HINTS.isEmpty()) {
+ COMMENT_SCALE_HINTS["This file uses centimeters as units"] = 1.0f / 100.0f;
+ COMMENT_SCALE_HINTS["This file uses millimeters as units"] = 1.0f / 1000.0f;
+ }
+}
+
+
int OBJTokenizer::nextToken() {
if (_pushedBackToken != NO_PUSHBACKED_TOKEN) {
int token = _pushedBackToken;
@@ -60,7 +72,7 @@ int OBJTokenizer::nextToken() {
}
switch (ch) {
case '#': {
- _comment = _device->readLine(); // skip the comment
+ _comment = _device->readLine(); // stash comment for a future call to getComment
qDebug() << "COMMENT:" << _comment;
return COMMENT_TOKEN;
}
@@ -136,11 +148,15 @@ bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping,
while (true) {
int tokenType = tokenizer.nextToken();
if (tokenType == OBJTokenizer::COMMENT_TOKEN) {
- if (tokenizer.getComment().contains("This file uses centimeters as units")) {
- scaleGuess = 1.0f / 100.0f;
- }
- if (tokenizer.getComment().contains("This file uses millimeters as units")) {
- scaleGuess = 1.0f / 1000.0f;
+ // loop through the list of known comments which suggest a scaling factor.
+ // if we find one, save the scaling hint into scaleGuess
+ QString comment = tokenizer.getComment();
+ QHashIterator i(COMMENT_SCALE_HINTS);
+ while (i.hasNext()) {
+ i.next();
+ if (comment.contains(i.key())) {
+ scaleGuess = i.value();
+ }
}
continue;
}
diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp
index 1c171eee76..096ec273eb 100644
--- a/libraries/model/src/model/Stage.cpp
+++ b/libraries/model/src/model/Stage.cpp
@@ -92,8 +92,8 @@ void EarthSunModel::setSurfaceOrientation(const Quat& orientation) {
double moduloRange(double val, double minVal, double maxVal) {
double range = maxVal - minVal;
double rval = (val - minVal) / range;
- double intval;
- return modf(rval, &intval) * range + minVal;
+ rval = rval - floor(rval);
+ return rval * range + minVal;
}
const float MAX_LONGITUDE = 180.0f;
diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp
index d714194b2e..f8c8e31ece 100755
--- a/libraries/physics/src/CharacterController.cpp
+++ b/libraries/physics/src/CharacterController.cpp
@@ -212,6 +212,9 @@ btVector3 CharacterController::perpindicularComponent(const btVector3& direction
}
const btVector3 LOCAL_UP_AXIS(0.0f, 1.0f, 0.0f);
+const float DEFAULT_GRAVITY = 5.0f;
+const float TERMINAL_VELOCITY = 55.0f;
+const float JUMP_SPEED = 5.0f;
CharacterController::CharacterController(AvatarData* avatarData) {
assert(avatarData);
@@ -226,9 +229,9 @@ CharacterController::CharacterController(AvatarData* avatarData) {
_velocityTimeInterval = 0.0f;
_verticalVelocity = 0.0f;
_verticalOffset = 0.0f;
- _gravity = 5.0f; // slower than Earth's
- _maxFallSpeed = 55.0f; // Terminal velocity of a sky diver in m/s.
- _jumpSpeed = 5.0f;
+ _gravity = DEFAULT_GRAVITY; // slower than Earth's
+ _maxFallSpeed = TERMINAL_VELOCITY; // Terminal velocity of a sky diver in m/s.
+ _jumpSpeed = JUMP_SPEED;
_isOnGround = false;
_isJumping = false;
_isHovering = true;
@@ -350,6 +353,7 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl
return penetration;
}
+
void CharacterController::scanDown(btCollisionWorld* world) {
// we test with downward raycast and if we don't find floor close enough then turn on "hover"
btKinematicClosestNotMeRayResultCallback callback(_ghostObject);
diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp
index b4d322a4a3..2c30887e3e 100644
--- a/libraries/physics/src/ShapeManager.cpp
+++ b/libraries/physics/src/ShapeManager.cpp
@@ -35,7 +35,7 @@ btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
// Very small or large objects are not supported.
float diagonal = 4.0f * glm::length2(info.getHalfExtents());
const float MIN_SHAPE_DIAGONAL_SQUARED = 3.0e-4f; // 1 cm cube
- const float MAX_SHAPE_DIAGONAL_SQUARED = 3.0e4f; // 100 m cube
+ const float MAX_SHAPE_DIAGONAL_SQUARED = 3.0e6f; // 1000 m cube
if (diagonal < MIN_SHAPE_DIAGONAL_SQUARED || diagonal > MAX_SHAPE_DIAGONAL_SQUARED) {
// qDebug() << "ShapeManager::getShape -- not making shape due to size" << diagonal;
return NULL;
diff --git a/libraries/script-engine/src/SceneScriptingInterface.cpp b/libraries/script-engine/src/SceneScriptingInterface.cpp
index 9cac521225..855701f536 100644
--- a/libraries/script-engine/src/SceneScriptingInterface.cpp
+++ b/libraries/script-engine/src/SceneScriptingInterface.cpp
@@ -20,20 +20,47 @@ void SceneScriptingInterface::setStageLocation(float longitude, float latitude,
_skyStage->setOriginLocation(longitude, latitude, altitude);
}
+float SceneScriptingInterface::getStageLocationLongitude() const {
+ return _skyStage->getOriginLongitude();
+}
+float SceneScriptingInterface::getStageLocationLatitude() const {
+ return _skyStage->getOriginLatitude();
+}
+float SceneScriptingInterface::getStageLocationAltitude() const {
+ return _skyStage->getOriginSurfaceAltitude();
+}
+
void SceneScriptingInterface::setStageDayTime(float hour) {
_skyStage->setDayTime(hour);
}
+
+float SceneScriptingInterface::getStageDayTime() const {
+ return _skyStage->getDayTime();
+}
+
void SceneScriptingInterface::setStageYearTime(int day) {
_skyStage->setYearTime(day);
}
+int SceneScriptingInterface::getStageYearTime() const {
+ return _skyStage->getYearTime();
+}
+
void SceneScriptingInterface::setSunColor(const glm::vec3& color) {
_skyStage->setSunColor(color);
}
+
+const glm::vec3& SceneScriptingInterface::getSunColor() const {
+ return _skyStage->getSunColor();
+}
+
void SceneScriptingInterface::setSunIntensity(float intensity) {
_skyStage->setSunIntensity(intensity);
}
+float SceneScriptingInterface::getSunIntensity() const {
+ return _skyStage->getSunIntensity();
+}
model::SunSkyStagePointer SceneScriptingInterface::getSkyStage() const {
return _skyStage;
diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h
index 8ae9424c95..0c36b303e9 100644
--- a/libraries/script-engine/src/SceneScriptingInterface.h
+++ b/libraries/script-engine/src/SceneScriptingInterface.h
@@ -24,12 +24,21 @@ class SceneScriptingInterface : public QObject, public Dependency {
public:
Q_INVOKABLE void setStageOrientation(const glm::quat& orientation);
+
Q_INVOKABLE void setStageLocation(float longitude, float latitude, float altitude);
+ Q_INVOKABLE float getStageLocationLongitude() const;
+ Q_INVOKABLE float getStageLocationLatitude() const;
+ Q_INVOKABLE float getStageLocationAltitude() const;
+
Q_INVOKABLE void setStageDayTime(float hour);
+ Q_INVOKABLE float getStageDayTime() const;
Q_INVOKABLE void setStageYearTime(int day);
+ Q_INVOKABLE int getStageYearTime() const;
Q_INVOKABLE void setSunColor(const glm::vec3& color);
+ Q_INVOKABLE const glm::vec3& getSunColor() const;
Q_INVOKABLE void setSunIntensity(float intensity);
+ Q_INVOKABLE float getSunIntensity() const;
model::SunSkyStagePointer getSkyStage() const;
diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp
index c31f5be46a..390b889579 100644
--- a/libraries/script-engine/src/ScriptEngine.cpp
+++ b/libraries/script-engine/src/ScriptEngine.cpp
@@ -305,8 +305,6 @@ void ScriptEngine::init() {
_isInitialized = true;
- auto sceneScriptingInterface = DependencyManager::set();
-
auto entityScriptingInterface = DependencyManager::get();
entityScriptingInterface->init();
@@ -350,7 +348,6 @@ void ScriptEngine::init() {
registerGlobalObject("Vec3", &_vec3Library);
registerGlobalObject("Uuid", &_uuidLibrary);
registerGlobalObject("AnimationCache", DependencyManager::get().data());
- registerGlobalObject("Scene", DependencyManager::get().data());
// constants
globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp
index ae0486dd0c..9a6f81b19f 100644
--- a/libraries/script-engine/src/XMLHttpRequestClass.cpp
+++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp
@@ -13,15 +13,14 @@
//
#include
-#include
#include
+#include
#include
#include
-#include
-#include "XMLHttpRequestClass.h"
#include "ScriptEngine.h"
+#include "XMLHttpRequestClass.h"
const QString METAVERSE_API_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/api/";
@@ -42,7 +41,6 @@ XMLHttpRequestClass::XMLHttpRequestClass(QScriptEngine* engine) :
_onReadyStateChange(QScriptValue::NullValue),
_readyState(XMLHttpRequestClass::UNSENT),
_errorCode(QNetworkReply::NoError),
- _file(NULL),
_timeout(0),
_timer(this),
_numRedirects(0) {
@@ -63,22 +61,6 @@ QScriptValue XMLHttpRequestClass::getStatus() const {
if (_reply) {
return QScriptValue(_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt());
}
- if(_url.isLocalFile()) {
- switch (_errorCode) {
- case QNetworkReply::NoError:
- return QScriptValue(200);
- case QNetworkReply::ContentNotFoundError:
- return QScriptValue(404);
- case QNetworkReply::ContentConflictError:
- return QScriptValue(409);
- case QNetworkReply::TimeoutError:
- return QScriptValue(408);
- case QNetworkReply::ContentOperationNotPermittedError:
- return QScriptValue(501);
- default:
- break;
- }
- }
return QScriptValue(0);
}
@@ -86,22 +68,6 @@ QString XMLHttpRequestClass::getStatusText() const {
if (_reply) {
return _reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
}
- if (_url.isLocalFile()) {
- switch (_errorCode) {
- case QNetworkReply::NoError:
- return "OK";
- case QNetworkReply::ContentNotFoundError:
- return "Not Found";
- case QNetworkReply::ContentConflictError:
- return "Conflict";
- case QNetworkReply::TimeoutError:
- return "Timeout";
- case QNetworkReply::ContentOperationNotPermittedError:
- return "Not Implemented";
- default:
- break;
- }
- }
return "";
}
@@ -147,13 +113,6 @@ QScriptValue XMLHttpRequestClass::getAllResponseHeaders() const {
}
return QString(headers.data());
}
- if (_url.isLocalFile()) {
- QString headers = QString("Content-Type: application/octet-stream\n");
- headers.append("Content-Length: ");
- headers.append(QString("%1").arg(_rawResponseData.length()));
- headers.append("\n");
- return headers;
- }
return QScriptValue("");
}
@@ -161,14 +120,6 @@ QScriptValue XMLHttpRequestClass::getResponseHeader(const QString& name) const {
if (_reply && _reply->hasRawHeader(name.toLatin1())) {
return QScriptValue(QString(_reply->rawHeader(name.toLatin1())));
}
- if (_url.isLocalFile()) {
- if (name.toLower() == "content-type") {
- return QString("application/octet-stream");
- }
- if (name.toLower() == "content-length") {
- return QString("%1").arg(_rawResponseData.length());
- }
- }
return QScriptValue::NullValue;
}
@@ -188,47 +139,24 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a
_url.setUrl(url);
_async = async;
- if (_url.isLocalFile()) {
- if (_method.toUpper() == "GET" && !_async && username.isEmpty() && password.isEmpty()) {
- _file = new QFile(_url.toLocalFile());
- if (!_file->exists()) {
- qDebug() << "Can't find file " << _url.fileName();
- abortRequest();
- _errorCode = QNetworkReply::ContentNotFoundError;
- setReadyState(DONE);
- emit requestComplete();
- } else if (!_file->open(QIODevice::ReadOnly)) {
- qDebug() << "Can't open file " << _url.fileName();
- abortRequest();
- _errorCode = QNetworkReply::ContentConflictError;
- setReadyState(DONE);
- emit requestComplete();
- } else {
- setReadyState(OPENED);
- }
- } else {
- notImplemented();
- }
- } else {
- if (url.toLower().left(METAVERSE_API_URL.length()) == METAVERSE_API_URL) {
- AccountManager& accountManager = AccountManager::getInstance();
+ if (url.toLower().left(METAVERSE_API_URL.length()) == METAVERSE_API_URL) {
+ AccountManager& accountManager = AccountManager::getInstance();
- if (accountManager.hasValidAccessToken()) {
- QUrlQuery urlQuery(_url.query());
- urlQuery.addQueryItem("access_token", accountManager.getAccountInfo().getAccessToken().token);
- _url.setQuery(urlQuery);
- }
+ if (accountManager.hasValidAccessToken()) {
+ QUrlQuery urlQuery(_url.query());
+ urlQuery.addQueryItem("access_token", accountManager.getAccountInfo().getAccessToken().token);
+ _url.setQuery(urlQuery);
+ }
- }
- if (!username.isEmpty()) {
- _url.setUserName(username);
- }
- if (!password.isEmpty()) {
- _url.setPassword(password);
- }
- _request.setUrl(_url);
- setReadyState(OPENED);
}
+ if (!username.isEmpty()) {
+ _url.setUserName(username);
+ }
+ if (!password.isEmpty()) {
+ _url.setPassword(password);
+ }
+ _request.setUrl(_url);
+ setReadyState(OPENED);
}
}
@@ -239,23 +167,18 @@ void XMLHttpRequestClass::send() {
void XMLHttpRequestClass::send(const QScriptValue& data) {
if (_readyState == OPENED && !_reply) {
if (!data.isNull()) {
- if (_url.isLocalFile()) {
- notImplemented();
- return;
+ _sendData = new QBuffer(this);
+ if (data.isObject()) {
+ QByteArray ba = qscriptvalue_cast(data);
+ _sendData->setData(ba);
} else {
- _sendData = new QBuffer(this);
- if (data.isObject()) {
- QByteArray ba = qscriptvalue_cast(data);
- _sendData->setData(ba);
- } else {
- _sendData->setData(data.toString().toUtf8());
- }
+ _sendData->setData(data.toString().toUtf8());
}
}
doSend();
- if (!_async && !_url.isLocalFile()) {
+ if (!_async) {
QEventLoop loop;
connect(this, SIGNAL(requestComplete()), &loop, SLOT(quit()));
loop.exec();
@@ -265,23 +188,13 @@ void XMLHttpRequestClass::send(const QScriptValue& data) {
void XMLHttpRequestClass::doSend() {
- if (!_url.isLocalFile()) {
- _reply = NetworkAccessManager::getInstance().sendCustomRequest(_request, _method.toLatin1(), _sendData);
- connectToReply(_reply);
- }
+ _reply = NetworkAccessManager::getInstance().sendCustomRequest(_request, _method.toLatin1(), _sendData);
+ connectToReply(_reply);
if (_timeout > 0) {
_timer.start(_timeout);
connect(&_timer, SIGNAL(timeout()), this, SLOT(requestTimeout()));
}
-
- if (_url.isLocalFile()) {
- setReadyState(HEADERS_RECEIVED);
- setReadyState(LOADING);
- _rawResponseData = _file->readAll();
- _file->close();
- requestFinished();
- }
}
void XMLHttpRequestClass::requestTimeout() {
@@ -300,16 +213,10 @@ void XMLHttpRequestClass::requestError(QNetworkReply::NetworkError code) {
void XMLHttpRequestClass::requestFinished() {
disconnect(&_timer, SIGNAL(timeout()), this, SLOT(requestTimeout()));
- if (!_url.isLocalFile()) {
- _errorCode = _reply->error();
- } else {
- _errorCode = QNetworkReply::NoError;
- }
+ _errorCode = _reply->error();
if (_errorCode == QNetworkReply::NoError) {
- if (!_url.isLocalFile()) {
- _rawResponseData.append(_reply->readAll());
- }
+ _rawResponseData.append(_reply->readAll());
if (_responseType == "json") {
_responseData = _engine->evaluate("(" + QString(_rawResponseData.data()) + ")");
@@ -338,19 +245,6 @@ void XMLHttpRequestClass::abortRequest() {
_reply->deleteLater();
_reply = NULL;
}
-
- if (_file != NULL) {
- _file->close();
- _file = NULL;
- }
-}
-
-void XMLHttpRequestClass::notImplemented() {
- abortRequest();
- //_errorCode = QNetworkReply::OperationNotImplementedError; TODO: Use this status code when update to Qt 5.3
- _errorCode = QNetworkReply::ContentOperationNotPermittedError;
- setReadyState(DONE);
- emit requestComplete();
}
void XMLHttpRequestClass::connectToReply(QNetworkReply* reply) {
diff --git a/libraries/script-engine/src/XMLHttpRequestClass.h b/libraries/script-engine/src/XMLHttpRequestClass.h
index 55bf646476..c79859e895 100644
--- a/libraries/script-engine/src/XMLHttpRequestClass.h
+++ b/libraries/script-engine/src/XMLHttpRequestClass.h
@@ -97,7 +97,6 @@ private:
void connectToReply(QNetworkReply* reply);
void disconnectFromReply(QNetworkReply* reply);
void abortRequest();
- void notImplemented();
QScriptEngine* _engine;
bool _async;
@@ -113,7 +112,6 @@ private:
QScriptValue _onReadyStateChange;
ReadyState _readyState;
QNetworkReply::NetworkError _errorCode;
- QFile* _file;
int _timeout;
QTimer _timer;
int _numRedirects;
diff --git a/tools/vhacd/src/VHACDUtil.cpp b/tools/vhacd/src/VHACDUtil.cpp
index 4f2cb0e2b8..804a3562c6 100644
--- a/tools/vhacd/src/VHACDUtil.cpp
+++ b/tools/vhacd/src/VHACDUtil.cpp
@@ -38,6 +38,15 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *re
}
+ std::cout << "-------------------\n";
+ foreach (const FBXMesh& mesh, geometry.meshes) {
+ foreach (const FBXMeshPart &meshPart, mesh.parts) {
+ std::cout << meshPart.triangleIndices.size() << " ";
+ }
+ }
+ std::cout << "\n";
+
+
//results->meshCount = geometry.meshes.count();
// qDebug() << "read in" << geometry.meshes.count() << "meshes";
@@ -52,14 +61,29 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *re
vertices.append(glm::vec3(mesh.modelTransform * glm::vec4(vertex, 1.0f)));
}
- //get the triangle indices for each mesh
+ // get the triangle indices for each mesh
QVector triangles;
- foreach(FBXMeshPart part, mesh.parts){
- QVector indices = part.triangleIndices;
+ foreach(FBXMeshPart meshPart, mesh.parts){
+ QVector indices = meshPart.triangleIndices;
triangles += indices;
+
+ unsigned int quadCount = meshPart.quadIndices.size() / 4;
+ for (unsigned int i = 0; i < quadCount; i++) {
+ unsigned int p0Index = meshPart.quadIndices[i * 4];
+ unsigned int p1Index = meshPart.quadIndices[i * 4 + 1];
+ unsigned int p2Index = meshPart.quadIndices[i * 4 + 2];
+ unsigned int p3Index = meshPart.quadIndices[i * 4 + 3];
+ // split each quad into two triangles
+ triangles.append(p0Index);
+ triangles.append(p1Index);
+ triangles.append(p2Index);
+ triangles.append(p0Index);
+ triangles.append(p2Index);
+ triangles.append(p3Index);
+ }
}
- //only read meshes with triangles
+ // only read meshes with triangles
if (triangles.count() <= 0){
continue;
}
@@ -131,15 +155,16 @@ void vhacd::VHACDUtil::fattenMeshes(vhacd::LoadFBXResults *meshes, vhacd::LoadFB
auto d1 = p2 - p0;
auto cp = glm::cross(d0, d1);
- cp = 5.0f * glm::normalize(cp);
+ cp = -2.0f * glm::normalize(cp);
auto p3 = p0 + cp;
- auto p4 = p1 + cp;
- auto p5 = p2 + cp;
auto n = results->perMeshVertices.size();
- results->perMeshVertices[i] << p3 << p4 << p5;
- results->perMeshTriangleIndices[i] << n << n+1 << n+2;
+ results->perMeshVertices[i] << p3;
+
+ results->perMeshTriangleIndices[i] << triangles[j] << n << triangles[j + 1];
+ results->perMeshTriangleIndices[i] << triangles[j + 1] << n << triangles[j + 2];
+ results->perMeshTriangleIndices[i] << triangles[j + 2] << n << triangles[j];
}
results->meshCount++;
@@ -148,21 +173,26 @@ void vhacd::VHACDUtil::fattenMeshes(vhacd::LoadFBXResults *meshes, vhacd::LoadFB
-bool vhacd::VHACDUtil::computeVHACD(vhacd::LoadFBXResults *meshes, VHACD::IVHACD::Parameters params,
+bool vhacd::VHACDUtil::computeVHACD(vhacd::LoadFBXResults *inMeshes, VHACD::IVHACD::Parameters params,
vhacd::ComputeResults *results,
- int startMeshIndex, int endMeshIndex, float minimumMeshSize) const {
+ int startMeshIndex, int endMeshIndex, float minimumMeshSize,
+ bool fattenFaces) const {
- // vhacd::LoadFBXResults *meshes = new vhacd::LoadFBXResults;
+ vhacd::LoadFBXResults *meshes = new vhacd::LoadFBXResults;
// combineMeshes(inMeshes, meshes);
// vhacd::LoadFBXResults *meshes = new vhacd::LoadFBXResults;
- // fattenMeshes(inMeshes, meshes);
+
+ if (fattenFaces) {
+ fattenMeshes(inMeshes, meshes);
+ } else {
+ meshes = inMeshes;
+ }
VHACD::IVHACD * interfaceVHACD = VHACD::CreateVHACD();
int meshCount = meshes->meshCount;
int count = 0;
- std::cout << "Performing V-HACD computation on " << meshCount << " meshes ..... " << std::endl;
if (startMeshIndex < 0) {
startMeshIndex = 0;
@@ -171,6 +201,14 @@ bool vhacd::VHACDUtil::computeVHACD(vhacd::LoadFBXResults *meshes, VHACD::IVHACD
endMeshIndex = meshCount;
}
+ for (int i = 0; i < meshCount; i++) {
+ std::cout << meshes->perMeshTriangleIndices.at(i).size() << " ";
+ }
+ std::cout << "\n";
+
+
+ std::cout << "Performing V-HACD computation on " << endMeshIndex - startMeshIndex << " meshes ..... " << std::endl;
+
for (int i = startMeshIndex; i < endMeshIndex; i++){
qDebug() << "--------------------";
std::vector vertices = meshes->perMeshVertices.at(i).toStdVector();
@@ -211,7 +249,6 @@ bool vhacd::VHACDUtil::computeVHACD(vhacd::LoadFBXResults *meshes, VHACD::IVHACD
}
hull.m_points = m_points_copy;
-
int *m_triangles_copy = new int[hull.m_nTriangles * 3];
// std::copy(std::begin(hull.m_triangles), std::end(hull.m_triangles), std::begin(m_triangles_copy));
for (unsigned int i=0; i