mirror of
https://github.com/overte-org/overte.git
synced 2025-04-11 12:20:26 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into applications_diet_cpp11
This commit is contained in:
commit
f77fab2fe0
60 changed files with 1342 additions and 1246 deletions
|
@ -9,6 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QTimer>
|
||||
|
@ -978,6 +979,7 @@ void OctreeServer::readConfiguration() {
|
|||
const QJsonObject& settingsObject = domainHandler.getSettingsObject();
|
||||
QString settingsKey = getMyDomainSettingsKey();
|
||||
QJsonObject settingsSectionObject = settingsObject[settingsKey].toObject();
|
||||
_settings = settingsSectionObject; // keep this for later
|
||||
|
||||
if (!readOptionString(QString("statusHost"), settingsSectionObject, _statusHost) || _statusHost.isEmpty()) {
|
||||
_statusHost = getLocalAddress().toString();
|
||||
|
@ -1042,20 +1044,8 @@ void OctreeServer::readConfiguration() {
|
|||
_wantBackup = !noBackup;
|
||||
qDebug() << "wantBackup=" << _wantBackup;
|
||||
|
||||
if (_wantBackup) {
|
||||
_backupExtensionFormat = OctreePersistThread::DEFAULT_BACKUP_EXTENSION_FORMAT;
|
||||
readOptionString(QString("backupExtensionFormat"), settingsSectionObject, _backupExtensionFormat);
|
||||
qDebug() << "backupExtensionFormat=" << _backupExtensionFormat;
|
||||
|
||||
_backupInterval = OctreePersistThread::DEFAULT_BACKUP_INTERVAL;
|
||||
readOptionInt(QString("backupInterval"), settingsSectionObject, _backupInterval);
|
||||
qDebug() << "backupInterval=" << _backupInterval;
|
||||
|
||||
_maxBackupVersions = OctreePersistThread::DEFAULT_MAX_BACKUP_VERSIONS;
|
||||
readOptionInt(QString("maxBackupVersions"), settingsSectionObject, _maxBackupVersions);
|
||||
qDebug() << "maxBackupVersions=" << _maxBackupVersions;
|
||||
}
|
||||
|
||||
//qDebug() << "settingsSectionObject:" << settingsSectionObject;
|
||||
|
||||
} else {
|
||||
qDebug("persistFilename= DISABLED");
|
||||
}
|
||||
|
@ -1140,8 +1130,7 @@ void OctreeServer::run() {
|
|||
|
||||
// now set up PersistThread
|
||||
_persistThread = new OctreePersistThread(_tree, _persistFilename, _persistInterval,
|
||||
_wantBackup, _backupInterval, _backupExtensionFormat,
|
||||
_maxBackupVersions, _debugTimestampNow);
|
||||
_wantBackup, _settings, _debugTimestampNow);
|
||||
if (_persistThread) {
|
||||
_persistThread->initialize(true);
|
||||
}
|
||||
|
|
|
@ -150,6 +150,7 @@ protected:
|
|||
int _argc;
|
||||
const char** _argv;
|
||||
char** _parsedArgV;
|
||||
QJsonObject _settings;
|
||||
|
||||
HTTPManager* _httpManager;
|
||||
int _statusPort;
|
||||
|
|
|
@ -305,20 +305,66 @@
|
|||
"settings": [
|
||||
{
|
||||
"name": "persistFilename",
|
||||
"label": "Persistant Filename",
|
||||
"help": "the filename for your entities",
|
||||
"label": "Entities Filename",
|
||||
"help": "the path to the file entities are stored in. Make sure the path exists.",
|
||||
"placeholder": "resources/models.svo",
|
||||
"default": "resources/models.svo",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "persistInterval",
|
||||
"label": "Persist Interval",
|
||||
"help": "Interval between persist checks in msecs.",
|
||||
"label": "Save Check Interval",
|
||||
"help": "Milliseconds between checks for saving the current state of entities.",
|
||||
"placeholder": "30000",
|
||||
"default": "30000",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "backups",
|
||||
"type": "table",
|
||||
"label": "Backup Rules",
|
||||
"help": "In this table you can define a set of rules for how frequently to backup copies of your entites content file.",
|
||||
"numbered": false,
|
||||
"default": [
|
||||
{"Name":"Half Hourly Rolling","backupInterval":1800,"format":".backup.halfhourly.%N","maxBackupVersions":5},
|
||||
{"Name":"Daily Rolling","backupInterval":86400,"format":".backup.daily.%N","maxBackupVersions":7},
|
||||
{"Name":"Weekly Rolling","backupInterval":604800,"format":".backup.weekly.%N","maxBackupVersions":4},
|
||||
{"Name":"Thirty Day Rolling","backupInterval":2592000,"format":".backup.thirtyday.%N","maxBackupVersions":12}
|
||||
],
|
||||
"columns": [
|
||||
{
|
||||
"name": "Name",
|
||||
"label": "Name",
|
||||
"can_set": true,
|
||||
"placeholder": "Example",
|
||||
"default": "Example"
|
||||
},
|
||||
{
|
||||
"name": "format",
|
||||
"label": "Rule Format",
|
||||
"can_set": true,
|
||||
"help": "Format used to create the extension for the backup of your persisted entities. Use a format with %N to get rolling. Or use date formatting like %Y-%m-%d.%H:%M:%S.%z",
|
||||
"placeholder": ".backup.example.%N",
|
||||
"default": ".backup.example.%N"
|
||||
},
|
||||
{
|
||||
"name": "backupInterval",
|
||||
"label": "Backup Interval in Seconds",
|
||||
"help": "Interval between backup checks in seconds.",
|
||||
"placeholder": 1800,
|
||||
"default": 1800,
|
||||
"can_set": true
|
||||
},
|
||||
{
|
||||
"name": "maxBackupVersions",
|
||||
"label": "Max Rolled Backup Versions",
|
||||
"help": "If your backup extension format uses 'rolling', how many versions do you want us to keep?",
|
||||
"placeholder": 5,
|
||||
"default": 5,
|
||||
"can_set": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "NoPersist",
|
||||
"type": "checkbox",
|
||||
|
@ -326,30 +372,6 @@
|
|||
"default": false,
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "backupExtensionFormat",
|
||||
"label": "Backup File Extension Format:",
|
||||
"help": "Format used to create the extension for the backup of your persisted entities. Use a format with %N to get rolling. Or use date formatting like %Y-%m-%d.%H:%M:%S.%z",
|
||||
"placeholder": ".backup.%N",
|
||||
"default": ".backup.%N",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "backupInterval",
|
||||
"label": "Backup Interval",
|
||||
"help": "Interval between backup checks in msecs.",
|
||||
"placeholder": "1800000",
|
||||
"default": "1800000",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "maxBackupVersions",
|
||||
"label": "Max Rolled Backup Versions",
|
||||
"help": "If your backup extension format uses 'rolling', how many versions do you want us to keep?",
|
||||
"placeholder": "5",
|
||||
"default": "5",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "NoBackup",
|
||||
"type": "checkbox",
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("../../libraries/globals.js");
|
||||
Script.include("libraries/globals.js");
|
||||
|
||||
function getRandomFloat(min, max) {
|
||||
return Math.random() * (max - min) + min;
|
||||
|
@ -26,14 +26,19 @@ var yawFromMouse = 0;
|
|||
var pitchFromMouse = 0;
|
||||
var isMouseDown = false;
|
||||
|
||||
var BULLET_VELOCITY = 5.0;
|
||||
var BULLET_VELOCITY = 20.0;
|
||||
var MIN_THROWER_DELAY = 1000;
|
||||
var MAX_THROWER_DELAY = 1000;
|
||||
var LEFT_BUTTON_3 = 3;
|
||||
var RELOAD_INTERVAL = 5;
|
||||
|
||||
var KICKBACK_ANGLE = 15;
|
||||
var elbowKickAngle = 0.0;
|
||||
var rotationBeforeKickback;
|
||||
|
||||
var showScore = false;
|
||||
|
||||
|
||||
// Load some sound to use for loading and firing
|
||||
var fireSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/GUN-SHOT2.raw");
|
||||
var loadSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/Gun_Reload_Weapon22.raw");
|
||||
|
@ -48,10 +53,11 @@ var audioOptions = {
|
|||
}
|
||||
|
||||
var shotsFired = 0;
|
||||
|
||||
var shotTime = new Date();
|
||||
|
||||
// initialize our triggers
|
||||
var activeControllers = 0;
|
||||
|
||||
// initialize our controller triggers
|
||||
var triggerPulled = new Array();
|
||||
var numberOfTriggers = Controller.getNumberOfTriggers();
|
||||
for (t = 0; t < numberOfTriggers; t++) {
|
||||
|
@ -59,9 +65,11 @@ for (t = 0; t < numberOfTriggers; t++) {
|
|||
}
|
||||
|
||||
var isLaunchButtonPressed = false;
|
||||
|
||||
var score = 0;
|
||||
|
||||
var bulletID = false;
|
||||
var targetID = false;
|
||||
|
||||
// Create a reticle image in center of screen
|
||||
var screenSize = Controller.getViewportDimensions();
|
||||
var reticle = Overlays.addOverlay("image", {
|
||||
|
@ -74,6 +82,16 @@ var reticle = Overlays.addOverlay("image", {
|
|||
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},
|
||||
alpha: 1
|
||||
});
|
||||
|
||||
if (showScore) {
|
||||
var text = Overlays.addOverlay("text", {
|
||||
x: screenSize.x / 2 - 100,
|
||||
|
@ -95,18 +113,20 @@ function printVector(string, vector) {
|
|||
}
|
||||
|
||||
function shootBullet(position, velocity) {
|
||||
var BULLET_SIZE = 0.01;
|
||||
var BULLET_LIFETIME = 20.0;
|
||||
var BULLET_SIZE = 0.07;
|
||||
var BULLET_LIFETIME = 10.0;
|
||||
var BULLET_GRAVITY = -0.02;
|
||||
Entities.addEntity(
|
||||
bulletID = Entities.addEntity(
|
||||
{ type: "Sphere",
|
||||
position: position,
|
||||
dimensions: { x: BULLET_SIZE, y: BULLET_SIZE, z: BULLET_SIZE },
|
||||
color: { red: 10, green: 10, blue: 10 },
|
||||
color: { red: 255, green: 0, blue: 0 },
|
||||
velocity: velocity,
|
||||
lifetime: BULLET_LIFETIME,
|
||||
gravity: { x: 0, y: BULLET_GRAVITY, z: 0 },
|
||||
damping: 0 });
|
||||
gravity: { x: 0, y: BULLET_GRAVITY, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
collisionsWillMove: true
|
||||
});
|
||||
|
||||
// Play firing sounds
|
||||
audioOptions.position = position;
|
||||
|
@ -115,36 +135,45 @@ function shootBullet(position, velocity) {
|
|||
if ((shotsFired % RELOAD_INTERVAL) == 0) {
|
||||
Audio.playSound(loadSound, audioOptions);
|
||||
}
|
||||
|
||||
// Kickback the arm
|
||||
rotationBeforeKickback = MyAvatar.getJointRotation("LeftForeArm");
|
||||
var armRotation = MyAvatar.getJointRotation("LeftForeArm");
|
||||
armRotation = Quat.multiply(armRotation, Quat.fromPitchYawRollDegrees(0.0, 0.0, KICKBACK_ANGLE));
|
||||
MyAvatar.setJointData("LeftForeArm", armRotation);
|
||||
elbowKickAngle = KICKBACK_ANGLE;
|
||||
}
|
||||
|
||||
function shootTarget() {
|
||||
var TARGET_SIZE = 0.25;
|
||||
var TARGET_GRAVITY = -0.6;
|
||||
var TARGET_SIZE = 0.50;
|
||||
var TARGET_GRAVITY = -0.25;
|
||||
var TARGET_LIFETIME = 300.0;
|
||||
var TARGET_UP_VELOCITY = 3.0;
|
||||
var TARGET_FWD_VELOCITY = 5.0;
|
||||
var TARGET_UP_VELOCITY = 0.5;
|
||||
var TARGET_FWD_VELOCITY = 1.0;
|
||||
var DISTANCE_TO_LAUNCH_FROM = 3.0;
|
||||
var ANGLE_RANGE_FOR_LAUNCH = 20.0;
|
||||
var camera = Camera.getPosition();
|
||||
//printVector("camera", camera);
|
||||
var targetDirection = Quat.angleAxis(getRandomFloat(-20.0, 20.0), { x:0, y:1, z:0 });
|
||||
var targetDirection = Quat.angleAxis(getRandomFloat(-ANGLE_RANGE_FOR_LAUNCH, ANGLE_RANGE_FOR_LAUNCH), { x:0, y:1, z:0 });
|
||||
targetDirection = Quat.multiply(Camera.getOrientation(), targetDirection);
|
||||
var forwardVector = Quat.getFront(targetDirection);
|
||||
//printVector("forwardVector", forwardVector);
|
||||
|
||||
var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_TO_LAUNCH_FROM));
|
||||
//printVector("newPosition", newPosition);
|
||||
|
||||
var velocity = Vec3.multiply(forwardVector, TARGET_FWD_VELOCITY);
|
||||
velocity.y += TARGET_UP_VELOCITY;
|
||||
//printVector("velocity", velocity);
|
||||
|
||||
Entities.addEntity(
|
||||
{ type: "Sphere",
|
||||
|
||||
targetID = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: newPosition,
|
||||
dimensions: { x: TARGET_SIZE, y: TARGET_SIZE, z: TARGET_SIZE },
|
||||
color: { red: 0, green: 200, blue: 200 },
|
||||
//angularVelocity: { x: 1, y: 0, z: 0 },
|
||||
velocity: velocity,
|
||||
gravity: { x: 0, y: TARGET_GRAVITY, z: 0 },
|
||||
lifetime: TARGET_LIFETIME,
|
||||
damping: 0.0001 });
|
||||
damping: 0.0001,
|
||||
collisionsWillMove: true });
|
||||
|
||||
// Record start time
|
||||
shotTime = new Date();
|
||||
|
@ -157,24 +186,25 @@ function shootTarget() {
|
|||
|
||||
|
||||
function entityCollisionWithEntity(entity1, entity2, collision) {
|
||||
score++;
|
||||
if (showScore) {
|
||||
Overlays.editOverlay(text, { text: "Score: " + score } );
|
||||
}
|
||||
|
||||
// Sort out which entity is which
|
||||
|
||||
// Record shot time
|
||||
var endTime = new Date();
|
||||
var msecs = endTime.valueOf() - shotTime.valueOf();
|
||||
//print("hit, msecs = " + msecs);
|
||||
//Vec3.print("penetration = ", collision.penetration);
|
||||
//Vec3.print("contactPoint = ", collision.contactPoint);
|
||||
Entities.deleteEntity(entity1);
|
||||
Entities.deleteEntity(entity2);
|
||||
// play the sound near the camera so the shooter can hear it
|
||||
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||
Audio.playSound(targetHitSound, audioOptions);
|
||||
if (((entity1.id == bulletID.id) || (entity1.id == targetID.id)) &&
|
||||
((entity2.id == bulletID.id) || (entity2.id == targetID.id))) {
|
||||
score++;
|
||||
if (showScore) {
|
||||
Overlays.editOverlay(text, { text: "Score: " + score } );
|
||||
}
|
||||
|
||||
// We will delete the bullet and target in 1/2 sec, but for now we can see them bounce!
|
||||
Script.setTimeout(deleteBulletAndTarget, 500);
|
||||
|
||||
// Turn the target and the bullet white
|
||||
Entities.editEntity(entity1, { color: { red: 255, green: 255, blue: 255 }});
|
||||
Entities.editEntity(entity2, { color: { red: 255, green: 255, blue: 255 }});
|
||||
|
||||
// play the sound near the camera so the shooter can hear it
|
||||
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||
Audio.playSound(targetHitSound, audioOptions);
|
||||
}
|
||||
}
|
||||
|
||||
function keyPressEvent(event) {
|
||||
|
@ -186,12 +216,42 @@ function keyPressEvent(event) {
|
|||
shootFromMouse();
|
||||
} else if (event.text == "r") {
|
||||
playLoadSound();
|
||||
} else if (event.text == "s") {
|
||||
// Hit this key to dump a posture from hydra to log
|
||||
Quat.print("arm = ", MyAvatar.getJointRotation("LeftArm"));
|
||||
Quat.print("forearm = ", MyAvatar.getJointRotation("LeftForeArm"));
|
||||
Quat.print("hand = ", MyAvatar.getJointRotation("LeftHand"));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function playLoadSound() {
|
||||
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||
Audio.playSound(loadSound, audioOptions);
|
||||
// Raise arm to firing posture
|
||||
takeFiringPose();
|
||||
}
|
||||
|
||||
function clearPose() {
|
||||
MyAvatar.clearJointData("LeftForeArm");
|
||||
MyAvatar.clearJointData("LeftArm");
|
||||
MyAvatar.clearJointData("LeftHand");
|
||||
}
|
||||
|
||||
function deleteBulletAndTarget() {
|
||||
Entities.deleteEntity(bulletID);
|
||||
Entities.deleteEntity(targetID);
|
||||
bulletID = false;
|
||||
targetID = false;
|
||||
}
|
||||
|
||||
function takeFiringPose() {
|
||||
clearPose();
|
||||
if (Controller.getNumberOfSpatialControls() == 0) {
|
||||
MyAvatar.setJointData("LeftForeArm", {x: -0.251919, y: -0.0415449, z: 0.499487, w: 0.827843});
|
||||
MyAvatar.setJointData("LeftArm", { x: 0.470196, y: -0.132559, z: 0.494033, w: 0.719219});
|
||||
MyAvatar.setJointData("LeftHand", { x: -0.0104815, y: -0.110551, z: -0.352111, w: 0.929333});
|
||||
}
|
||||
}
|
||||
|
||||
MyAvatar.attach(gunModel, "RightHand", {x:0.02, y: 0.11, z: 0.04}, Quat.fromPitchYawRollDegrees(-0, -160, -79), 0.20);
|
||||
|
@ -201,17 +261,49 @@ MyAvatar.attach(gunModel, "RightHand", {x:0.02, y: 0.11, z: 0.04}, Quat.fromPitc
|
|||
Script.setTimeout(playLoadSound, 2000);
|
||||
|
||||
function update(deltaTime) {
|
||||
if (bulletID && !bulletID.isKnownID) {
|
||||
print("Trying to identify bullet");
|
||||
bulletID = Entities.identifyEntity(bulletID);
|
||||
}
|
||||
if (targetID && !targetID.isKnownID) {
|
||||
targetID = Entities.identifyEntity(targetID);
|
||||
}
|
||||
// Check for mouseLook movement, update rotation
|
||||
// rotate body yaw for yaw received from mouse
|
||||
var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Radians( { x: 0, y: yawFromMouse, z: 0 } ));
|
||||
MyAvatar.orientation = newOrientation;
|
||||
//MyAvatar.orientation = newOrientation;
|
||||
yawFromMouse = 0;
|
||||
|
||||
// apply pitch from mouse
|
||||
var newPitch = MyAvatar.headPitch + pitchFromMouse;
|
||||
MyAvatar.headPitch = newPitch;
|
||||
//MyAvatar.headPitch = newPitch;
|
||||
pitchFromMouse = 0;
|
||||
|
||||
|
||||
if (activeControllers == 0) {
|
||||
if (Controller.getNumberOfSpatialControls() > 0) {
|
||||
activeControllers = Controller.getNumberOfSpatialControls();
|
||||
clearPose();
|
||||
}
|
||||
}
|
||||
|
||||
var KICKBACK_DECAY_RATE = 0.125;
|
||||
if (elbowKickAngle > 0.0) {
|
||||
if (elbowKickAngle > 0.5) {
|
||||
var newAngle = elbowKickAngle * KICKBACK_DECAY_RATE;
|
||||
elbowKickAngle -= newAngle;
|
||||
var armRotation = MyAvatar.getJointRotation("LeftForeArm");
|
||||
armRotation = Quat.multiply(armRotation, Quat.fromPitchYawRollDegrees(0.0, 0.0, -newAngle));
|
||||
MyAvatar.setJointData("LeftForeArm", armRotation);
|
||||
} else {
|
||||
MyAvatar.setJointData("LeftForeArm", rotationBeforeKickback);
|
||||
if (Controller.getNumberOfSpatialControls() > 0) {
|
||||
clearPose();
|
||||
}
|
||||
elbowKickAngle = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
// Check hydra controller for launch button press
|
||||
if (!isLaunchButtonPressed && Controller.isButtonPressed(LEFT_BUTTON_3)) {
|
||||
isLaunchButtonPressed = true;
|
||||
|
@ -222,15 +314,13 @@ function update(deltaTime) {
|
|||
|
||||
}
|
||||
|
||||
// Check hydra controller for trigger press
|
||||
// check for trigger press
|
||||
|
||||
var numberOfTriggers = Controller.getNumberOfTriggers();
|
||||
var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
|
||||
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
|
||||
var numberOfTriggers = 2;
|
||||
var controllersPerTrigger = 2;
|
||||
|
||||
// this is expected for hydras
|
||||
if (numberOfTriggers == 2 && controllersPerTrigger == 2) {
|
||||
for (var t = 0; t < numberOfTriggers; t++) {
|
||||
for (var t = 0; t < 2; t++) {
|
||||
var shootABullet = false;
|
||||
var triggerValue = Controller.getTriggerValue(t);
|
||||
if (triggerPulled[t]) {
|
||||
|
@ -239,14 +329,13 @@ function update(deltaTime) {
|
|||
triggerPulled[t] = false; // unpulled
|
||||
}
|
||||
} else {
|
||||
// must pull to at least 0.9
|
||||
if (triggerValue > 0.9) {
|
||||
// must pull to at least
|
||||
if (triggerValue > 0.5) {
|
||||
triggerPulled[t] = true; // pulled
|
||||
shootABullet = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (shootABullet) {
|
||||
var palmController = t * controllersPerTrigger;
|
||||
var palmPosition = Controller.getSpatialControlPosition(palmController);
|
||||
|
@ -263,12 +352,8 @@ function update(deltaTime) {
|
|||
var position = { x: fingerTipPosition.x + palmToFingerTipVector.x/2,
|
||||
y: fingerTipPosition.y + palmToFingerTipVector.y/2,
|
||||
z: fingerTipPosition.z + palmToFingerTipVector.z/2};
|
||||
|
||||
var linearVelocity = 25;
|
||||
|
||||
var velocity = { x: palmToFingerTipVector.x * linearVelocity,
|
||||
y: palmToFingerTipVector.y * linearVelocity,
|
||||
z: palmToFingerTipVector.z * linearVelocity };
|
||||
|
||||
var velocity = Vec3.multiply(BULLET_VELOCITY, Vec3.normalize(palmToFingerTipVector));
|
||||
|
||||
shootBullet(position, velocity);
|
||||
}
|
||||
|
@ -280,8 +365,12 @@ function mousePressEvent(event) {
|
|||
isMouseDown = true;
|
||||
lastX = event.x;
|
||||
lastY = event.y;
|
||||
//audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||
//Audio.playSound(loadSound, audioOptions);
|
||||
|
||||
if (Overlays.getOverlayAtPoint({ x: event.x, y: event.y }) === offButton) {
|
||||
Script.stop();
|
||||
} else {
|
||||
shootFromMouse();
|
||||
}
|
||||
}
|
||||
|
||||
function shootFromMouse() {
|
||||
|
@ -312,8 +401,10 @@ function mouseMoveEvent(event) {
|
|||
|
||||
function scriptEnding() {
|
||||
Overlays.deleteOverlay(reticle);
|
||||
Overlays.deleteOverlay(offButton);
|
||||
Overlays.deleteOverlay(text);
|
||||
MyAvatar.detachOne(gunModel);
|
||||
clearPose();
|
||||
}
|
||||
|
||||
Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity);
|
||||
|
|
|
@ -662,8 +662,6 @@ 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",
|
||||
|
@ -674,7 +672,7 @@ function setupModelMenus() {
|
|||
}
|
||||
|
||||
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: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Model List..." });
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Large Models", shortcutKey: "CTRL+META+L",
|
||||
afterItem: "Paste Models", isCheckable: true, isChecked: true });
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Small Models", shortcutKey: "CTRL+META+S",
|
||||
|
@ -696,7 +694,6 @@ setupModelMenus(); // do this when first running our script.
|
|||
|
||||
function cleanupModelMenus() {
|
||||
Menu.removeSeparator("Edit", "Models");
|
||||
Menu.removeMenuItem("Edit", "Edit Properties...");
|
||||
if (modelMenuAddedDelete) {
|
||||
// delete our menuitems
|
||||
Menu.removeMenuItem("Edit", "Delete");
|
||||
|
@ -798,22 +795,6 @@ function handeMenuEvent(menuItem) {
|
|||
MyAvatar.position = selectedModel.properties.position;
|
||||
}
|
||||
}
|
||||
} else if (menuItem == "Edit Properties...") {
|
||||
// good place to put the properties dialog
|
||||
|
||||
editModelID = -1;
|
||||
if (selectionManager.selections.length == 1) {
|
||||
print(" Edit Properties.... selectedEntityID="+ selectedEntityID);
|
||||
editModelID = selectionManager.selections[0];
|
||||
} else {
|
||||
print(" Edit Properties.... not holding...");
|
||||
}
|
||||
if (editModelID != -1) {
|
||||
print(" Edit Properties.... about to edit properties...");
|
||||
entityPropertyDialogBox.openDialog(editModelID);
|
||||
selectionManager._update();
|
||||
}
|
||||
|
||||
} else if (menuItem == "Paste Models") {
|
||||
modelImporter.paste();
|
||||
} else if (menuItem == "Export Models") {
|
||||
|
@ -841,9 +822,6 @@ Controller.keyPressEvent.connect(function(event) {
|
|||
|
||||
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" || event.text == "DELETE") {
|
||||
handeMenuEvent("Delete");
|
||||
} else if (event.text == "TAB") {
|
||||
|
|
66
examples/example/downloadInfoExample.js
Normal file
66
examples/example/downloadInfoExample.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// downloadInfoExample.js
|
||||
// examples/example
|
||||
//
|
||||
// Created by David Rowe on 5 Jan 2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Display downloads information the same as in the stats.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var downloadInfo,
|
||||
downloadInfoOverlay;
|
||||
|
||||
function formatInfo(info) {
|
||||
var string = "Downloads: ",
|
||||
i;
|
||||
|
||||
for (i = 0; i < info.downloading.length; i += 1) {
|
||||
string += info.downloading[i].toFixed(0) + "% ";
|
||||
}
|
||||
|
||||
string += "(" + info.pending.toFixed(0) + " pending)";
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
// Get and log the current downloads info ...
|
||||
|
||||
downloadInfo = GlobalServices.getDownloadInfo();
|
||||
print(formatInfo(downloadInfo));
|
||||
|
||||
|
||||
// Display and update the downloads info in an overlay ...
|
||||
|
||||
function setUp() {
|
||||
downloadInfoOverlay = Overlays.addOverlay("text", {
|
||||
x: 300,
|
||||
y: 200,
|
||||
width: 300,
|
||||
height: 50,
|
||||
color: { red: 255, green: 255, blue: 255 },
|
||||
alpha: 1.0,
|
||||
backgroundColor: { red: 127, green: 127, blue: 127 },
|
||||
backgroundAlpha: 0.5,
|
||||
topMargin: 15,
|
||||
leftMargin: 20,
|
||||
text: ""
|
||||
});
|
||||
}
|
||||
|
||||
function updateInfo(info) {
|
||||
Overlays.editOverlay(downloadInfoOverlay, { text: formatInfo(info) });
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
Overlays.deleteOverlay(downloadInfoOverlay);
|
||||
}
|
||||
|
||||
setUp();
|
||||
GlobalServices.downloadInfoChanged.connect(updateInfo);
|
||||
GlobalServices.updateDownloadInfo();
|
||||
Script.scriptEnding.connect(tearDown);
|
418
examples/gun.js
418
examples/gun.js
|
@ -1,418 +0,0 @@
|
|||
//
|
||||
// gun.js
|
||||
// examples
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/31/13.
|
||||
// Modified by Philip on 3/3/14
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that turns the hydra controllers and mouse into a entity gun.
|
||||
// It reads the controller, watches for trigger pulls, and launches entities.
|
||||
// When entities collide with voxels they blow little holes out of the voxels.
|
||||
//
|
||||
// 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");
|
||||
|
||||
function getRandomFloat(min, max) {
|
||||
return Math.random() * (max - min) + min;
|
||||
}
|
||||
|
||||
var lastX = 0;
|
||||
var lastY = 0;
|
||||
var yawFromMouse = 0;
|
||||
var pitchFromMouse = 0;
|
||||
var isMouseDown = false;
|
||||
|
||||
var BULLET_VELOCITY = 20.0;
|
||||
var MIN_THROWER_DELAY = 1000;
|
||||
var MAX_THROWER_DELAY = 1000;
|
||||
var LEFT_BUTTON_3 = 3;
|
||||
var RELOAD_INTERVAL = 5;
|
||||
|
||||
var KICKBACK_ANGLE = 15;
|
||||
var elbowKickAngle = 0.0;
|
||||
var rotationBeforeKickback;
|
||||
|
||||
var showScore = false;
|
||||
|
||||
|
||||
// Load some sound to use for loading and firing
|
||||
var fireSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/GUN-SHOT2.raw");
|
||||
var loadSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/Gun_Reload_Weapon22.raw");
|
||||
var impactSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/BulletImpact2.raw");
|
||||
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 audioOptions = {
|
||||
volume: 0.9
|
||||
}
|
||||
|
||||
var shotsFired = 0;
|
||||
var shotTime = new Date();
|
||||
|
||||
var activeControllers = 0;
|
||||
|
||||
// initialize our controller triggers
|
||||
var triggerPulled = new Array();
|
||||
var numberOfTriggers = Controller.getNumberOfTriggers();
|
||||
for (t = 0; t < numberOfTriggers; t++) {
|
||||
triggerPulled[t] = false;
|
||||
}
|
||||
|
||||
var isLaunchButtonPressed = false;
|
||||
var score = 0;
|
||||
|
||||
var bulletID = false;
|
||||
var targetID = false;
|
||||
|
||||
// Create a reticle image in center of screen
|
||||
var screenSize = Controller.getViewportDimensions();
|
||||
var reticle = Overlays.addOverlay("image", {
|
||||
x: screenSize.x / 2 - 16,
|
||||
y: screenSize.y / 2 - 16,
|
||||
width: 32,
|
||||
height: 32,
|
||||
imageURL: HIFI_PUBLIC_BUCKET + "images/reticle.png",
|
||||
color: { red: 255, green: 255, blue: 255},
|
||||
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},
|
||||
alpha: 1
|
||||
});
|
||||
|
||||
if (showScore) {
|
||||
var text = Overlays.addOverlay("text", {
|
||||
x: screenSize.x / 2 - 100,
|
||||
y: screenSize.y / 2 - 50,
|
||||
width: 150,
|
||||
height: 50,
|
||||
color: { red: 0, green: 0, blue: 0},
|
||||
textColor: { red: 255, green: 0, blue: 0},
|
||||
topMargin: 4,
|
||||
leftMargin: 4,
|
||||
text: "Score: " + score
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
function printVector(string, vector) {
|
||||
print(string + " " + vector.x + ", " + vector.y + ", " + vector.z);
|
||||
}
|
||||
|
||||
function shootBullet(position, velocity) {
|
||||
var BULLET_SIZE = 0.07;
|
||||
var BULLET_LIFETIME = 10.0;
|
||||
var BULLET_GRAVITY = -0.02;
|
||||
bulletID = Entities.addEntity(
|
||||
{ type: "Sphere",
|
||||
position: position,
|
||||
dimensions: { x: BULLET_SIZE, y: BULLET_SIZE, z: BULLET_SIZE },
|
||||
color: { red: 255, green: 0, blue: 0 },
|
||||
velocity: velocity,
|
||||
lifetime: BULLET_LIFETIME,
|
||||
gravity: { x: 0, y: BULLET_GRAVITY, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
collisionsWillMove: true
|
||||
});
|
||||
|
||||
// Play firing sounds
|
||||
audioOptions.position = position;
|
||||
Audio.playSound(fireSound, audioOptions);
|
||||
shotsFired++;
|
||||
if ((shotsFired % RELOAD_INTERVAL) == 0) {
|
||||
Audio.playSound(loadSound, audioOptions);
|
||||
}
|
||||
|
||||
// Kickback the arm
|
||||
rotationBeforeKickback = MyAvatar.getJointRotation("LeftForeArm");
|
||||
var armRotation = MyAvatar.getJointRotation("LeftForeArm");
|
||||
armRotation = Quat.multiply(armRotation, Quat.fromPitchYawRollDegrees(0.0, 0.0, KICKBACK_ANGLE));
|
||||
MyAvatar.setJointData("LeftForeArm", armRotation);
|
||||
elbowKickAngle = KICKBACK_ANGLE;
|
||||
}
|
||||
|
||||
function shootTarget() {
|
||||
var TARGET_SIZE = 0.50;
|
||||
var TARGET_GRAVITY = -0.25;
|
||||
var TARGET_LIFETIME = 300.0;
|
||||
var TARGET_UP_VELOCITY = 0.5;
|
||||
var TARGET_FWD_VELOCITY = 1.0;
|
||||
var DISTANCE_TO_LAUNCH_FROM = 3.0;
|
||||
var ANGLE_RANGE_FOR_LAUNCH = 20.0;
|
||||
var camera = Camera.getPosition();
|
||||
//printVector("camera", camera);
|
||||
var targetDirection = Quat.angleAxis(getRandomFloat(-ANGLE_RANGE_FOR_LAUNCH, ANGLE_RANGE_FOR_LAUNCH), { x:0, y:1, z:0 });
|
||||
targetDirection = Quat.multiply(Camera.getOrientation(), targetDirection);
|
||||
var forwardVector = Quat.getFront(targetDirection);
|
||||
|
||||
var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_TO_LAUNCH_FROM));
|
||||
|
||||
var velocity = Vec3.multiply(forwardVector, TARGET_FWD_VELOCITY);
|
||||
velocity.y += TARGET_UP_VELOCITY;
|
||||
|
||||
targetID = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: newPosition,
|
||||
dimensions: { x: TARGET_SIZE, y: TARGET_SIZE, z: TARGET_SIZE },
|
||||
color: { red: 0, green: 200, blue: 200 },
|
||||
//angularVelocity: { x: 1, y: 0, z: 0 },
|
||||
velocity: velocity,
|
||||
gravity: { x: 0, y: TARGET_GRAVITY, z: 0 },
|
||||
lifetime: TARGET_LIFETIME,
|
||||
damping: 0.0001,
|
||||
collisionsWillMove: true });
|
||||
|
||||
// Record start time
|
||||
shotTime = new Date();
|
||||
|
||||
// Play target shoot sound
|
||||
audioOptions.position = newPosition;
|
||||
Audio.playSound(targetLaunchSound, audioOptions);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function entityCollisionWithEntity(entity1, entity2, collision) {
|
||||
|
||||
if (((entity1.id == bulletID.id) || (entity1.id == targetID.id)) &&
|
||||
((entity2.id == bulletID.id) || (entity2.id == targetID.id))) {
|
||||
score++;
|
||||
if (showScore) {
|
||||
Overlays.editOverlay(text, { text: "Score: " + score } );
|
||||
}
|
||||
|
||||
// We will delete the bullet and target in 1/2 sec, but for now we can see them bounce!
|
||||
Script.setTimeout(deleteBulletAndTarget, 500);
|
||||
|
||||
// Turn the target and the bullet white
|
||||
Entities.editEntity(entity1, { color: { red: 255, green: 255, blue: 255 }});
|
||||
Entities.editEntity(entity2, { color: { red: 255, green: 255, blue: 255 }});
|
||||
|
||||
// play the sound near the camera so the shooter can hear it
|
||||
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||
Audio.playSound(targetHitSound, audioOptions);
|
||||
}
|
||||
}
|
||||
|
||||
function keyPressEvent(event) {
|
||||
// if our tools are off, then don't do anything
|
||||
if (event.text == "t") {
|
||||
var time = MIN_THROWER_DELAY + Math.random() * MAX_THROWER_DELAY;
|
||||
Script.setTimeout(shootTarget, time);
|
||||
} else if (event.text == ".") {
|
||||
shootFromMouse();
|
||||
} else if (event.text == "r") {
|
||||
playLoadSound();
|
||||
} else if (event.text == "s") {
|
||||
// Hit this key to dump a posture from hydra to log
|
||||
Quat.print("arm = ", MyAvatar.getJointRotation("LeftArm"));
|
||||
Quat.print("forearm = ", MyAvatar.getJointRotation("LeftForeArm"));
|
||||
Quat.print("hand = ", MyAvatar.getJointRotation("LeftHand"));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function playLoadSound() {
|
||||
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||
Audio.playSound(loadSound, audioOptions);
|
||||
// Raise arm to firing posture
|
||||
takeFiringPose();
|
||||
}
|
||||
|
||||
function clearPose() {
|
||||
MyAvatar.clearJointData("LeftForeArm");
|
||||
MyAvatar.clearJointData("LeftArm");
|
||||
MyAvatar.clearJointData("LeftHand");
|
||||
}
|
||||
|
||||
function deleteBulletAndTarget() {
|
||||
Entities.deleteEntity(bulletID);
|
||||
Entities.deleteEntity(targetID);
|
||||
bulletID = false;
|
||||
targetID = false;
|
||||
}
|
||||
|
||||
function takeFiringPose() {
|
||||
clearPose();
|
||||
if (Controller.getNumberOfSpatialControls() == 0) {
|
||||
MyAvatar.setJointData("LeftForeArm", {x: -0.251919, y: -0.0415449, z: 0.499487, w: 0.827843});
|
||||
MyAvatar.setJointData("LeftArm", { x: 0.470196, y: -0.132559, z: 0.494033, w: 0.719219});
|
||||
MyAvatar.setJointData("LeftHand", { x: -0.0104815, y: -0.110551, z: -0.352111, w: 0.929333});
|
||||
}
|
||||
}
|
||||
|
||||
MyAvatar.attach(gunModel, "LeftHand", {x: -0.02, y: -.14, z: 0.07}, Quat.fromPitchYawRollDegrees(-70, -151, 72), 0.20);
|
||||
|
||||
// Give a bit of time to load before playing sound
|
||||
Script.setTimeout(playLoadSound, 2000);
|
||||
|
||||
function update(deltaTime) {
|
||||
if (bulletID && !bulletID.isKnownID) {
|
||||
print("Trying to identify bullet");
|
||||
bulletID = Entities.identifyEntity(bulletID);
|
||||
}
|
||||
if (targetID && !targetID.isKnownID) {
|
||||
targetID = Entities.identifyEntity(targetID);
|
||||
}
|
||||
// Check for mouseLook movement, update rotation
|
||||
// rotate body yaw for yaw received from mouse
|
||||
var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Radians( { x: 0, y: yawFromMouse, z: 0 } ));
|
||||
//MyAvatar.orientation = newOrientation;
|
||||
yawFromMouse = 0;
|
||||
|
||||
// apply pitch from mouse
|
||||
var newPitch = MyAvatar.headPitch + pitchFromMouse;
|
||||
//MyAvatar.headPitch = newPitch;
|
||||
pitchFromMouse = 0;
|
||||
|
||||
|
||||
if (activeControllers == 0) {
|
||||
if (Controller.getNumberOfSpatialControls() > 0) {
|
||||
activeControllers = Controller.getNumberOfSpatialControls();
|
||||
clearPose();
|
||||
}
|
||||
}
|
||||
|
||||
var KICKBACK_DECAY_RATE = 0.125;
|
||||
if (elbowKickAngle > 0.0) {
|
||||
if (elbowKickAngle > 0.5) {
|
||||
var newAngle = elbowKickAngle * KICKBACK_DECAY_RATE;
|
||||
elbowKickAngle -= newAngle;
|
||||
var armRotation = MyAvatar.getJointRotation("LeftForeArm");
|
||||
armRotation = Quat.multiply(armRotation, Quat.fromPitchYawRollDegrees(0.0, 0.0, -newAngle));
|
||||
MyAvatar.setJointData("LeftForeArm", armRotation);
|
||||
} else {
|
||||
MyAvatar.setJointData("LeftForeArm", rotationBeforeKickback);
|
||||
if (Controller.getNumberOfSpatialControls() > 0) {
|
||||
clearPose();
|
||||
}
|
||||
elbowKickAngle = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
// Check hydra controller for launch button press
|
||||
if (!isLaunchButtonPressed && Controller.isButtonPressed(LEFT_BUTTON_3)) {
|
||||
isLaunchButtonPressed = true;
|
||||
var time = MIN_THROWER_DELAY + Math.random() * MAX_THROWER_DELAY;
|
||||
Script.setTimeout(shootTarget, time);
|
||||
} else if (isLaunchButtonPressed && !Controller.isButtonPressed(LEFT_BUTTON_3)) {
|
||||
isLaunchButtonPressed = false;
|
||||
|
||||
}
|
||||
|
||||
// check for trigger press
|
||||
|
||||
var numberOfTriggers = 2;
|
||||
var controllersPerTrigger = 2;
|
||||
|
||||
if (numberOfTriggers == 2 && controllersPerTrigger == 2) {
|
||||
for (var t = 0; t < 2; t++) {
|
||||
var shootABullet = false;
|
||||
var triggerValue = Controller.getTriggerValue(t);
|
||||
if (triggerPulled[t]) {
|
||||
// must release to at least 0.1
|
||||
if (triggerValue < 0.1) {
|
||||
triggerPulled[t] = false; // unpulled
|
||||
}
|
||||
} else {
|
||||
// must pull to at least
|
||||
if (triggerValue > 0.5) {
|
||||
triggerPulled[t] = true; // pulled
|
||||
shootABullet = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (shootABullet) {
|
||||
var palmController = t * controllersPerTrigger;
|
||||
var palmPosition = Controller.getSpatialControlPosition(palmController);
|
||||
|
||||
var fingerTipController = palmController + 1;
|
||||
var fingerTipPosition = Controller.getSpatialControlPosition(fingerTipController);
|
||||
|
||||
var palmToFingerTipVector =
|
||||
{ x: (fingerTipPosition.x - palmPosition.x),
|
||||
y: (fingerTipPosition.y - palmPosition.y),
|
||||
z: (fingerTipPosition.z - palmPosition.z) };
|
||||
|
||||
// just off the front of the finger tip
|
||||
var position = { x: fingerTipPosition.x + palmToFingerTipVector.x/2,
|
||||
y: fingerTipPosition.y + palmToFingerTipVector.y/2,
|
||||
z: fingerTipPosition.z + palmToFingerTipVector.z/2};
|
||||
|
||||
var velocity = Vec3.multiply(BULLET_VELOCITY, Vec3.normalize(palmToFingerTipVector));
|
||||
|
||||
shootBullet(position, velocity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function mousePressEvent(event) {
|
||||
isMouseDown = true;
|
||||
lastX = event.x;
|
||||
lastY = event.y;
|
||||
|
||||
if (Overlays.getOverlayAtPoint({ x: event.x, y: event.y }) === offButton) {
|
||||
Script.stop();
|
||||
} else {
|
||||
shootFromMouse();
|
||||
}
|
||||
}
|
||||
|
||||
function shootFromMouse() {
|
||||
var DISTANCE_FROM_CAMERA = 2.0;
|
||||
var camera = Camera.getPosition();
|
||||
var forwardVector = Quat.getFront(Camera.getOrientation());
|
||||
var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_FROM_CAMERA));
|
||||
var velocity = Vec3.multiply(forwardVector, BULLET_VELOCITY);
|
||||
shootBullet(newPosition, velocity);
|
||||
}
|
||||
|
||||
function mouseReleaseEvent(event) {
|
||||
// position
|
||||
isMouseDown = false;
|
||||
}
|
||||
|
||||
function mouseMoveEvent(event) {
|
||||
if (isMouseDown) {
|
||||
var MOUSE_YAW_SCALE = -0.25;
|
||||
var MOUSE_PITCH_SCALE = -12.5;
|
||||
var FIXED_MOUSE_TIMESTEP = 0.016;
|
||||
yawFromMouse += ((event.x - lastX) * MOUSE_YAW_SCALE * FIXED_MOUSE_TIMESTEP);
|
||||
pitchFromMouse += ((event.y - lastY) * MOUSE_PITCH_SCALE * FIXED_MOUSE_TIMESTEP);
|
||||
lastX = event.x;
|
||||
lastY = event.y;
|
||||
}
|
||||
}
|
||||
|
||||
function scriptEnding() {
|
||||
Overlays.deleteOverlay(reticle);
|
||||
Overlays.deleteOverlay(offButton);
|
||||
Overlays.deleteOverlay(text);
|
||||
MyAvatar.detachOne(gunModel);
|
||||
clearPose();
|
||||
}
|
||||
|
||||
Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity);
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
Script.update.connect(update);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
||||
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
|
||||
|
||||
|
|
@ -31,8 +31,13 @@
|
|||
}
|
||||
function createEmitTextPropertyUpdateFunction(propertyName) {
|
||||
return function() {
|
||||
var properties = {};
|
||||
properties[propertyName] = this.value;
|
||||
EventBridge.emitWebEvent(
|
||||
'{ "type":"update", "properties":{"' + propertyName + '":"' + this.value + '"}}'
|
||||
JSON.stringify({
|
||||
type: "update",
|
||||
properties: properties,
|
||||
})
|
||||
);
|
||||
};
|
||||
}
|
||||
|
@ -146,6 +151,9 @@
|
|||
var elModelAnimationPlaying = document.getElementById("property-model-animation-playing");
|
||||
var elModelAnimationFPS = document.getElementById("property-model-animation-fps");
|
||||
var elModelAnimationFrame = document.getElementById("property-model-animation-frame");
|
||||
var elModelAnimationSettings = document.getElementById("property-model-animation-settings");
|
||||
var elModelTextures = document.getElementById("property-model-textures");
|
||||
var elModelOriginalTextures = document.getElementById("property-model-original-textures");
|
||||
|
||||
var elTextSections = document.querySelectorAll(".text-section");
|
||||
var elTextText = document.getElementById("property-text-text");
|
||||
|
@ -244,6 +252,10 @@
|
|||
elModelAnimationURL.value = properties.animationURL;
|
||||
elModelAnimationPlaying.checked = properties.animationIsPlaying;
|
||||
elModelAnimationFPS.value = properties.animationFPS;
|
||||
elModelAnimationFrame.value = properties.animationFrameIndex;
|
||||
elModelAnimationSettings.value = properties.animationSettings;
|
||||
elModelTextures.value = properties.textures;
|
||||
elModelOriginalTextures.value = properties.originalTextures;
|
||||
}
|
||||
|
||||
if (properties.type != "Text") {
|
||||
|
@ -387,6 +399,8 @@
|
|||
elModelAnimationPlaying.addEventListener('change', createEmitCheckedPropertyUpdateFunction('animationIsPlaying'));
|
||||
elModelAnimationFPS.addEventListener('change', createEmitNumberPropertyUpdateFunction('animationFPS'));
|
||||
elModelAnimationFrame.addEventListener('change', createEmitNumberPropertyUpdateFunction('animationFrameIndex'));
|
||||
elModelAnimationSettings.addEventListener('change', createEmitTextPropertyUpdateFunction('animationSettings'));
|
||||
elModelTextures.addEventListener('change', createEmitTextPropertyUpdateFunction('textures'));
|
||||
|
||||
elTextText.addEventListener('change', createEmitTextPropertyUpdateFunction('text'));
|
||||
elTextLineHeight.addEventListener('change', createEmitNumberPropertyUpdateFunction('lineHeight'));
|
||||
|
@ -429,7 +443,6 @@
|
|||
}));
|
||||
});
|
||||
|
||||
|
||||
var resizing = false;
|
||||
var startX = 0;
|
||||
var originalWidth = 0;
|
||||
|
@ -679,6 +692,24 @@
|
|||
<input class="coord" type='number' id="property-model-animation-frame"></input>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="model-section">
|
||||
<td class="label">Animation Settings</td>
|
||||
<td>
|
||||
<textarea id="property-model-animation-settings" value='asdfasdf'></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="model-section">
|
||||
<td class="label">Textures</td>
|
||||
<td>
|
||||
<textarea id="property-model-textures" value='asdfasdf'></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="model-section">
|
||||
<td class="label">Original Textures</td>
|
||||
<td>
|
||||
<textarea id="property-model-original-textures" readonly value='asdfasdf'></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr class="text-section">
|
||||
|
|
|
@ -90,12 +90,17 @@ input[type=button] {
|
|||
font-size: .9em;
|
||||
}
|
||||
|
||||
input {
|
||||
textarea, input {
|
||||
padding: 2px;
|
||||
border: 1px solid #999;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
input.url {
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
@ -105,6 +105,8 @@ CameraManager = function() {
|
|||
Camera.mode = "independent";
|
||||
|
||||
that.updateCamera();
|
||||
|
||||
cameraTool.setVisible(true);
|
||||
}
|
||||
|
||||
that.disable = function(ignoreCamera) {
|
||||
|
@ -115,6 +117,7 @@ CameraManager = function() {
|
|||
if (!ignoreCamera) {
|
||||
Camera.mode = that.previousCameraMode;
|
||||
}
|
||||
cameraTool.setVisible(false);
|
||||
}
|
||||
|
||||
that.focus = function(position, dimensions, easeOrientation) {
|
||||
|
@ -243,9 +246,9 @@ CameraManager = function() {
|
|||
}
|
||||
|
||||
that.mousePressEvent = function(event) {
|
||||
// if (cameraTool.mousePressEvent(event)) {
|
||||
// return true;
|
||||
// }
|
||||
if (cameraTool.mousePressEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!that.enabled) return;
|
||||
|
||||
|
@ -291,7 +294,7 @@ CameraManager = function() {
|
|||
|
||||
that.updateCamera = function() {
|
||||
if (!that.enabled || Camera.mode != "independent") {
|
||||
// cameraTool.update();
|
||||
cameraTool.update();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -313,7 +316,7 @@ CameraManager = function() {
|
|||
|
||||
Camera.setOrientation(q);
|
||||
|
||||
// cameraTool.update();
|
||||
cameraTool.update();
|
||||
}
|
||||
|
||||
function normalizeDegrees(degrees) {
|
||||
|
@ -383,7 +386,7 @@ CameraManager = function() {
|
|||
|
||||
Controller.wheelEvent.connect(that.wheelEvent);
|
||||
|
||||
// var cameraTool = new CameraTool(that);
|
||||
var cameraTool = new CameraTool(that);
|
||||
|
||||
return that;
|
||||
}
|
||||
|
@ -395,43 +398,21 @@ CameraTool = function(cameraManager) {
|
|||
var GREEN = { red: 26, green: 193, blue: 105 };
|
||||
var BLUE = { red: 0, green: 131, blue: 204 };
|
||||
|
||||
var ORIENTATION_OVERLAY_SIZE = 20;
|
||||
var BORDER_WIDTH = 1;
|
||||
|
||||
var ORIENTATION_OVERLAY_SIZE = 26;
|
||||
var ORIENTATION_OVERLAY_HALF_SIZE = ORIENTATION_OVERLAY_SIZE / 2;
|
||||
var ORIENTATION_OVERLAY_CUBE_SIZE = 8,
|
||||
var ORIENTATION_OVERLAY_CUBE_SIZE = 10.5,
|
||||
|
||||
var ORIENTATION_OVERLAY_OFFSET = {
|
||||
x: 96,
|
||||
x: 30,
|
||||
y: 30,
|
||||
}
|
||||
|
||||
var UI_URL = HIFI_PUBLIC_BUCKET + "images/tools/camera-controls.svg";
|
||||
|
||||
var UI_WIDTH = 128;
|
||||
var UI_HEIGHT = 61;
|
||||
var UI_WIDTH = 70;
|
||||
var UI_HEIGHT = 70;
|
||||
var UI_PADDING = 10;
|
||||
|
||||
var UI_BUTTON_WIDTH = 64;
|
||||
var UI_BUTTON_HEIGHT = 30;
|
||||
|
||||
var UI_SUBIMAGE_FIRST_PERSON = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: UI_WIDTH,
|
||||
height: UI_HEIGHT
|
||||
},
|
||||
var UI_SUBIMAGE_THIRD_PERSON = {
|
||||
x: 0,
|
||||
y: UI_HEIGHT,
|
||||
width: UI_WIDTH,
|
||||
height: UI_HEIGHT
|
||||
},
|
||||
var UI_SUBIMAGE_OTHER = {
|
||||
x: 0,
|
||||
y: UI_HEIGHT * 2,
|
||||
width: UI_WIDTH,
|
||||
height: UI_HEIGHT
|
||||
},
|
||||
|
||||
var lastKnownWidth = Window.innerWidth;
|
||||
|
||||
var uiPosition = {
|
||||
|
@ -439,20 +420,28 @@ CameraTool = function(cameraManager) {
|
|||
y: UI_PADDING,
|
||||
};
|
||||
|
||||
var ui = Overlays.addOverlay("image", {
|
||||
imageURL: UI_URL,
|
||||
var backgroundBorder = Overlays.addOverlay("text", {
|
||||
x: uiPosition.x - BORDER_WIDTH,
|
||||
y: uiPosition.y - BORDER_WIDTH,
|
||||
width: UI_WIDTH + BORDER_WIDTH * 2,
|
||||
height: UI_HEIGHT + BORDER_WIDTH * 2,
|
||||
alpha: 0,
|
||||
text: "",
|
||||
backgroundColor: { red: 101, green: 101, blue: 101 },
|
||||
backgroundAlpha: 1.0,
|
||||
visible: false,
|
||||
});
|
||||
|
||||
var background = Overlays.addOverlay("text", {
|
||||
x: uiPosition.x,
|
||||
y: uiPosition.y,
|
||||
subImage: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: UI_WIDTH,
|
||||
height: UI_HEIGHT
|
||||
},
|
||||
width: UI_WIDTH,
|
||||
height: UI_HEIGHT,
|
||||
alpha: 1.0,
|
||||
visible: true
|
||||
alpha: 0,
|
||||
text: "",
|
||||
backgroundColor: { red: 51, green: 51, blue: 51 },
|
||||
backgroundAlpha: 1.0,
|
||||
visible: false,
|
||||
});
|
||||
|
||||
var defaultCubeProps = {
|
||||
|
@ -470,15 +459,16 @@ CameraTool = function(cameraManager) {
|
|||
start: { x: 0, y: 0, z: 0 },
|
||||
end: { x: 0, y: 0, z: 0 },
|
||||
color: { red: 255, green: 0, blue: 0 },
|
||||
visible: true,
|
||||
visible: false,
|
||||
drawOnHUD: true,
|
||||
};
|
||||
|
||||
var orientationOverlay = OverlayGroup({
|
||||
position: {
|
||||
x: uiPosition.x + ORIENTATION_OVERLAY_OFFSET.x,
|
||||
y: uiPosition.y + ORIENTATION_OVERLAY_OFFSET.y,
|
||||
}
|
||||
x: uiPosition.x + UI_WIDTH / 2,
|
||||
y: uiPosition.y + UI_HEIGHT / 2,
|
||||
},
|
||||
visible: false,
|
||||
});
|
||||
|
||||
var OOHS = ORIENTATION_OVERLAY_HALF_SIZE;
|
||||
|
@ -512,7 +502,8 @@ CameraTool = function(cameraManager) {
|
|||
|
||||
Script.scriptEnding.connect(function() {
|
||||
orientationOverlay.destroy();
|
||||
Overlays.deleteOverlay(ui);
|
||||
Overlays.deleteOverlay(background);
|
||||
Overlays.deleteOverlay(backgroundBorder);
|
||||
});
|
||||
|
||||
var flip = Quat.fromPitchYawRollDegrees(0, 180, 0);
|
||||
|
@ -527,16 +518,20 @@ CameraTool = function(cameraManager) {
|
|||
x: lastKnownWidth - UI_WIDTH - UI_PADDING,
|
||||
y: UI_PADDING,
|
||||
};
|
||||
Overlays.editOverlay(ui, {
|
||||
x: uiPosition.x,
|
||||
y: uiPosition.y
|
||||
});
|
||||
orientationOverlay.setProperties({
|
||||
position: {
|
||||
x: uiPosition.x + ORIENTATION_OVERLAY_OFFSET.x,
|
||||
y: uiPosition.y + ORIENTATION_OVERLAY_OFFSET.y,
|
||||
}
|
||||
});
|
||||
Overlays.editOverlay(backgroundBorder, {
|
||||
x: uiPosition.x - BORDER_WIDTH,
|
||||
y: uiPosition.y - BORDER_WIDTH,
|
||||
});
|
||||
Overlays.editOverlay(background, {
|
||||
x: uiPosition.x,
|
||||
y: uiPosition.y,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -558,40 +553,16 @@ CameraTool = function(cameraManager) {
|
|||
targetYaw = event.isLeftButton ? 0 : 180;
|
||||
cameraManager.setTargetPitchYaw(targetPitch, targetYaw);
|
||||
return true;
|
||||
} else if (clickedOverlay == ui) {
|
||||
var x = event.x - uiPosition.x;
|
||||
var y = event.y - uiPosition.y;
|
||||
|
||||
// Did we hit a button?
|
||||
if (x < UI_BUTTON_WIDTH) {
|
||||
if (y < UI_BUTTON_HEIGHT) {
|
||||
Camera.mode = "first person";
|
||||
} else {
|
||||
Camera.mode = "third person";
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
function updateMode() {
|
||||
var mode = Camera.mode;
|
||||
|
||||
var subImage = UI_SUBIMAGE_OTHER;
|
||||
if (mode == "first person") {
|
||||
subImage = UI_SUBIMAGE_FIRST_PERSON;
|
||||
} else if (mode == "third person") {
|
||||
subImage = UI_SUBIMAGE_THIRD_PERSON;
|
||||
}
|
||||
|
||||
Overlays.editOverlay(ui, { subImage: subImage });
|
||||
}
|
||||
|
||||
Camera.modeUpdated.connect(updateMode);
|
||||
updateMode();
|
||||
|
||||
that.setVisible = function(visible) {
|
||||
orientationOverlay.setProperties({ visible: visible });
|
||||
Overlays.editOverlay(background, { visible: visible });
|
||||
Overlays.editOverlay(backgroundBorder, { visible: visible });
|
||||
};
|
||||
|
||||
that.setVisible(false);
|
||||
|
||||
return that;
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@ OverlayGroup = function(opts) {
|
|||
|
||||
var rootPosition = opts.position || { x: 0, y: 0, z: 0 };
|
||||
var rootRotation = opts.rotation || Quat.fromPitchYawRollRadians(0, 0, 0);
|
||||
var visible = true;
|
||||
var visible = opts.visible == true;
|
||||
|
||||
function updateOverlays() {
|
||||
for (overlayID in overlays) {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
//
|
||||
|
||||
|
||||
var buttonImageUrl = "https://public.highfidelity.io/images/tools/sit.svg";
|
||||
var buttonImageUrl = "https://s3.amazonaws.com/hifi-public/images/tools/sit.svg";
|
||||
|
||||
var windowDimensions = Controller.getViewportDimensions();
|
||||
|
||||
|
|
|
@ -3469,6 +3469,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
scriptEngine->registerGlobalObject("Metavoxels", &_metavoxels);
|
||||
|
||||
scriptEngine->registerGlobalObject("GlobalServices", GlobalServicesScriptingInterface::getInstance());
|
||||
qScriptRegisterMetaType(scriptEngine, DownloadInfoResultToScriptValue, DownloadInfoResultFromScriptValue);
|
||||
|
||||
scriptEngine->registerGlobalObject("AvatarManager", &_avatarManager);
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <mmdeviceapi.h>
|
||||
#include <devicetopology.h>
|
||||
#include <Functiondiscoverykeys_devpkey.h>
|
||||
#include <VersionHelpers.h>
|
||||
#endif
|
||||
|
||||
#include <AudioConstants.h>
|
||||
|
@ -179,12 +180,7 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
|
|||
#ifdef WIN32
|
||||
QString deviceName;
|
||||
//Check for Windows Vista or higher, IMMDeviceEnumerator doesn't work below that.
|
||||
OSVERSIONINFO osvi;
|
||||
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
|
||||
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||
GetVersionEx(&osvi);
|
||||
const DWORD VISTA_MAJOR_VERSION = 6;
|
||||
if (osvi.dwMajorVersion < VISTA_MAJOR_VERSION) {// lower then vista
|
||||
if (!IsWindowsVistaOrGreater()) { // lower then vista
|
||||
if (mode == QAudio::AudioInput) {
|
||||
WAVEINCAPS wic;
|
||||
// first use WAVE_MAPPER to get the default devices manufacturer ID
|
||||
|
@ -223,9 +219,7 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
|
|||
pPropertyStore->Release();
|
||||
pPropertyStore = NULL;
|
||||
deviceName = QString::fromWCharArray((wchar_t*)pv.pwszVal);
|
||||
const DWORD WINDOWS7_MAJOR_VERSION = 6;
|
||||
const DWORD WINDOWS7_MINOR_VERSION = 1;
|
||||
if (osvi.dwMajorVersion <= WINDOWS7_MAJOR_VERSION && osvi.dwMinorVersion <= WINDOWS7_MINOR_VERSION) {
|
||||
if (!IsWindows8OrGreater()) {
|
||||
// Windows 7 provides only the 31 first characters of the device name.
|
||||
const DWORD QT_WIN7_MAX_AUDIO_DEVICENAME_LEN = 31;
|
||||
deviceName = deviceName.left(QT_WIN7_MAX_AUDIO_DEVICENAME_LEN);
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
#include <cstdlib>
|
||||
|
||||
|
||||
#include <QBoxLayout>
|
||||
#include <QColorDialog>
|
||||
#include <QDialogButtonBox>
|
||||
|
@ -44,20 +43,26 @@
|
|||
#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"
|
||||
#include "scripting/MenuScriptingInterface.h"
|
||||
#include "Util.h"
|
||||
#include "ui/AddressBarDialog.h"
|
||||
#include "ui/AnimationsDialog.h"
|
||||
#include "ui/AttachmentsDialog.h"
|
||||
#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.h"
|
||||
#include "ui/PreferencesDialog.h"
|
||||
#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;
|
||||
|
@ -79,56 +84,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(),
|
||||
_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
|
||||
_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),
|
||||
_loginAction(NULL),
|
||||
_preferencesDialog(NULL),
|
||||
_loginDialog(NULL),
|
||||
_hasLoginDialogDisplayed(false),
|
||||
_snapshotsLocation(),
|
||||
_scriptsLocation(),
|
||||
_walletPrivateKey(),
|
||||
_shouldRenderTableNeedsRebuilding(true)
|
||||
_lastAvatarDetailDrop(usecTimestampNow())
|
||||
{
|
||||
Application *appInstance = Application::getInstance();
|
||||
|
||||
|
@ -354,11 +312,8 @@ Menu::Menu() :
|
|||
|
||||
QMenu* nodeBordersMenu = viewMenu->addMenu("Server Borders");
|
||||
NodeBounds& nodeBounds = appInstance->getNodeBoundsDisplay();
|
||||
addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersVoxelNodes,
|
||||
Qt::CTRL | Qt::SHIFT | Qt::Key_1, false,
|
||||
&nodeBounds, SLOT(setShowVoxelNodes(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersEntityNodes,
|
||||
Qt::CTRL | Qt::SHIFT | Qt::Key_2, false,
|
||||
Qt::CTRL | Qt::SHIFT | Qt::Key_1, false,
|
||||
&nodeBounds, SLOT(setShowEntityNodes(bool)));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::OffAxisProjection, 0, false);
|
||||
|
@ -492,6 +447,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()));
|
||||
|
||||
|
@ -619,15 +575,6 @@ Menu::Menu() :
|
|||
#endif
|
||||
}
|
||||
|
||||
Menu::~Menu() {
|
||||
bandwidthDetailsClosed();
|
||||
octreeStatsDetailsClosed();
|
||||
if (_hmdToolsDialog) {
|
||||
delete _hmdToolsDialog;
|
||||
_hmdToolsDialog = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::loadSettings(QSettings* settings) {
|
||||
bool lockedSettings = false;
|
||||
if (!settings) {
|
||||
|
@ -1153,7 +1100,7 @@ void Menu::bandwidthDetails() {
|
|||
if (! _bandwidthDialog) {
|
||||
_bandwidthDialog = new BandwidthDialog(DependencyManager::get<GLCanvas>().data(),
|
||||
Application::getInstance()->getBandwidthMeter());
|
||||
connect(_bandwidthDialog, SIGNAL(closed()), SLOT(bandwidthDetailsClosed()));
|
||||
connect(_bandwidthDialog, SIGNAL(closed()), _bandwidthDialog, SLOT(deleteLater()));
|
||||
|
||||
_bandwidthDialog->show();
|
||||
|
||||
|
@ -1253,18 +1200,11 @@ void Menu::audioMuteToggled() {
|
|||
}
|
||||
}
|
||||
|
||||
void Menu::bandwidthDetailsClosed() {
|
||||
if (_bandwidthDialog) {
|
||||
delete _bandwidthDialog;
|
||||
_bandwidthDialog = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::octreeStatsDetails() {
|
||||
if (!_octreeStatsDialog) {
|
||||
_octreeStatsDialog = new OctreeStatsDialog(DependencyManager::get<GLCanvas>().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());
|
||||
|
@ -1273,13 +1213,6 @@ void Menu::octreeStatsDetails() {
|
|||
_octreeStatsDialog->raise();
|
||||
}
|
||||
|
||||
void Menu::octreeStatsDetailsClosed() {
|
||||
if (_octreeStatsDialog) {
|
||||
delete _octreeStatsDialog;
|
||||
_octreeStatsDialog = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
QString Menu::getLODFeedbackText() {
|
||||
// determine granularity feedback
|
||||
int boundaryLevelAdjust = getBoundaryLevelAdjust();
|
||||
|
@ -1443,11 +1376,23 @@ 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<GLCanvas>().data());
|
||||
connect(_cachesSizeDialog, SIGNAL(closed()), _cachesSizeDialog, SLOT(deleteLater()));
|
||||
_cachesSizeDialog->show();
|
||||
if (_hmdToolsDialog) {
|
||||
_hmdToolsDialog->watchWindow(_cachesSizeDialog->windowHandle());
|
||||
}
|
||||
}
|
||||
_cachesSizeDialog->raise();
|
||||
}
|
||||
|
||||
void Menu::lodTools() {
|
||||
if (!_lodToolsDialog) {
|
||||
_lodToolsDialog = new LodToolsDialog(DependencyManager::get<GLCanvas>().data());
|
||||
connect(_lodToolsDialog, SIGNAL(closed()), SLOT(lodToolsClosed()));
|
||||
connect(_lodToolsDialog, SIGNAL(closed()), _lodToolsDialog, SLOT(deleteLater()));
|
||||
_lodToolsDialog->show();
|
||||
if (_hmdToolsDialog) {
|
||||
_hmdToolsDialog->watchWindow(_lodToolsDialog->windowHandle());
|
||||
|
@ -1456,13 +1401,6 @@ void Menu::lodTools() {
|
|||
_lodToolsDialog->raise();
|
||||
}
|
||||
|
||||
void Menu::lodToolsClosed() {
|
||||
if (_lodToolsDialog) {
|
||||
delete _lodToolsDialog;
|
||||
_lodToolsDialog = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::hmdTools(bool showTools) {
|
||||
if (showTools) {
|
||||
if (!_hmdToolsDialog) {
|
||||
|
|
|
@ -27,14 +27,13 @@
|
|||
#include "SpeechRecognizer.h"
|
||||
#endif
|
||||
|
||||
#include "ui/AddressBarDialog.h"
|
||||
#include "devices/Faceshift.h"
|
||||
#include "devices/SixenseManager.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"
|
||||
|
||||
// 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;
|
||||
|
@ -50,26 +49,37 @@ 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 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 float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f;
|
||||
|
||||
const QString SETTINGS_ADDRESS_KEY = "address";
|
||||
class QSettings;
|
||||
|
||||
class AddressBarDialog;
|
||||
class AnimationsDialog;
|
||||
class AttachmentsDialog;
|
||||
class CachesSizeDialog;
|
||||
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);
|
||||
|
@ -159,6 +169,7 @@ public slots:
|
|||
void showLoginForCurrentDomain();
|
||||
void bandwidthDetails();
|
||||
void octreeStatsDetails();
|
||||
void cachesSizeDialog();
|
||||
void lodTools();
|
||||
void hmdTools(bool showTools);
|
||||
void loadSettings(QSettings* settings = NULL);
|
||||
|
@ -191,9 +202,6 @@ private slots:
|
|||
void changePrivateKey();
|
||||
void nameLocation();
|
||||
void toggleLocationList();
|
||||
void bandwidthDetailsClosed();
|
||||
void octreeStatsDetailsClosed();
|
||||
void lodToolsClosed();
|
||||
void hmdToolsClosed();
|
||||
void runTests();
|
||||
void showMetavoxelEditor();
|
||||
|
@ -242,54 +250,63 @@ private:
|
|||
|
||||
QHash<QString, QAction*> _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;
|
||||
QString _faceshiftHostname;
|
||||
// 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 = 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 = FIVE_SECONDS_OF_FRAMES;
|
||||
SimpleMovingAverage _fastFPSAverage = ONE_SECOND_OF_FRAMES;
|
||||
|
||||
QPointer<AddressBarDialog> _addressBarDialog;
|
||||
QPointer<AnimationsDialog> _animationsDialog;
|
||||
QPointer<AttachmentsDialog> _attachmentsDialog;
|
||||
QPointer<BandwidthDialog> _bandwidthDialog;
|
||||
QPointer<CachesSizeDialog> _cachesSizeDialog;
|
||||
QPointer<DataWebDialog> _newLocationDialog;
|
||||
QPointer<DataWebDialog> _userLocationsDialog;
|
||||
QPointer<HMDToolsDialog> _hmdToolsDialog;
|
||||
QPointer<LodToolsDialog> _lodToolsDialog;
|
||||
QPointer<LoginDialog> _loginDialog;
|
||||
QPointer<OctreeStatsDialog> _octreeStatsDialog;
|
||||
QPointer<PreferencesDialog> _preferencesDialog;
|
||||
|
||||
QPointer<MetavoxelEditor> _MetavoxelEditor;
|
||||
QPointer<MetavoxelNetworkSimulator> _metavoxelNetworkSimulator;
|
||||
QPointer<ScriptEditorWindow> _ScriptEditor;
|
||||
QPointer<ChatWindow> _chatWindow;
|
||||
QDialog* _jsConsole;
|
||||
OctreeStatsDialog* _octreeStatsDialog;
|
||||
LodToolsDialog* _lodToolsDialog;
|
||||
HMDToolsDialog* _hmdToolsDialog;
|
||||
QPointer<DataWebDialog> _newLocationDialog;
|
||||
QPointer<DataWebDialog> _userLocationsDialog;
|
||||
#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;
|
||||
QString replaceLastOccurrence(QChar search, QChar replace, QString string);
|
||||
quint64 _lastAdjust;
|
||||
quint64 _lastAvatarDetailDrop;
|
||||
SimpleMovingAverage _fpsAverage;
|
||||
SimpleMovingAverage _fastFPSAverage;
|
||||
QAction* _loginAction;
|
||||
QPointer<PreferencesDialog> _preferencesDialog;
|
||||
QPointer<AttachmentsDialog> _attachmentsDialog;
|
||||
QPointer<AnimationsDialog> _animationsDialog;
|
||||
QPointer<AddressBarDialog> _addressBarDialog;
|
||||
QPointer<LoginDialog> _loginDialog;
|
||||
bool _hasLoginDialogDisplayed;
|
||||
QAction* _chatAction;
|
||||
|
||||
QAction* _loginAction = nullptr;
|
||||
QAction* _chatAction = nullptr;
|
||||
QString _snapshotsLocation;
|
||||
QString _scriptsLocation;
|
||||
QByteArray _walletPrivateKey;
|
||||
|
||||
bool _shouldRenderTableNeedsRebuilding;
|
||||
bool _shouldRenderTableNeedsRebuilding = true;
|
||||
QMap<float, float> _shouldRenderTable;
|
||||
|
||||
};
|
||||
|
||||
namespace MenuOption {
|
||||
|
@ -318,6 +335,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)";
|
||||
|
@ -406,7 +424,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";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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, public Dependency {
|
||||
Q_OBJECT
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "InterfaceConfig.h"
|
||||
|
||||
#include "OculusManager.h"
|
||||
#include "ui/overlays/Text3DOverlay.h"
|
||||
|
||||
#include <QDesktopWidget>
|
||||
#include <QGuiApplication>
|
||||
|
|
|
@ -19,12 +19,9 @@
|
|||
|
||||
#include <ProgramObject.h>
|
||||
|
||||
#include "ui/overlays/Text3DOverlay.h"
|
||||
|
||||
const float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f;
|
||||
|
||||
class Camera;
|
||||
class PalmData;
|
||||
class Text3DOverlay;
|
||||
|
||||
/// Handles interaction with the Oculus Rift.
|
||||
class OculusManager {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
//
|
||||
|
||||
#include "AccountManager.h"
|
||||
#include "Application.h"
|
||||
#include "ResourceCache.h"
|
||||
#include "XmppClient.h"
|
||||
|
||||
#include "GlobalServicesScriptingInterface.h"
|
||||
|
@ -25,6 +27,10 @@ GlobalServicesScriptingInterface::GlobalServicesScriptingInterface() {
|
|||
const QXmppClient& qxmppClient = XmppClient::getInstance().getXMPPClient();
|
||||
connect(&qxmppClient, &QXmppClient::messageReceived, this, &GlobalServicesScriptingInterface::messageReceived);
|
||||
#endif // HAVE_QXMPP
|
||||
|
||||
_downloading = false;
|
||||
connect(Application::getInstance(), &Application::renderingInWorldInterface,
|
||||
this, &GlobalServicesScriptingInterface::checkDownloadInfo);
|
||||
}
|
||||
|
||||
GlobalServicesScriptingInterface::~GlobalServicesScriptingInterface() {
|
||||
|
@ -38,14 +44,16 @@ GlobalServicesScriptingInterface::~GlobalServicesScriptingInterface() {
|
|||
const QXmppClient& qxmppClient = XmppClient::getInstance().getXMPPClient();
|
||||
disconnect(&qxmppClient, &QXmppClient::messageReceived, this, &GlobalServicesScriptingInterface::messageReceived);
|
||||
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
|
||||
disconnect(publicChatRoom, &QXmppMucRoom::participantsChanged, this, &GlobalServicesScriptingInterface::participantsChanged);
|
||||
disconnect(publicChatRoom, &QXmppMucRoom::participantsChanged,
|
||||
this, &GlobalServicesScriptingInterface::participantsChanged);
|
||||
#endif // HAVE_QXMPP
|
||||
}
|
||||
|
||||
void GlobalServicesScriptingInterface::onConnected() {
|
||||
#ifdef HAVE_QXMPP
|
||||
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
|
||||
connect(publicChatRoom, &QXmppMucRoom::participantsChanged, this, &GlobalServicesScriptingInterface::participantsChanged, Qt::UniqueConnection);
|
||||
connect(publicChatRoom, &QXmppMucRoom::participantsChanged,
|
||||
this, &GlobalServicesScriptingInterface::participantsChanged, Qt::UniqueConnection);
|
||||
#endif // HAVE_QXMPP
|
||||
}
|
||||
|
||||
|
@ -110,6 +118,61 @@ void GlobalServicesScriptingInterface::messageReceived(const QXmppMessage& messa
|
|||
return;
|
||||
}
|
||||
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
|
||||
emit GlobalServicesScriptingInterface::incomingMessage(message.from().right(message.from().count() - 1 - publicChatRoom->jid().count()), message.body());
|
||||
QString username = message.from().right(message.from().count() - 1 - publicChatRoom->jid().count());
|
||||
emit GlobalServicesScriptingInterface::incomingMessage(username, message.body());
|
||||
}
|
||||
#endif // HAVE_QXMPP
|
||||
|
||||
|
||||
DownloadInfoResult::DownloadInfoResult() :
|
||||
downloading(QList<float>()),
|
||||
pending(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
QScriptValue DownloadInfoResultToScriptValue(QScriptEngine* engine, const DownloadInfoResult& result) {
|
||||
QScriptValue object = engine->newObject();
|
||||
|
||||
QScriptValue array = engine->newArray(result.downloading.count());
|
||||
for (int i = 0; i < result.downloading.count(); i += 1) {
|
||||
array.setProperty(i, result.downloading[i]);
|
||||
}
|
||||
|
||||
object.setProperty("downloading", array);
|
||||
object.setProperty("pending", result.pending);
|
||||
return object;
|
||||
}
|
||||
|
||||
void DownloadInfoResultFromScriptValue(const QScriptValue& object, DownloadInfoResult& result) {
|
||||
QList<QVariant> downloading = object.property("downloading").toVariant().toList();
|
||||
result.downloading.clear();
|
||||
for (int i = 0; i < downloading.count(); i += 1) {
|
||||
result.downloading.append(downloading[i].toFloat());
|
||||
}
|
||||
|
||||
result.pending = object.property("pending").toVariant().toFloat();
|
||||
}
|
||||
|
||||
DownloadInfoResult GlobalServicesScriptingInterface::getDownloadInfo() {
|
||||
DownloadInfoResult result;
|
||||
foreach(Resource* resource, ResourceCache::getLoadingRequests()) {
|
||||
result.downloading.append(resource->getProgress() * 100.0f);
|
||||
}
|
||||
result.pending = ResourceCache::getPendingRequestCount();
|
||||
return result;
|
||||
}
|
||||
|
||||
void GlobalServicesScriptingInterface::checkDownloadInfo() {
|
||||
DownloadInfoResult downloadInfo = getDownloadInfo();
|
||||
bool downloading = downloadInfo.downloading.count() > 0 || downloadInfo.pending > 0;
|
||||
|
||||
// Emit signal if downloading or have just finished.
|
||||
if (downloading || _downloading) {
|
||||
_downloading = downloading;
|
||||
emit downloadInfoChanged(downloadInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void GlobalServicesScriptingInterface::updateDownloadInfo() {
|
||||
emit downloadInfoChanged(getDownloadInfo());
|
||||
}
|
||||
|
|
|
@ -26,6 +26,19 @@
|
|||
|
||||
#endif // HAVE_QXMPP
|
||||
|
||||
class DownloadInfoResult {
|
||||
public:
|
||||
DownloadInfoResult();
|
||||
QList<float> downloading; // List of percentages
|
||||
float pending;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(DownloadInfoResult)
|
||||
|
||||
QScriptValue DownloadInfoResultToScriptValue(QScriptEngine* engine, const DownloadInfoResult& result);
|
||||
void DownloadInfoResultFromScriptValue(const QScriptValue& object, DownloadInfoResult& result);
|
||||
|
||||
|
||||
class GlobalServicesScriptingInterface : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool isConnected READ isConnected)
|
||||
|
@ -42,6 +55,8 @@ public:
|
|||
|
||||
public slots:
|
||||
QScriptValue chat(const QString& message);
|
||||
DownloadInfoResult getDownloadInfo();
|
||||
void updateDownloadInfo();
|
||||
|
||||
private slots:
|
||||
void loggedOut();
|
||||
|
@ -50,6 +65,7 @@ private slots:
|
|||
#ifdef HAVE_QXMPP
|
||||
void messageReceived(const QXmppMessage& message);
|
||||
#endif // HAVE_QXMPP
|
||||
void checkDownloadInfo();
|
||||
|
||||
signals:
|
||||
void connected();
|
||||
|
@ -57,6 +73,10 @@ signals:
|
|||
void incomingMessage(const QString& username, const QString& message);
|
||||
void onlineUsersChanged(const QStringList& usernames);
|
||||
void myUsernameChanged(const QString& username);
|
||||
void downloadInfoChanged(DownloadInfoResult info);
|
||||
|
||||
private:
|
||||
bool _downloading;
|
||||
};
|
||||
|
||||
#endif // hifi_GlobalServicesScriptingInterface_h
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#ifndef hifi_ApplicationOverlay_h
|
||||
#define hifi_ApplicationOverlay_h
|
||||
|
||||
class Camera;
|
||||
class Overlays;
|
||||
class QOpenGLFramebufferObject;
|
||||
|
||||
|
|
85
interface/src/ui/CachesSizeDialog.cpp
Normal file
85
interface/src/ui/CachesSizeDialog.cpp
Normal file
|
@ -0,0 +1,85 @@
|
|||
//
|
||||
// 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 <QDoubleSpinBox>
|
||||
#include <QFormLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
#include <AnimationCache.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <ScriptCache.h>
|
||||
#include <SoundCache.h>
|
||||
#include <TextureCache.h>
|
||||
|
||||
#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<AnimationCache>()->setUnusedResourceCacheSize(_animations->value() * BYTES_PER_MEGABYTES);
|
||||
DependencyManager::get<GeometryCache>()->setUnusedResourceCacheSize(_geometries->value() * BYTES_PER_MEGABYTES);
|
||||
ScriptCache::getInstance()->setUnusedResourceCacheSize(_scripts->value() * BYTES_PER_MEGABYTES);
|
||||
SoundCache::getInstance().setUnusedResourceCacheSize(_sounds->value() * BYTES_PER_MEGABYTES);
|
||||
DependencyManager::get<TextureCache>()->setUnusedResourceCacheSize(_textures->value() * BYTES_PER_MEGABYTES);
|
||||
|
||||
QDialog::close();
|
||||
}
|
||||
|
||||
void CachesSizeDialog::resetClicked(bool checked) {
|
||||
_animations->setValue(DependencyManager::get<AnimationCache>()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES);
|
||||
_geometries->setValue(DependencyManager::get<GeometryCache>()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES);
|
||||
_scripts->setValue(ScriptCache::getInstance()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES);
|
||||
_sounds->setValue(SoundCache::getInstance().getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES);
|
||||
_textures->setValue(DependencyManager::get<TextureCache>()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES);
|
||||
}
|
||||
|
||||
void CachesSizeDialog::reject() {
|
||||
// Just regularly close upon ESC
|
||||
QDialog::close();
|
||||
}
|
||||
|
||||
void CachesSizeDialog::closeEvent(QCloseEvent* event) {
|
||||
QDialog::closeEvent(event);
|
||||
emit closed();
|
||||
}
|
45
interface/src/ui/CachesSizeDialog.h
Normal file
45
interface/src/ui/CachesSizeDialog.h
Normal file
|
@ -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 <QDialog>
|
||||
|
||||
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
|
|
@ -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:
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -13,18 +13,17 @@
|
|||
#define hifi_LodToolsDialog_h
|
||||
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
#include <QSlider>
|
||||
|
||||
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;
|
||||
|
|
|
@ -31,8 +31,6 @@
|
|||
#include "FlowLayout.h"
|
||||
#include "JSConsole.h"
|
||||
|
||||
const int CONSOLE_HEIGHT = 150;
|
||||
|
||||
ScriptEditorWindow::ScriptEditorWindow() :
|
||||
_ScriptEditorWindowUI(new Ui::ScriptEditorWindow),
|
||||
_loadMenu(new QMenu),
|
||||
|
|
|
@ -17,7 +17,10 @@
|
|||
static int animationPointerMetaTypeId = qRegisterMetaType<AnimationPointer>();
|
||||
|
||||
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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -35,25 +35,25 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) {
|
|||
_created = UNKNOWN_CREATED_TIME;
|
||||
_changedOnServer = 0;
|
||||
|
||||
_position = glm::vec3(0,0,0);
|
||||
_dimensions = DEFAULT_DIMENSIONS;
|
||||
_rotation = DEFAULT_ROTATION;
|
||||
_glowLevel = DEFAULT_GLOW_LEVEL;
|
||||
_localRenderAlpha = DEFAULT_LOCAL_RENDER_ALPHA;
|
||||
_mass = DEFAULT_MASS;
|
||||
_velocity = DEFAULT_VELOCITY;
|
||||
_gravity = DEFAULT_GRAVITY;
|
||||
_damping = DEFAULT_DAMPING;
|
||||
_lifetime = DEFAULT_LIFETIME;
|
||||
_script = DEFAULT_SCRIPT;
|
||||
_registrationPoint = DEFAULT_REGISTRATION_POINT;
|
||||
_angularVelocity = DEFAULT_ANGULAR_VELOCITY;
|
||||
_angularDamping = DEFAULT_ANGULAR_DAMPING;
|
||||
_visible = DEFAULT_VISIBLE;
|
||||
_ignoreForCollisions = DEFAULT_IGNORE_FOR_COLLISIONS;
|
||||
_collisionsWillMove = DEFAULT_COLLISIONS_WILL_MOVE;
|
||||
_locked = DEFAULT_LOCKED;
|
||||
_userData = DEFAULT_USER_DATA;
|
||||
_position = ENTITY_ITEM_ZERO_VEC3;
|
||||
_dimensions = ENTITY_ITEM_DEFAULT_DIMENSIONS;
|
||||
_rotation = ENTITY_ITEM_DEFAULT_ROTATION;
|
||||
_glowLevel = ENTITY_ITEM_DEFAULT_GLOW_LEVEL;
|
||||
_localRenderAlpha = ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA;
|
||||
_mass = ENTITY_ITEM_DEFAULT_MASS;
|
||||
_velocity = ENTITY_ITEM_DEFAULT_VELOCITY;
|
||||
_gravity = ENTITY_ITEM_DEFAULT_GRAVITY;
|
||||
_damping = ENTITY_ITEM_DEFAULT_DAMPING;
|
||||
_lifetime = ENTITY_ITEM_DEFAULT_LIFETIME;
|
||||
_script = ENTITY_ITEM_DEFAULT_SCRIPT;
|
||||
_registrationPoint = ENTITY_ITEM_DEFAULT_REGISTRATION_POINT;
|
||||
_angularVelocity = ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY;
|
||||
_angularDamping = ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING;
|
||||
_visible = ENTITY_ITEM_DEFAULT_VISIBLE;
|
||||
_ignoreForCollisions = ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS;
|
||||
_collisionsWillMove = ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE;
|
||||
_locked = ENTITY_ITEM_DEFAULT_LOCKED;
|
||||
_userData = ENTITY_ITEM_DEFAULT_USER_DATA;
|
||||
|
||||
recalculateCollisionShape();
|
||||
}
|
||||
|
@ -555,6 +555,8 @@ void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, s
|
|||
}
|
||||
}
|
||||
|
||||
const float ENTITY_ITEM_EPSILON_VELOCITY_LENGTH = 0.001f / (float)TREE_SCALE;
|
||||
|
||||
// TODO: we probably want to change this to make "down" be the direction of the entity's gravity vector
|
||||
// for now, this is always true DOWN even if entity has non-down gravity.
|
||||
// TODO: the old code had "&& _velocity.y >= -EPSILON && _velocity.y <= EPSILON" --- what was I thinking?
|
||||
|
@ -562,7 +564,7 @@ bool EntityItem::isRestingOnSurface() const {
|
|||
glm::vec3 downwardVelocity = glm::vec3(0.0f, _velocity.y, 0.0f);
|
||||
|
||||
return _position.y <= getDistanceToBottomOfEntity()
|
||||
&& (glm::length(downwardVelocity) <= EPSILON_VELOCITY_LENGTH)
|
||||
&& (glm::length(downwardVelocity) <= ENTITY_ITEM_EPSILON_VELOCITY_LENGTH)
|
||||
&& _gravity.y < 0.0f;
|
||||
}
|
||||
|
||||
|
@ -639,7 +641,7 @@ void EntityItem::simulate(const quint64& now) {
|
|||
|
||||
const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.1f; //
|
||||
if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) {
|
||||
setAngularVelocity(NO_ANGULAR_VELOCITY);
|
||||
setAngularVelocity(ENTITY_ITEM_ZERO_VEC3);
|
||||
} else {
|
||||
// NOTE: angularSpeed is currently in degrees/sec!!!
|
||||
// TODO: Andrew to convert to radians/sec
|
||||
|
@ -668,7 +670,7 @@ void EntityItem::simulate(const quint64& now) {
|
|||
qDebug() << " damping:" << _damping;
|
||||
qDebug() << " velocity AFTER dampingResistance:" << velocity;
|
||||
qDebug() << " glm::length(velocity):" << glm::length(velocity);
|
||||
qDebug() << " EPSILON_VELOCITY_LENGTH:" << EPSILON_VELOCITY_LENGTH;
|
||||
qDebug() << " velocityEspilon :" << ENTITY_ITEM_EPSILON_VELOCITY_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -696,8 +698,8 @@ void EntityItem::simulate(const quint64& now) {
|
|||
|
||||
#ifndef USE_BULLET_PHYSICS
|
||||
// if we've slowed considerably, then just stop moving, but only if no BULLET
|
||||
if (glm::length(velocity) <= EPSILON_VELOCITY_LENGTH) {
|
||||
velocity = NO_VELOCITY;
|
||||
if (glm::length(velocity) <= ENTITY_ITEM_EPSILON_VELOCITY_LENGTH) {
|
||||
velocity = ENTITY_ITEM_ZERO_VEC3;
|
||||
}
|
||||
#endif // !USE_BULLET_PHYSICS
|
||||
|
||||
|
@ -720,8 +722,8 @@ void EntityItem::simulate(const quint64& now) {
|
|||
// When Bullet is available we assume that it will tell us when velocities go to zero...
|
||||
#else // !USE_BULLET_PHYSICS
|
||||
// ... otherwise we help things come to rest by clamping small velocities.
|
||||
if (glm::length(velocity) <= EPSILON_VELOCITY_LENGTH) {
|
||||
velocity = NO_VELOCITY;
|
||||
if (glm::length(velocity) <= ENTITY_ITEM_EPSILON_VELOCITY_LENGTH) {
|
||||
velocity = ENTITY_ITEM_ZERO_VEC3;
|
||||
}
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
|
||||
|
@ -909,7 +911,7 @@ AACube EntityItem::getMinimumAACube() const {
|
|||
// _position represents the position of the registration point.
|
||||
glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint;
|
||||
|
||||
glm::vec3 unrotatedMinRelativeToEntity = glm::vec3(0.0f, 0.0f, 0.0f) - (_dimensions * _registrationPoint);
|
||||
glm::vec3 unrotatedMinRelativeToEntity = - (_dimensions * _registrationPoint);
|
||||
glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder;
|
||||
Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
|
||||
Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation());
|
||||
|
@ -934,7 +936,7 @@ AABox EntityItem::getAABox() const {
|
|||
// _position represents the position of the registration point.
|
||||
glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint;
|
||||
|
||||
glm::vec3 unrotatedMinRelativeToEntity = glm::vec3(0.0f, 0.0f, 0.0f) - (_dimensions * _registrationPoint);
|
||||
glm::vec3 unrotatedMinRelativeToEntity = - (_dimensions * _registrationPoint);
|
||||
glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder;
|
||||
Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
|
||||
Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation());
|
||||
|
@ -998,7 +1000,7 @@ void EntityItem::recalculateCollisionShape() {
|
|||
const float MIN_POSITION_DELTA = 0.0001f;
|
||||
const float MIN_ALIGNMENT_DOT = 0.9999f;
|
||||
const float MIN_MASS_DELTA = 0.001f;
|
||||
const float MIN_VELOCITY_DELTA = 0.025f;
|
||||
const float MIN_VELOCITY_DELTA = 0.01f;
|
||||
const float MIN_DAMPING_DELTA = 0.001f;
|
||||
const float MIN_GRAVITY_DELTA = 0.001f;
|
||||
const float MIN_SPIN_DELTA = 0.0003f;
|
||||
|
@ -1055,7 +1057,7 @@ void EntityItem::updateMass(float value) {
|
|||
void EntityItem::updateVelocity(const glm::vec3& value) {
|
||||
if (glm::distance(_velocity, value) * (float)TREE_SCALE > MIN_VELOCITY_DELTA) {
|
||||
if (glm::length(value) * (float)TREE_SCALE < MIN_VELOCITY_DELTA) {
|
||||
_velocity = glm::vec3(0.0f);
|
||||
_velocity = ENTITY_ITEM_ZERO_VEC3;
|
||||
} else {
|
||||
_velocity = value;
|
||||
}
|
||||
|
@ -1067,7 +1069,7 @@ void EntityItem::updateVelocityInMeters(const glm::vec3& value) {
|
|||
glm::vec3 velocity = value / (float) TREE_SCALE;
|
||||
if (glm::distance(_velocity, velocity) * (float)TREE_SCALE > MIN_VELOCITY_DELTA) {
|
||||
if (glm::length(value) < MIN_VELOCITY_DELTA) {
|
||||
_velocity = glm::vec3(0.0f);
|
||||
_velocity = ENTITY_ITEM_ZERO_VEC3;
|
||||
} else {
|
||||
_velocity = velocity;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "EntityItemID.h"
|
||||
#include "EntityItemProperties.h"
|
||||
#include "EntityItemPropertiesDefaults.h"
|
||||
#include "EntityTypes.h"
|
||||
|
||||
class EntityTree;
|
||||
|
@ -35,30 +36,6 @@ 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) / (float)TREE_SCALE;
|
||||
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
|
||||
|
@ -201,13 +178,13 @@ public:
|
|||
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; }
|
||||
bool hasVelocity() const { return _velocity != ENTITY_ITEM_ZERO_VEC3; }
|
||||
|
||||
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
|
||||
void setGravityInMeters(const glm::vec3& value) { _gravity = value / (float) TREE_SCALE; } /// gravity in meters
|
||||
bool hasGravity() const { return _gravity != NO_GRAVITY; }
|
||||
bool hasGravity() const { return _gravity != ENTITY_ITEM_ZERO_VEC3; }
|
||||
|
||||
// TODO: this should eventually be updated to support resting on collisions with other surfaces
|
||||
bool isRestingOnSurface() const;
|
||||
|
@ -220,10 +197,10 @@ public:
|
|||
void setLifetime(float value) { _lifetime = value; } /// set the lifetime in seconds for the entity
|
||||
|
||||
/// is this entity immortal, in that it has no lifetime set, and will exist until manually deleted
|
||||
bool isImmortal() const { return _lifetime == IMMORTAL; }
|
||||
bool isImmortal() const { return _lifetime == ENTITY_ITEM_IMMORTAL_LIFETIME; }
|
||||
|
||||
/// is this entity mortal, in that it has a lifetime set, and will automatically be deleted when that lifetime expires
|
||||
bool isMortal() const { return _lifetime != IMMORTAL; }
|
||||
bool isMortal() const { return _lifetime != ENTITY_ITEM_IMMORTAL_LIFETIME; }
|
||||
|
||||
/// age of this entity in seconds
|
||||
float getAge() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; }
|
||||
|
@ -247,7 +224,7 @@ public:
|
|||
|
||||
const glm::vec3& getAngularVelocity() const { return _angularVelocity; }
|
||||
void setAngularVelocity(const glm::vec3& value) { _angularVelocity = value; }
|
||||
bool hasAngularVelocity() const { return _angularVelocity != NO_ANGULAR_VELOCITY; }
|
||||
bool hasAngularVelocity() const { return _angularVelocity != ENTITY_ITEM_ZERO_VEC3; }
|
||||
|
||||
float getAngularDamping() const { return _angularDamping; }
|
||||
void setAngularDamping(float value) { _angularDamping = value; }
|
||||
|
|
|
@ -19,32 +19,34 @@
|
|||
|
||||
#include "EntityItem.h"
|
||||
#include "EntityItemProperties.h"
|
||||
#include "EntityItemPropertiesDefaults.h"
|
||||
#include "ModelEntityItem.h"
|
||||
#include "TextEntityItem.h"
|
||||
|
||||
|
||||
EntityItemProperties::EntityItemProperties() :
|
||||
|
||||
CONSTRUCT_PROPERTY(visible, DEFAULT_VISIBLE),
|
||||
CONSTRUCT_PROPERTY(visible, ENTITY_ITEM_DEFAULT_VISIBLE),
|
||||
CONSTRUCT_PROPERTY(position, 0),
|
||||
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(dimensions, ENTITY_ITEM_DEFAULT_DIMENSIONS),
|
||||
CONSTRUCT_PROPERTY(rotation, ENTITY_ITEM_DEFAULT_ROTATION),
|
||||
CONSTRUCT_PROPERTY(mass, ENTITY_ITEM_DEFAULT_MASS),
|
||||
CONSTRUCT_PROPERTY(velocity, ENTITY_ITEM_DEFAULT_VELOCITY),
|
||||
CONSTRUCT_PROPERTY(gravity, ENTITY_ITEM_DEFAULT_GRAVITY),
|
||||
CONSTRUCT_PROPERTY(damping, ENTITY_ITEM_DEFAULT_DAMPING),
|
||||
CONSTRUCT_PROPERTY(lifetime, ENTITY_ITEM_DEFAULT_LIFETIME),
|
||||
CONSTRUCT_PROPERTY(script, ENTITY_ITEM_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, 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(registrationPoint, ENTITY_ITEM_DEFAULT_REGISTRATION_POINT),
|
||||
CONSTRUCT_PROPERTY(angularVelocity, ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY),
|
||||
CONSTRUCT_PROPERTY(angularDamping, ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING),
|
||||
CONSTRUCT_PROPERTY(ignoreForCollisions, ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS),
|
||||
CONSTRUCT_PROPERTY(collisionsWillMove, ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE),
|
||||
CONSTRUCT_PROPERTY(isSpotlight, false),
|
||||
CONSTRUCT_PROPERTY(diffuseColor, ),
|
||||
CONSTRUCT_PROPERTY(ambientColor, ),
|
||||
|
@ -54,10 +56,10 @@ EntityItemProperties::EntityItemProperties() :
|
|||
CONSTRUCT_PROPERTY(quadraticAttenuation, 0.0f),
|
||||
CONSTRUCT_PROPERTY(exponent, 0.0f),
|
||||
CONSTRUCT_PROPERTY(cutoff, PI),
|
||||
CONSTRUCT_PROPERTY(locked, false),
|
||||
CONSTRUCT_PROPERTY(locked, ENTITY_ITEM_DEFAULT_LOCKED),
|
||||
CONSTRUCT_PROPERTY(textures, ""),
|
||||
CONSTRUCT_PROPERTY(animationSettings, ""),
|
||||
CONSTRUCT_PROPERTY(userData, DEFAULT_USER_DATA),
|
||||
CONSTRUCT_PROPERTY(userData, ENTITY_ITEM_DEFAULT_USER_DATA),
|
||||
CONSTRUCT_PROPERTY(text, TextEntityItem::DEFAULT_TEXT),
|
||||
CONSTRUCT_PROPERTY(lineHeight, TextEntityItem::DEFAULT_LINE_HEIGHT),
|
||||
CONSTRUCT_PROPERTY(textColor, TextEntityItem::DEFAULT_TEXT_COLOR),
|
||||
|
@ -858,7 +860,7 @@ AABox EntityItemProperties::getAABoxInMeters() const {
|
|||
// _position represents the position of the registration point.
|
||||
glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint;
|
||||
|
||||
glm::vec3 unrotatedMinRelativeToEntity = glm::vec3(0.0f, 0.0f, 0.0f) - (_dimensions * _registrationPoint);
|
||||
glm::vec3 unrotatedMinRelativeToEntity = - (_dimensions * _registrationPoint);
|
||||
glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder;
|
||||
Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
|
||||
Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation());
|
||||
|
|
51
libraries/entities/src/EntityItemPropertiesDefaults.h
Normal file
51
libraries/entities/src/EntityItemPropertiesDefaults.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
//
|
||||
// EntityItemPropertiesDefaults.h
|
||||
// libraries/entities/src
|
||||
//
|
||||
// Created by Andrew Meadows on 2015.01.12
|
||||
// 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_EntityItemPropertiesDefaults_h
|
||||
#define hifi_EntityItemPropertiesDefaults_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
// There is a minor performance gain when comparing/copying an existing glm::vec3 rather than
|
||||
// creating a new one on the stack so we declare the ZERO_VEC3 constant as an optimization.
|
||||
const glm::vec3 ENTITY_ITEM_ZERO_VEC3(0.0f);
|
||||
|
||||
const glm::vec3 REGULAR_GRAVITY = glm::vec3(0, -9.8f / (float)TREE_SCALE, 0);
|
||||
|
||||
const bool ENTITY_ITEM_DEFAULT_LOCKED = false;
|
||||
const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString("");
|
||||
|
||||
const float ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA = 1.0f;
|
||||
const float ENTITY_ITEM_DEFAULT_GLOW_LEVEL = 0.0f;
|
||||
const bool ENTITY_ITEM_DEFAULT_VISIBLE = true;
|
||||
|
||||
const QString ENTITY_ITEM_DEFAULT_SCRIPT = QString("");
|
||||
const glm::vec3 ENTITY_ITEM_DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f, 0.5f, 0.5f); // center
|
||||
|
||||
const float ENTITY_ITEM_IMMORTAL_LIFETIME = -1.0f; /// special lifetime which means the entity lives for ever
|
||||
const float ENTITY_ITEM_DEFAULT_LIFETIME = ENTITY_ITEM_IMMORTAL_LIFETIME;
|
||||
|
||||
const glm::quat ENTITY_ITEM_DEFAULT_ROTATION;
|
||||
const glm::vec3 ENTITY_ITEM_DEFAULT_DIMENSIONS = glm::vec3(0.1f) / (float)TREE_SCALE;
|
||||
const float ENTITY_ITEM_DEFAULT_MASS = 1.0f;
|
||||
|
||||
const glm::vec3 ENTITY_ITEM_DEFAULT_VELOCITY = ENTITY_ITEM_ZERO_VEC3;
|
||||
const glm::vec3 ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY = ENTITY_ITEM_ZERO_VEC3;
|
||||
const glm::vec3 ENTITY_ITEM_DEFAULT_GRAVITY = ENTITY_ITEM_ZERO_VEC3;
|
||||
const float ENTITY_ITEM_DEFAULT_DAMPING = 0.39347f; // approx timescale = 2.0 sec (see damping timescale formula in header)
|
||||
const float ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING = 0.39347f; // approx timescale = 2.0 sec (see damping timescale formula in header)
|
||||
|
||||
const bool ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS = false;
|
||||
const bool ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE = false;
|
||||
|
||||
#endif // hifi_EntityItemPropertiesDefaults_h
|
|
@ -753,6 +753,7 @@ public:
|
|||
float shininess;
|
||||
float opacity;
|
||||
QString id;
|
||||
model::MaterialPointer _material;
|
||||
};
|
||||
|
||||
class Cluster {
|
||||
|
@ -1715,6 +1716,14 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping,
|
|||
#endif
|
||||
}
|
||||
material.id = getID(object.properties);
|
||||
|
||||
material._material = model::MaterialPointer(new model::Material());
|
||||
material._material->setEmissive(material.emissive);
|
||||
material._material->setDiffuse(material.diffuse);
|
||||
material._material->setSpecular(material.specular);
|
||||
material._material->setShininess(material.shininess);
|
||||
material._material->setOpacity(material.opacity);
|
||||
|
||||
materials.insert(material.id, material);
|
||||
|
||||
} else if (object.name == "NodeAttribute") {
|
||||
|
@ -2138,6 +2147,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping,
|
|||
for (int j = 0; j < extracted.partMaterialTextures.size(); j++) {
|
||||
if (extracted.partMaterialTextures.at(j).first == materialIndex) {
|
||||
FBXMeshPart& part = extracted.mesh.parts[j];
|
||||
|
||||
part._material = material._material;
|
||||
part.diffuseColor = material.diffuse;
|
||||
part.specularColor = material.specular;
|
||||
part.emissiveColor = material.emissive;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -20,11 +20,12 @@
|
|||
|
||||
#include "ResourceCache.h"
|
||||
|
||||
#define clamp(x, min, max) (((x) < (min)) ? (min) :\
|
||||
(((x) > (max)) ? (max) :\
|
||||
(x)))
|
||||
|
||||
ResourceCache::ResourceCache(QObject* parent) :
|
||||
QObject(parent),
|
||||
_lastLRUKey(0)
|
||||
{
|
||||
|
||||
QObject(parent) {
|
||||
}
|
||||
|
||||
ResourceCache::~ResourceCache() {
|
||||
|
@ -32,7 +33,7 @@ ResourceCache::~ResourceCache() {
|
|||
// list on destruction, so keep clearing until there are no references left
|
||||
while (!_unusedResources.isEmpty()) {
|
||||
foreach (const QSharedPointer<Resource>& resource, _unusedResources) {
|
||||
resource->setCache(NULL);
|
||||
resource->setCache(nullptr);
|
||||
}
|
||||
_unusedResources.clear();
|
||||
}
|
||||
|
@ -72,37 +73,40 @@ QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl&
|
|||
return resource;
|
||||
}
|
||||
|
||||
void ResourceCache::setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize) {
|
||||
_unusedResourcesMaxSize = clamp(unusedResourcesMaxSize, MIN_UNUSED_MAX_SIZE, MAX_UNUSED_MAX_SIZE);
|
||||
reserveUnusedResource(0);
|
||||
}
|
||||
|
||||
void ResourceCache::addUnusedResource(const QSharedPointer<Resource>& 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 &&
|
||||
!_unusedResources.empty()) {
|
||||
// unload the oldest resource
|
||||
QMap<int, QSharedPointer<Resource> >::iterator it = _unusedResources.begin();
|
||||
|
||||
_unusedResourcesTotalBytes -= 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());
|
||||
|
||||
|
||||
if (_unusedResources.size() > RETAINED_RESOURCE_COUNT) {
|
||||
// unload the oldest resource
|
||||
QMap<int, QSharedPointer<Resource> >::iterator it = _unusedResources.begin();
|
||||
it.value()->setCache(NULL);
|
||||
_unusedResources.erase(it);
|
||||
}
|
||||
resource->setLRUKey(++_lastLRUKey);
|
||||
_unusedResources.insert(resource->getLRUKey(), resource);
|
||||
_unusedResourcesTotalBytes += resource->getBytesTotal();
|
||||
_unusedResourcesSize += resource->getBytesTotal();
|
||||
}
|
||||
|
||||
void ResourceCache::removeUnusedResource(const QSharedPointer<Resource>& resource) {
|
||||
if (_unusedResources.contains(resource->getLRUKey())) {
|
||||
_unusedResources.remove(resource->getLRUKey());
|
||||
_unusedResourcesTotalBytes -= resource->getBytesTotal();
|
||||
_unusedResourcesSize -= resource->getBytesTotal();
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceCache::reserveUnusedResource(qint64 resourceSize) {
|
||||
while (!_unusedResources.empty() &&
|
||||
_unusedResourcesSize + resourceSize > _unusedResourcesMaxSize) {
|
||||
// unload the oldest resource
|
||||
QMap<int, QSharedPointer<Resource> >::iterator it = _unusedResources.begin();
|
||||
|
||||
_unusedResourcesSize -= it.value()->getBytesTotal();
|
||||
it.value()->setCache(nullptr);
|
||||
_unusedResources.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,9 +154,7 @@ QList<Resource*> ResourceCache::_loadingRequests;
|
|||
|
||||
Resource::Resource(const QUrl& url, bool delayLoad) :
|
||||
_url(url),
|
||||
_request(url),
|
||||
_lruKey(0),
|
||||
_reply(NULL) {
|
||||
_request(url) {
|
||||
|
||||
init();
|
||||
|
||||
|
@ -168,6 +170,7 @@ Resource::~Resource() {
|
|||
if (_reply) {
|
||||
ResourceCache::requestCompleted(this);
|
||||
delete _reply;
|
||||
_reply = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,13 +216,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);
|
||||
|
@ -295,10 +298,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);
|
||||
|
@ -330,10 +333,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
|
||||
|
|
|
@ -27,6 +27,19 @@ class QTimer;
|
|||
|
||||
class Resource;
|
||||
|
||||
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 const qint64 DEFAULT_UNUSED_MAX_SIZE = 100 * BYTES_PER_MEGABYTES;
|
||||
#else
|
||||
static const qint64 DEFAULT_UNUSED_MAX_SIZE = 1024 * BYTES_PER_MEGABYTES;
|
||||
#endif
|
||||
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 {
|
||||
Q_OBJECT
|
||||
|
@ -34,6 +47,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<Resource*>& getLoadingRequests() { return _loadingRequests; }
|
||||
|
||||
|
@ -45,8 +61,8 @@ public:
|
|||
void refresh(const QUrl& url);
|
||||
|
||||
protected:
|
||||
|
||||
qint64 _unusedResourcesTotalBytes = 0;
|
||||
qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE;
|
||||
qint64 _unusedResourcesSize = 0;
|
||||
QMap<int, QSharedPointer<Resource> > _unusedResources;
|
||||
|
||||
/// Loads a resource from the specified URL.
|
||||
|
@ -62,16 +78,16 @@ protected:
|
|||
|
||||
void addUnusedResource(const QSharedPointer<Resource>& resource);
|
||||
void removeUnusedResource(const QSharedPointer<Resource>& resource);
|
||||
void reserveUnusedResource(qint64 resourceSize);
|
||||
|
||||
static void attemptRequest(Resource* resource);
|
||||
static void requestCompleted(Resource* resource);
|
||||
|
||||
private:
|
||||
|
||||
friend class Resource;
|
||||
|
||||
QHash<QUrl, QWeakPointer<Resource> > _resources;
|
||||
int _lastLRUKey;
|
||||
int _lastLRUKey = 0;
|
||||
|
||||
static int _requestLimit;
|
||||
static QList<QPointer<Resource> > _pendingRequests;
|
||||
|
@ -152,9 +168,9 @@ protected:
|
|||
|
||||
QUrl _url;
|
||||
QNetworkRequest _request;
|
||||
bool _startedLoading;
|
||||
bool _failedToLoad;
|
||||
bool _loaded;
|
||||
bool _startedLoading = false;
|
||||
bool _failedToLoad = false;
|
||||
bool _loaded = false;
|
||||
QHash<QPointer<QObject>, float> _loadPriorities;
|
||||
QWeakPointer<Resource> _self;
|
||||
QPointer<ResourceCache> _cache;
|
||||
|
@ -176,13 +192,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<QObject>& value, uint seed = 0);
|
||||
|
|
|
@ -9,10 +9,17 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <time.h>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QDirIterator>
|
||||
#include <QFile>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include <PerfStat.h>
|
||||
#include <SharedUtil.h>
|
||||
|
@ -20,30 +27,71 @@
|
|||
#include "OctreePersistThread.h"
|
||||
|
||||
const int OctreePersistThread::DEFAULT_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds
|
||||
const int OctreePersistThread::DEFAULT_BACKUP_INTERVAL = 1000 * 60 * 30; // every 30 minutes
|
||||
const QString OctreePersistThread::DEFAULT_BACKUP_EXTENSION_FORMAT(".backup.%N");
|
||||
const int OctreePersistThread::DEFAULT_MAX_BACKUP_VERSIONS = 5;
|
||||
|
||||
|
||||
OctreePersistThread::OctreePersistThread(Octree* tree, const QString& filename, int persistInterval,
|
||||
bool wantBackup, int backupInterval, const QString& backupExtensionFormat,
|
||||
int maxBackupVersions, bool debugTimestampNow) :
|
||||
bool wantBackup, const QJsonObject& settings, bool debugTimestampNow) :
|
||||
_tree(tree),
|
||||
_filename(filename),
|
||||
_backupExtensionFormat(backupExtensionFormat),
|
||||
_maxBackupVersions(maxBackupVersions),
|
||||
_persistInterval(persistInterval),
|
||||
_backupInterval(backupInterval),
|
||||
_initialLoadComplete(false),
|
||||
_loadTimeUSecs(0),
|
||||
_lastCheck(0),
|
||||
_lastBackup(0),
|
||||
_wantBackup(wantBackup),
|
||||
_debugTimestampNow(debugTimestampNow),
|
||||
_lastTimeDebug(0)
|
||||
{
|
||||
parseSettings(settings);
|
||||
}
|
||||
|
||||
void OctreePersistThread::parseSettings(const QJsonObject& settings) {
|
||||
if (settings["backups"].isArray()) {
|
||||
const QJsonArray& backupRules = settings["backups"].toArray();
|
||||
qDebug() << "BACKUP RULES:";
|
||||
|
||||
foreach (const QJsonValue& value, backupRules) {
|
||||
QJsonObject obj = value.toObject();
|
||||
qDebug() << " Name:" << obj["Name"].toString();
|
||||
qDebug() << " format:" << obj["format"].toString();
|
||||
qDebug() << " interval:" << obj["backupInterval"].toInt();
|
||||
qDebug() << " count:" << obj["maxBackupVersions"].toInt();
|
||||
|
||||
BackupRule newRule = { obj["Name"].toString(), obj["backupInterval"].toInt(),
|
||||
obj["format"].toString(), obj["maxBackupVersions"].toInt(), 0};
|
||||
|
||||
newRule.lastBackup = getMostRecentBackupTimeInUsecs(obj["format"].toString());
|
||||
|
||||
if (newRule.lastBackup > 0) {
|
||||
quint64 now = usecTimestampNow();
|
||||
quint64 sinceLastBackup = now - newRule.lastBackup;
|
||||
qDebug() << " lastBackup:" << qPrintable(formatUsecTime(sinceLastBackup)) << "ago";
|
||||
} else {
|
||||
qDebug() << " lastBackup: NEVER";
|
||||
}
|
||||
|
||||
_backupRules << newRule;
|
||||
}
|
||||
} else {
|
||||
qDebug() << "BACKUP RULES: NONE";
|
||||
}
|
||||
}
|
||||
|
||||
quint64 OctreePersistThread::getMostRecentBackupTimeInUsecs(const QString& format) {
|
||||
|
||||
quint64 mostRecentBackupInUsecs = 0;
|
||||
|
||||
QString mostRecentBackupFileName;
|
||||
QDateTime mostRecentBackupTime;
|
||||
|
||||
bool recentBackup = getMostRecentBackup(format, mostRecentBackupFileName, mostRecentBackupTime);
|
||||
|
||||
if (recentBackup) {
|
||||
mostRecentBackupInUsecs = mostRecentBackupTime.toMSecsSinceEpoch() * USECS_PER_MSEC;
|
||||
}
|
||||
|
||||
return mostRecentBackupInUsecs;
|
||||
}
|
||||
|
||||
|
||||
bool OctreePersistThread::process() {
|
||||
|
||||
if (!_initialLoadComplete) {
|
||||
|
@ -55,6 +103,25 @@ bool OctreePersistThread::process() {
|
|||
_tree->lockForWrite();
|
||||
{
|
||||
PerformanceWarning warn(true, "Loading Octree File", true);
|
||||
|
||||
// First check to make sure "lock" file doesn't exist. If it does exist, then
|
||||
// our last save crashed during the save, and we want to load our most recent backup.
|
||||
QString lockFileName = _filename + ".lock";
|
||||
std::ifstream lockFile(qPrintable(lockFileName), std::ios::in|std::ios::binary|std::ios::ate);
|
||||
if(lockFile.is_open()) {
|
||||
qDebug() << "WARNING: Octree lock file detected at startup:" << lockFileName
|
||||
<< "-- Attempting to restore from previous backup file.";
|
||||
|
||||
// This is where we should attempt to find the most recent backup and restore from
|
||||
// that file as our persist file.
|
||||
restoreFromMostRecentBackup();
|
||||
|
||||
lockFile.close();
|
||||
qDebug() << "Loading Octree... lock file closed:" << lockFileName;
|
||||
remove(qPrintable(lockFileName));
|
||||
qDebug() << "Loading Octree... lock file removed:" << lockFileName;
|
||||
}
|
||||
|
||||
persistantFileRead = _tree->readFromSVOFile(_filename.toLocal8Bit().constData());
|
||||
_tree->pruneTree();
|
||||
}
|
||||
|
@ -85,7 +152,13 @@ bool OctreePersistThread::process() {
|
|||
}
|
||||
|
||||
_initialLoadComplete = true;
|
||||
_lastBackup = _lastCheck = usecTimestampNow(); // we just loaded, no need to save again
|
||||
|
||||
// Since we just loaded the persistent file, we can consider ourselves as having "just checked" for persistance.
|
||||
_lastCheck = usecTimestampNow(); // we just loaded, no need to save again
|
||||
|
||||
// This last persist time is not really used until the file is actually persisted. It is only
|
||||
// used in formatting the backup filename in cases of non-rolling backup names. However, we don't
|
||||
// want an uninitialized value for this, so we set it to the current time (startup of the server)
|
||||
time(&_lastPersistTime);
|
||||
|
||||
emit loadCompleted();
|
||||
|
@ -142,82 +215,180 @@ void OctreePersistThread::persist() {
|
|||
|
||||
backup(); // handle backup if requested
|
||||
|
||||
qDebug() << "saving Octree to file " << _filename << "...";
|
||||
_tree->writeToSVOFile(qPrintable(_filename));
|
||||
time(&_lastPersistTime);
|
||||
_tree->clearDirtyBit(); // tree is clean after saving
|
||||
qDebug() << "DONE saving Octree to file...";
|
||||
|
||||
// create our "lock" file to indicate we're saving.
|
||||
QString lockFileName = _filename + ".lock";
|
||||
std::ofstream lockFile(qPrintable(lockFileName), std::ios::out|std::ios::binary);
|
||||
if(lockFile.is_open()) {
|
||||
qDebug() << "saving Octree lock file created at:" << lockFileName;
|
||||
|
||||
qDebug() << "saving Octree to file " << _filename << "...";
|
||||
|
||||
_tree->writeToSVOFile(qPrintable(_filename));
|
||||
time(&_lastPersistTime);
|
||||
_tree->clearDirtyBit(); // tree is clean after saving
|
||||
qDebug() << "DONE saving Octree to file...";
|
||||
|
||||
lockFile.close();
|
||||
qDebug() << "saving Octree lock file closed:" << lockFileName;
|
||||
remove(qPrintable(lockFileName));
|
||||
qDebug() << "saving Octree lock file removed:" << lockFileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OctreePersistThread::rollOldBackupVersions() {
|
||||
if (!_backupExtensionFormat.contains("%N")) {
|
||||
return; // this backup extension format doesn't support rolling
|
||||
void OctreePersistThread::restoreFromMostRecentBackup() {
|
||||
qDebug() << "Restoring from most recent backup...";
|
||||
|
||||
QString mostRecentBackupFileName;
|
||||
QDateTime mostRecentBackupTime;
|
||||
|
||||
bool recentBackup = getMostRecentBackup(QString(""), mostRecentBackupFileName, mostRecentBackupTime);
|
||||
|
||||
// If we found a backup file, restore from that file.
|
||||
if (recentBackup) {
|
||||
qDebug() << "BEST backup file:" << mostRecentBackupFileName << " last modified:" << mostRecentBackupTime.toString();
|
||||
|
||||
qDebug() << "Removing old file:" << _filename;
|
||||
remove(qPrintable(_filename));
|
||||
|
||||
qDebug() << "Restoring backup file " << mostRecentBackupFileName << "...";
|
||||
bool result = QFile::copy(mostRecentBackupFileName, _filename);
|
||||
if (result) {
|
||||
qDebug() << "DONE restoring backup file " << mostRecentBackupFileName << "to" << _filename << "...";
|
||||
} else {
|
||||
qDebug() << "ERROR while restoring backup file " << mostRecentBackupFileName << "to" << _filename << "...";
|
||||
}
|
||||
} else {
|
||||
qDebug() << "NO BEST backup file found.";
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "Rolling old backup versions...";
|
||||
for(int n = _maxBackupVersions - 1; n > 0; n--) {
|
||||
QString backupExtensionN = _backupExtensionFormat;
|
||||
QString backupExtensionNplusOne = _backupExtensionFormat;
|
||||
backupExtensionN.replace(QString("%N"), QString::number(n));
|
||||
backupExtensionNplusOne.replace(QString("%N"), QString::number(n+1));
|
||||
|
||||
QString backupFilenameN = _filename + backupExtensionN;
|
||||
QString backupFilenameNplusOne = _filename + backupExtensionNplusOne;
|
||||
bool OctreePersistThread::getMostRecentBackup(const QString& format,
|
||||
QString& mostRecentBackupFileName, QDateTime& mostRecentBackupTime) {
|
||||
|
||||
QFile backupFileN(backupFilenameN);
|
||||
// Based on our backup file name, determine the path and file name pattern for backup files
|
||||
QFileInfo persistFileInfo(_filename);
|
||||
QString path = persistFileInfo.path();
|
||||
QString fileNamePart = persistFileInfo.fileName();
|
||||
|
||||
if (backupFileN.exists()) {
|
||||
qDebug() << "rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "...";
|
||||
int result = rename(qPrintable(backupFilenameN), qPrintable(backupFilenameNplusOne));
|
||||
if (result == 0) {
|
||||
qDebug() << "DONE rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "...";
|
||||
} else {
|
||||
qDebug() << "ERROR in rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "...";
|
||||
}
|
||||
QStringList filters;
|
||||
|
||||
if (format.isEmpty()) {
|
||||
// Create a file filter that will find all backup files of this extension format
|
||||
foreach(const BackupRule& rule, _backupRules) {
|
||||
QString backupExtension = rule.extensionFormat;
|
||||
backupExtension.replace(QRegExp("%."), "*");
|
||||
QString backupFileNamePart = fileNamePart + backupExtension;
|
||||
filters << backupFileNamePart;
|
||||
}
|
||||
} else {
|
||||
QString backupExtension = format;
|
||||
backupExtension.replace(QRegExp("%."), "*");
|
||||
QString backupFileNamePart = fileNamePart + backupExtension;
|
||||
filters << backupFileNamePart;
|
||||
}
|
||||
|
||||
bool bestBackupFound = false;
|
||||
QString bestBackupFile;
|
||||
QDateTime bestBackupFileTime;
|
||||
|
||||
// Iterate over all of the backup files in the persist location
|
||||
QDirIterator dirIterator(path, filters, QDir::Files|QDir::NoSymLinks, QDirIterator::NoIteratorFlags);
|
||||
while(dirIterator.hasNext()) {
|
||||
|
||||
dirIterator.next();
|
||||
QDateTime lastModified = dirIterator.fileInfo().lastModified();
|
||||
|
||||
// Based on last modified date, track the most recently modified file as the best backup
|
||||
if (lastModified > bestBackupFileTime) {
|
||||
bestBackupFound = true;
|
||||
bestBackupFile = dirIterator.filePath();
|
||||
bestBackupFileTime = lastModified;
|
||||
}
|
||||
}
|
||||
qDebug() << "Done rolling old backup versions...";
|
||||
|
||||
// If we found a backup then return the results
|
||||
if (bestBackupFound) {
|
||||
mostRecentBackupFileName = bestBackupFile;
|
||||
mostRecentBackupTime = bestBackupFileTime;
|
||||
}
|
||||
return bestBackupFound;
|
||||
}
|
||||
|
||||
void OctreePersistThread::rollOldBackupVersions(const BackupRule& rule) {
|
||||
|
||||
if (rule.extensionFormat.contains("%N")) {
|
||||
qDebug() << "Rolling old backup versions for rule" << rule.name << "...";
|
||||
for(int n = rule.maxBackupVersions - 1; n > 0; n--) {
|
||||
QString backupExtensionN = rule.extensionFormat;
|
||||
QString backupExtensionNplusOne = rule.extensionFormat;
|
||||
backupExtensionN.replace(QString("%N"), QString::number(n));
|
||||
backupExtensionNplusOne.replace(QString("%N"), QString::number(n+1));
|
||||
|
||||
QString backupFilenameN = _filename + backupExtensionN;
|
||||
QString backupFilenameNplusOne = _filename + backupExtensionNplusOne;
|
||||
|
||||
QFile backupFileN(backupFilenameN);
|
||||
|
||||
if (backupFileN.exists()) {
|
||||
qDebug() << "rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "...";
|
||||
int result = rename(qPrintable(backupFilenameN), qPrintable(backupFilenameNplusOne));
|
||||
if (result == 0) {
|
||||
qDebug() << "DONE rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "...";
|
||||
} else {
|
||||
qDebug() << "ERROR in rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "...";
|
||||
}
|
||||
}
|
||||
}
|
||||
qDebug() << "Done rolling old backup versions...";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OctreePersistThread::backup() {
|
||||
if (_wantBackup) {
|
||||
quint64 now = usecTimestampNow();
|
||||
quint64 sinceLastBackup = now - _lastBackup;
|
||||
quint64 MSECS_TO_USECS = 1000;
|
||||
quint64 intervalToBackup = _backupInterval * MSECS_TO_USECS;
|
||||
|
||||
if (sinceLastBackup > intervalToBackup) {
|
||||
qDebug() << "Time since last backup [" << sinceLastBackup << "] exceeds backup interval ["
|
||||
<< intervalToBackup << "] doing backup now...";
|
||||
for(int i = 0; i < _backupRules.count(); i++) {
|
||||
BackupRule& rule = _backupRules[i];
|
||||
|
||||
struct tm* localTime = localtime(&_lastPersistTime);
|
||||
quint64 sinceLastBackup = now - rule.lastBackup;
|
||||
|
||||
QString backupFileName;
|
||||
quint64 SECS_TO_USECS = 1000 * 1000;
|
||||
quint64 intervalToBackup = rule.interval * SECS_TO_USECS;
|
||||
|
||||
if (sinceLastBackup > intervalToBackup) {
|
||||
qDebug() << "Time since last backup [" << sinceLastBackup << "] for rule [" << rule.name
|
||||
<< "] exceeds backup interval [" << intervalToBackup << "] doing backup now...";
|
||||
|
||||
struct tm* localTime = localtime(&_lastPersistTime);
|
||||
|
||||
QString backupFileName;
|
||||
|
||||
// check to see if they asked for version rolling format
|
||||
if (_backupExtensionFormat.contains("%N")) {
|
||||
rollOldBackupVersions(); // rename all the old backup files accordingly
|
||||
QString backupExtension = _backupExtensionFormat;
|
||||
backupExtension.replace(QString("%N"), QString("1"));
|
||||
backupFileName = _filename + backupExtension;
|
||||
} else {
|
||||
char backupExtension[256];
|
||||
strftime(backupExtension, sizeof(backupExtension), qPrintable(_backupExtensionFormat), localTime);
|
||||
backupFileName = _filename + backupExtension;
|
||||
}
|
||||
// check to see if they asked for version rolling format
|
||||
if (rule.extensionFormat.contains("%N")) {
|
||||
rollOldBackupVersions(rule); // rename all the old backup files accordingly
|
||||
QString backupExtension = rule.extensionFormat;
|
||||
backupExtension.replace(QString("%N"), QString("1"));
|
||||
backupFileName = _filename + backupExtension;
|
||||
} else {
|
||||
char backupExtension[256];
|
||||
strftime(backupExtension, sizeof(backupExtension), qPrintable(rule.extensionFormat), localTime);
|
||||
backupFileName = _filename + backupExtension;
|
||||
}
|
||||
|
||||
|
||||
qDebug() << "backing up persist file " << _filename << "to" << backupFileName << "...";
|
||||
int result = rename(qPrintable(_filename), qPrintable(backupFileName));
|
||||
if (result == 0) {
|
||||
qDebug() << "DONE backing up persist file...";
|
||||
} else {
|
||||
qDebug() << "ERROR in backing up persist file...";
|
||||
}
|
||||
qDebug() << "backing up persist file " << _filename << "to" << backupFileName << "...";
|
||||
bool result = QFile::copy(_filename, backupFileName);
|
||||
if (result) {
|
||||
qDebug() << "DONE backing up persist file...";
|
||||
} else {
|
||||
qDebug() << "ERROR in backing up persist file...";
|
||||
}
|
||||
|
||||
_lastBackup = now;
|
||||
rule.lastBackup = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,15 +22,19 @@
|
|||
class OctreePersistThread : public GenericThread {
|
||||
Q_OBJECT
|
||||
public:
|
||||
class BackupRule {
|
||||
public:
|
||||
QString name;
|
||||
int interval;
|
||||
QString extensionFormat;
|
||||
int maxBackupVersions;
|
||||
quint64 lastBackup;
|
||||
};
|
||||
|
||||
static const int DEFAULT_PERSIST_INTERVAL;
|
||||
static const int DEFAULT_BACKUP_INTERVAL;
|
||||
static const QString DEFAULT_BACKUP_EXTENSION_FORMAT;
|
||||
static const int DEFAULT_MAX_BACKUP_VERSIONS;
|
||||
|
||||
OctreePersistThread(Octree* tree, const QString& filename, int persistInterval = DEFAULT_PERSIST_INTERVAL,
|
||||
bool wantBackup = false, int backupInterval = DEFAULT_BACKUP_INTERVAL,
|
||||
const QString& backupExtensionFormat = DEFAULT_BACKUP_EXTENSION_FORMAT,
|
||||
int maxBackupVersions = DEFAULT_MAX_BACKUP_VERSIONS,
|
||||
bool wantBackup = false, const QJsonObject& settings = QJsonObject(),
|
||||
bool debugTimestampNow = false);
|
||||
|
||||
bool isInitialLoadComplete() const { return _initialLoadComplete; }
|
||||
|
@ -47,21 +51,24 @@ protected:
|
|||
|
||||
void persist();
|
||||
void backup();
|
||||
void rollOldBackupVersions();
|
||||
void rollOldBackupVersions(const BackupRule& rule);
|
||||
void restoreFromMostRecentBackup();
|
||||
bool getMostRecentBackup(const QString& format, QString& mostRecentBackupFileName, QDateTime& mostRecentBackupTime);
|
||||
quint64 getMostRecentBackupTimeInUsecs(const QString& format);
|
||||
void parseSettings(const QJsonObject& settings);
|
||||
|
||||
private:
|
||||
Octree* _tree;
|
||||
QString _filename;
|
||||
QString _backupExtensionFormat;
|
||||
int _maxBackupVersions;
|
||||
int _persistInterval;
|
||||
int _backupInterval;
|
||||
bool _initialLoadComplete;
|
||||
|
||||
quint64 _loadTimeUSecs;
|
||||
quint64 _lastCheck;
|
||||
quint64 _lastBackup;
|
||||
bool _wantBackup;
|
||||
|
||||
time_t _lastPersistTime;
|
||||
quint64 _lastCheck;
|
||||
bool _wantBackup;
|
||||
QVector<BackupRule> _backupRules;
|
||||
|
||||
bool _debugTimestampNow;
|
||||
quint64 _lastTimeDebug;
|
||||
|
|
|
@ -79,21 +79,59 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
|
|||
}
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
|
||||
void EntityMotionState::applyVelocities() const {
|
||||
void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t frame) {
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
if (_body) {
|
||||
setVelocity(_entity->getVelocityInMeters());
|
||||
// DANGER! EntityItem stores angularVelocity in degrees/sec!!!
|
||||
setAngularVelocity(glm::radians(_entity->getAngularVelocity()));
|
||||
_body->setActivationState(ACTIVE_TAG);
|
||||
}
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
}
|
||||
if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) {
|
||||
if (flags & EntityItem::DIRTY_POSITION) {
|
||||
_sentPosition = _entity->getPositionInMeters() - ObjectMotionState::getWorldOffset();
|
||||
btTransform worldTrans;
|
||||
worldTrans.setOrigin(glmToBullet(_sentPosition));
|
||||
|
||||
void EntityMotionState::applyGravity() const {
|
||||
_sentRotation = _entity->getRotation();
|
||||
worldTrans.setRotation(glmToBullet(_sentRotation));
|
||||
|
||||
_body->setWorldTransform(worldTrans);
|
||||
}
|
||||
if (flags & EntityItem::DIRTY_VELOCITY) {
|
||||
updateObjectVelocities();
|
||||
}
|
||||
_sentFrame = frame;
|
||||
}
|
||||
|
||||
// TODO: entity support for friction and restitution
|
||||
//_restitution = _entity->getRestitution();
|
||||
_body->setRestitution(_restitution);
|
||||
//_friction = _entity->getFriction();
|
||||
_body->setFriction(_friction);
|
||||
|
||||
_linearDamping = _entity->getDamping();
|
||||
_angularDamping = _entity->getAngularDamping();
|
||||
_body->setDamping(_linearDamping, _angularDamping);
|
||||
|
||||
if (flags & EntityItem::DIRTY_MASS) {
|
||||
float mass = getMass();
|
||||
btVector3 inertia(0.0f, 0.0f, 0.0f);
|
||||
_body->getCollisionShape()->calculateLocalInertia(mass, inertia);
|
||||
_body->setMassProps(mass, inertia);
|
||||
_body->updateInertiaTensor();
|
||||
}
|
||||
_body->activate();
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
};
|
||||
|
||||
void EntityMotionState::updateObjectVelocities() {
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
if (_body) {
|
||||
setGravity(_entity->getGravityInMeters());
|
||||
_sentVelocity = _entity->getVelocityInMeters();
|
||||
setVelocity(_sentVelocity);
|
||||
|
||||
// DANGER! EntityItem stores angularVelocity in degrees/sec!!!
|
||||
_sentAngularVelocity = glm::radians(_entity->getAngularVelocity());
|
||||
setAngularVelocity(_sentAngularVelocity);
|
||||
|
||||
_sentAcceleration = _entity->getGravityInMeters();
|
||||
setGravity(_sentAcceleration);
|
||||
|
||||
_body->setActivationState(ACTIVE_TAG);
|
||||
}
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
|
@ -123,7 +161,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
|
|||
_sentAngularVelocity = bulletToGLM(_body->getAngularVelocity());
|
||||
|
||||
// if the speeds are very small we zero them out
|
||||
const float MINIMUM_EXTRAPOLATION_SPEED_SQUARED = 4.0e-6f; // 2mm/sec
|
||||
const float MINIMUM_EXTRAPOLATION_SPEED_SQUARED = 1.0e-4f; // 1cm/sec
|
||||
bool zeroSpeed = (glm::length2(_sentVelocity) < MINIMUM_EXTRAPOLATION_SPEED_SQUARED);
|
||||
if (zeroSpeed) {
|
||||
_sentVelocity = glm::vec3(0.0f);
|
||||
|
|
|
@ -54,8 +54,8 @@ public:
|
|||
#endif // USE_BULLET_PHYSICS
|
||||
|
||||
// these relay incoming values to the RigidBody
|
||||
void applyVelocities() const;
|
||||
void applyGravity() const;
|
||||
void updateObjectEasy(uint32_t flags, uint32_t frame);
|
||||
void updateObjectVelocities();
|
||||
|
||||
void computeShapeInfo(ShapeInfo& info);
|
||||
|
||||
|
|
|
@ -123,9 +123,9 @@ bool ObjectMotionState::doesNotNeedToSendUpdate() const {
|
|||
|
||||
const float FIXED_SUBSTEP = 1.0f / 60.0f;
|
||||
|
||||
bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame, float subStepRemainder) {
|
||||
bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame) {
|
||||
assert(_body);
|
||||
float dt = (float)(simulationFrame - _sentFrame) * FIXED_SUBSTEP + subStepRemainder;
|
||||
float dt = (float)(simulationFrame - _sentFrame) * FIXED_SUBSTEP;
|
||||
_sentFrame = simulationFrame;
|
||||
bool isActive = _body->isActive();
|
||||
|
||||
|
@ -183,7 +183,7 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame, float subStep
|
|||
}
|
||||
const float MIN_ROTATION_DOT = 0.98f;
|
||||
glm::quat actualRotation = bulletToGLM(worldTrans.getRotation());
|
||||
return (glm::dot(actualRotation, _sentRotation) < MIN_ROTATION_DOT);
|
||||
return (fabsf(glm::dot(actualRotation, _sentRotation)) < MIN_ROTATION_DOT);
|
||||
}
|
||||
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
|
|
|
@ -56,8 +56,9 @@ public:
|
|||
ObjectMotionState();
|
||||
~ObjectMotionState();
|
||||
|
||||
virtual void applyVelocities() const = 0;
|
||||
virtual void applyGravity() const = 0;
|
||||
// An EASY update does not require the object to be removed and then reinserted into the PhysicsEngine
|
||||
virtual void updateObjectEasy(uint32_t flags, uint32_t frame) = 0;
|
||||
virtual void updateObjectVelocities() = 0;
|
||||
|
||||
virtual void computeShapeInfo(ShapeInfo& info) = 0;
|
||||
|
||||
|
@ -84,7 +85,7 @@ public:
|
|||
void clearOutgoingPacketFlags(uint32_t flags) { _outgoingPacketFlags &= ~flags; }
|
||||
|
||||
bool doesNotNeedToSendUpdate() const;
|
||||
virtual bool shouldSendUpdate(uint32_t simulationFrame, float subStepRemainder);
|
||||
virtual bool shouldSendUpdate(uint32_t simulationFrame);
|
||||
virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame) = 0;
|
||||
|
||||
virtual MotionType computeMotionType() const = 0;
|
||||
|
|
|
@ -41,14 +41,12 @@ void PhysicsEngine::updateEntitiesInternal(const quint64& now) {
|
|||
|
||||
// this is step (4)
|
||||
QSet<ObjectMotionState*>::iterator stateItr = _outgoingPackets.begin();
|
||||
uint32_t frame = getFrameCount();
|
||||
float subStepRemainder = getSubStepRemainder();
|
||||
while (stateItr != _outgoingPackets.end()) {
|
||||
ObjectMotionState* state = *stateItr;
|
||||
if (state->doesNotNeedToSendUpdate()) {
|
||||
stateItr = _outgoingPackets.erase(stateItr);
|
||||
} else if (state->shouldSendUpdate(frame, subStepRemainder)) {
|
||||
state->sendUpdate(_entityPacketSender, frame);
|
||||
} else if (state->shouldSendUpdate(_frameCount)) {
|
||||
state->sendUpdate(_entityPacketSender, _frameCount);
|
||||
++stateItr;
|
||||
} else {
|
||||
++stateItr;
|
||||
|
@ -140,7 +138,8 @@ void PhysicsEngine::relayIncomingChangesToSimulation() {
|
|||
updateObjectHard(body, motionState, flags);
|
||||
} else if (flags) {
|
||||
// an EASY update does NOT require that the body be pulled out of physics engine
|
||||
updateObjectEasy(body, motionState, flags);
|
||||
// hence the MotionState has all the knowledge and authority to perform the update.
|
||||
motionState->updateObjectEasy(flags, _frameCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,8 +268,12 @@ bool PhysicsEngine::addObject(ObjectMotionState* motionState) {
|
|||
body = new btRigidBody(mass, motionState, shape, inertia);
|
||||
body->updateInertiaTensor();
|
||||
motionState->_body = body;
|
||||
motionState->applyVelocities();
|
||||
motionState->applyGravity();
|
||||
motionState->updateObjectVelocities();
|
||||
// NOTE: Bullet will deactivate any object whose velocity is below these thresholds for longer than 2 seconds.
|
||||
// (the 2 seconds is determined by: static btRigidBody::gDeactivationTime
|
||||
const float LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec
|
||||
const float ANGULAR_VELOCITY_THRESHOLD = 0.087266f; // ~5 deg/sec
|
||||
body->setSleepingThresholds(LINEAR_VELOCITY_THRESHOLD, ANGULAR_VELOCITY_THRESHOLD);
|
||||
break;
|
||||
}
|
||||
case MOTION_TYPE_STATIC:
|
||||
|
@ -334,7 +337,7 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
|
|||
}
|
||||
bool easyUpdate = flags & EASY_DIRTY_PHYSICS_FLAGS;
|
||||
if (easyUpdate) {
|
||||
updateObjectEasy(body, motionState, flags);
|
||||
motionState->updateObjectEasy(flags, _frameCount);
|
||||
}
|
||||
|
||||
// update the motion parameters
|
||||
|
@ -385,31 +388,4 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
|
|||
body->activate();
|
||||
}
|
||||
|
||||
// private
|
||||
void PhysicsEngine::updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) {
|
||||
if (flags & EntityItem::DIRTY_POSITION) {
|
||||
btTransform transform;
|
||||
motionState->getWorldTransform(transform);
|
||||
body->setWorldTransform(transform);
|
||||
}
|
||||
if (flags & EntityItem::DIRTY_VELOCITY) {
|
||||
motionState->applyVelocities();
|
||||
motionState->applyGravity();
|
||||
}
|
||||
body->setRestitution(motionState->_restitution);
|
||||
body->setFriction(motionState->_friction);
|
||||
body->setDamping(motionState->_linearDamping, motionState->_angularDamping);
|
||||
|
||||
if (flags & EntityItem::DIRTY_MASS) {
|
||||
float mass = motionState->getMass();
|
||||
btVector3 inertia(0.0f, 0.0f, 0.0f);
|
||||
body->getCollisionShape()->calculateLocalInertia(mass, inertia);
|
||||
body->setMassProps(mass, inertia);
|
||||
body->updateInertiaTensor();
|
||||
}
|
||||
body->activate();
|
||||
|
||||
// TODO: support collision groups
|
||||
};
|
||||
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
|
|
|
@ -71,12 +71,6 @@ public:
|
|||
/// \return number of simulation frames the physics engine has taken
|
||||
uint32_t getFrameCount() const { return _frameCount; }
|
||||
|
||||
/// \return substep remainder used for Bullet MotionState extrapolation
|
||||
// Bullet will extrapolate the positions provided to MotionState::setWorldTransform() in an effort to provide
|
||||
// smoother visible motion when the render frame rate does not match that of the simulation loop. We provide
|
||||
// access to this fraction for improved filtering of update packets to interested parties.
|
||||
float getSubStepRemainder() { return _dynamicsWorld->getLocalTimeAccumulation(); }
|
||||
|
||||
protected:
|
||||
void updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags);
|
||||
void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags);
|
||||
|
|
65
libraries/render-utils/src/DeferredBuffer.slh
Executable file
65
libraries/render-utils/src/DeferredBuffer.slh
Executable file
|
@ -0,0 +1,65 @@
|
|||
<!
|
||||
// DeferredBuffer.slh
|
||||
// libraries/render-utils/src
|
||||
//
|
||||
// Created by Sam Gateau on 1/12/15.
|
||||
// Copyright 2013 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
|
||||
!>
|
||||
<@if not DEFERRED_BUFFER_SLH@>
|
||||
<@def DEFERRED_BUFFER_SLH@>
|
||||
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
// the normal texture
|
||||
uniform sampler2D normalMap;
|
||||
|
||||
// the specular texture
|
||||
uniform sampler2D specularMap;
|
||||
|
||||
// the depth texture
|
||||
uniform sampler2D depthMap;
|
||||
|
||||
// the distance to the near clip plane
|
||||
uniform float near;
|
||||
|
||||
// scale factor for depth: (far - near) / far
|
||||
uniform float depthScale;
|
||||
|
||||
// offset for depth texture coordinates
|
||||
uniform vec2 depthTexCoordOffset;
|
||||
|
||||
// scale for depth texture coordinates
|
||||
uniform vec2 depthTexCoordScale;
|
||||
|
||||
struct DeferredFragment {
|
||||
float depthVal;
|
||||
vec4 normalVal;
|
||||
vec4 diffuseVal;
|
||||
vec4 specularVal;
|
||||
vec4 position;
|
||||
vec3 normal;
|
||||
};
|
||||
|
||||
DeferredFragment unpackDeferredFragment(vec2 texcoord) {
|
||||
DeferredFragment frag;
|
||||
frag.depthVal = texture2D(depthMap, texcoord).r;
|
||||
frag.normalVal = texture2D(normalMap, texcoord);
|
||||
frag.diffuseVal = texture2D(diffuseMap, texcoord);
|
||||
frag.specularVal = texture2D(specularMap, texcoord);
|
||||
|
||||
// compute the view space position using the depth
|
||||
float z = near / (frag.depthVal * depthScale - 1.0);
|
||||
frag.position = vec4((depthTexCoordOffset + texcoord * depthTexCoordScale) * z, z, 1.0);
|
||||
|
||||
// Unpack the normal from the map
|
||||
frag.normal = normalize(frag.normalVal.xyz * 2.0 - vec3(1.0));
|
||||
|
||||
return frag;
|
||||
}
|
||||
|
||||
<@endif@>
|
|
@ -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() {
|
||||
|
|
|
@ -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() {
|
||||
|
@ -203,7 +205,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;
|
||||
}
|
||||
|
|
|
@ -12,56 +12,29 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
// the normal texture
|
||||
uniform sampler2D normalMap;
|
||||
|
||||
// the specular texture
|
||||
uniform sampler2D specularMap;
|
||||
|
||||
// the depth texture
|
||||
uniform sampler2D depthMap;
|
||||
|
||||
// the distance to the near clip plane
|
||||
uniform float near;
|
||||
|
||||
// scale factor for depth: (far - near) / far
|
||||
uniform float depthScale;
|
||||
|
||||
// offset for depth texture coordinates
|
||||
uniform vec2 depthTexCoordOffset;
|
||||
|
||||
// scale for depth texture coordinates
|
||||
uniform vec2 depthTexCoordScale;
|
||||
// Everything about deferred buffer
|
||||
<@include DeferredBuffer.slh@>
|
||||
|
||||
void main(void) {
|
||||
float depthVal = texture2D(depthMap, gl_TexCoord[0].st).r;
|
||||
vec4 normalVal = texture2D(normalMap, gl_TexCoord[0].st);
|
||||
vec4 diffuseVal = texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||
vec4 specularVal = texture2D(specularMap, gl_TexCoord[0].st);
|
||||
DeferredFragment frag = unpackDeferredFragment(gl_TexCoord[0].st);
|
||||
|
||||
vec4 normalVal = frag.normalVal;
|
||||
vec4 diffuseVal = frag.diffuseVal;
|
||||
vec4 specularVal = frag.specularVal;
|
||||
|
||||
// compute the view space position using the depth
|
||||
float z = near / (depthVal * depthScale - 1.0);
|
||||
vec4 position = vec4((depthTexCoordOffset + gl_TexCoord[0].st * depthTexCoordScale) * z, z, 0.0);
|
||||
|
||||
// Light mapped or not ?
|
||||
if ((normalVal.a >= 0.45) && (normalVal.a <= 0.55)) {
|
||||
gl_FragColor = vec4(diffuseVal.rgb * specularVal.rgb, 1.0);
|
||||
} else {
|
||||
// get the normal from the map
|
||||
vec3 normalizedNormal = normalize(normalVal.xyz * 2.0 - vec3(1.0));
|
||||
|
||||
// compute the base color based on OpenGL lighting model
|
||||
float diffuse = dot(normalizedNormal, gl_LightSource[0].position.xyz);
|
||||
float diffuse = dot(frag.normal, gl_LightSource[0].position.xyz);
|
||||
float facingLight = step(0.0, diffuse);
|
||||
vec3 baseColor = diffuseVal.rgb * (gl_FrontLightModelProduct.sceneColor.rgb +
|
||||
gl_FrontLightProduct[0].ambient.rgb + gl_FrontLightProduct[0].diffuse.rgb * (diffuse * facingLight));
|
||||
|
||||
// compute the specular multiplier (sans exponent)
|
||||
float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position.xyz - normalize(position.xyz)),
|
||||
normalizedNormal));
|
||||
float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position.xyz - normalize(frag.position.xyz)),
|
||||
frag.normal));
|
||||
|
||||
// add specular contribution
|
||||
vec4 specularColor = specularVal;
|
||||
|
|
|
@ -12,52 +12,24 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
// the normal texture
|
||||
uniform sampler2D normalMap;
|
||||
|
||||
// the specular texture
|
||||
uniform sampler2D specularMap;
|
||||
|
||||
// the depth texture
|
||||
uniform sampler2D depthMap;
|
||||
// Everything about deferred buffer
|
||||
<@include DeferredBuffer.slh@>
|
||||
|
||||
// Everything about shadow
|
||||
<@include Shadow.slh@>
|
||||
|
||||
// the distance to the near clip plane
|
||||
uniform float near;
|
||||
|
||||
// scale factor for depth: (far - near) / far
|
||||
uniform float depthScale;
|
||||
|
||||
// offset for depth texture coordinates
|
||||
uniform vec2 depthTexCoordOffset;
|
||||
|
||||
// scale for depth texture coordinates
|
||||
uniform vec2 depthTexCoordScale;
|
||||
|
||||
void main(void) {
|
||||
float depthVal = texture2D(depthMap, gl_TexCoord[0].st).r;
|
||||
vec4 normalVal = texture2D(normalMap, gl_TexCoord[0].st);
|
||||
vec4 diffuseVal = texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||
vec4 specularVal = texture2D(specularMap, gl_TexCoord[0].st);
|
||||
|
||||
// compute the view space position using the depth
|
||||
float z = near / (depthVal * depthScale - 1.0);
|
||||
vec4 position = vec4((depthTexCoordOffset + gl_TexCoord[0].st * depthTexCoordScale) * z, z, 1.0);
|
||||
DeferredFragment frag = unpackDeferredFragment(gl_TexCoord[0].st);
|
||||
vec4 normalVal = frag.normalVal;
|
||||
vec4 diffuseVal = frag.diffuseVal;
|
||||
vec4 specularVal = frag.specularVal;
|
||||
|
||||
// Eval shadow Texcoord and then Attenuation
|
||||
vec4 shadowTexcoord = evalCascadedShadowTexcoord(position);
|
||||
vec4 shadowTexcoord = evalCascadedShadowTexcoord(frag.position);
|
||||
float shadowAttenuation = evalShadowAttenuation(shadowTexcoord);
|
||||
|
||||
// get the normal from the map
|
||||
vec3 normalizedNormal = normalize(normalVal.xyz * 2.0 - vec3(1.0));
|
||||
|
||||
// how much this fragment faces the light direction
|
||||
float diffuse = dot(normalizedNormal, gl_LightSource[0].position.xyz);
|
||||
float diffuse = dot(frag.normal, gl_LightSource[0].position.xyz);
|
||||
|
||||
// Light mapped or not ?
|
||||
if ((normalVal.a >= 0.45) && (normalVal.a <= 0.55)) {
|
||||
|
@ -83,12 +55,12 @@ void main(void) {
|
|||
float facingLight = step(0.0, diffuse) * shadowAttenuation;
|
||||
|
||||
// compute the base color based on OpenGL lighting model
|
||||
vec3 baseColor = diffuseVal.rgb * (gl_FrontLightModelProduct.sceneColor.rgb +
|
||||
vec3 baseColor = diffuseVal.rgb * (gl_FrontLightModelProduct.sceneColor.rgb +
|
||||
gl_FrontLightProduct[0].ambient.rgb + gl_FrontLightProduct[0].diffuse.rgb * (diffuse * facingLight));
|
||||
|
||||
// compute the specular multiplier (sans exponent)
|
||||
float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position.xyz - normalize(position.xyz)),
|
||||
normalizedNormal));
|
||||
float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position.xyz - normalize(frag.position.xyz)),
|
||||
frag.normal));
|
||||
|
||||
// add specular contribution
|
||||
vec4 specularColor = specularVal;
|
||||
|
|
|
@ -12,52 +12,24 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
// the normal texture
|
||||
uniform sampler2D normalMap;
|
||||
|
||||
// the specular texture
|
||||
uniform sampler2D specularMap;
|
||||
|
||||
// the depth texture
|
||||
uniform sampler2D depthMap;
|
||||
// Everything about deferred buffer
|
||||
<@include DeferredBuffer.slh@>
|
||||
|
||||
// Everything about shadow
|
||||
<@include Shadow.slh@>
|
||||
|
||||
// the distance to the near clip plane
|
||||
uniform float near;
|
||||
|
||||
// scale factor for depth: (far - near) / far
|
||||
uniform float depthScale;
|
||||
|
||||
// offset for depth texture coordinates
|
||||
uniform vec2 depthTexCoordOffset;
|
||||
|
||||
// scale for depth texture coordinates
|
||||
uniform vec2 depthTexCoordScale;
|
||||
|
||||
void main(void) {
|
||||
float depthVal = texture2D(depthMap, gl_TexCoord[0].st).r;
|
||||
vec4 normalVal = texture2D(normalMap, gl_TexCoord[0].st);
|
||||
vec4 diffuseVal = texture2D(diffuseMap, gl_TexCoord[0].st);
|
||||
vec4 specularVal = texture2D(specularMap, gl_TexCoord[0].st);
|
||||
|
||||
// compute the view space position using the depth
|
||||
float z = near / (depthVal * depthScale - 1.0);
|
||||
vec4 position = vec4((depthTexCoordOffset + gl_TexCoord[0].st * depthTexCoordScale) * z, z, 1.0);
|
||||
DeferredFragment frag = unpackDeferredFragment(gl_TexCoord[0].st);
|
||||
vec4 normalVal = frag.normalVal;
|
||||
vec4 diffuseVal = frag.diffuseVal;
|
||||
vec4 specularVal = frag.specularVal;
|
||||
|
||||
// Eval shadow Texcoord and then Attenuation
|
||||
vec4 shadowTexcoord = evalShadowTexcoord(position);
|
||||
vec4 shadowTexcoord = evalShadowTexcoord(frag.position);
|
||||
float shadowAttenuation = evalShadowAttenuation(shadowTexcoord);
|
||||
|
||||
// get the normal from the map
|
||||
vec3 normalizedNormal = normalize(normalVal.xyz * 2.0 - vec3(1.0));
|
||||
|
||||
// how much this fragment faces the light direction
|
||||
float diffuse = dot(normalizedNormal, gl_LightSource[0].position.xyz);
|
||||
float diffuse = dot(frag.normal, gl_LightSource[0].position.xyz);
|
||||
|
||||
// Light mapped or not ?
|
||||
if ((normalVal.a >= 0.45) && (normalVal.a <= 0.55)) {
|
||||
|
@ -86,8 +58,8 @@ void main(void) {
|
|||
gl_FrontLightProduct[0].ambient.rgb + gl_FrontLightProduct[0].diffuse.rgb * (diffuse * facingLight));
|
||||
|
||||
// compute the specular multiplier (sans exponent)
|
||||
float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position.xyz - normalize(position.xyz)),
|
||||
normalizedNormal));
|
||||
float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position.xyz - normalize(frag.position.xyz)),
|
||||
frag.normal));
|
||||
|
||||
// add specular contribution
|
||||
vec4 specularColor = specularVal;
|
||||
|
|
|
@ -12,29 +12,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
// the normal texture
|
||||
uniform sampler2D normalMap;
|
||||
|
||||
// the specular texture
|
||||
uniform sampler2D specularMap;
|
||||
|
||||
// the depth texture
|
||||
uniform sampler2D depthMap;
|
||||
|
||||
// the distance to the near clip plane
|
||||
uniform float near;
|
||||
|
||||
// scale factor for depth: (far - near) / far
|
||||
uniform float depthScale;
|
||||
|
||||
// offset for depth texture coordinates
|
||||
uniform vec2 depthTexCoordOffset;
|
||||
|
||||
// scale for depth texture coordinates
|
||||
uniform vec2 depthTexCoordScale;
|
||||
// Everything about deferred buffer
|
||||
<@include DeferredBuffer.slh@>
|
||||
|
||||
// the radius (hard cutoff) of the light effect
|
||||
uniform float radius;
|
||||
|
|
|
@ -12,29 +12,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
// the normal texture
|
||||
uniform sampler2D normalMap;
|
||||
|
||||
// the specular texture
|
||||
uniform sampler2D specularMap;
|
||||
|
||||
// the depth texture
|
||||
uniform sampler2D depthMap;
|
||||
|
||||
// the distance to the near clip plane
|
||||
uniform float near;
|
||||
|
||||
// scale factor for depth: (far - near) / far
|
||||
uniform float depthScale;
|
||||
|
||||
// offset for depth texture coordinates
|
||||
uniform vec2 depthTexCoordOffset;
|
||||
|
||||
// scale for depth texture coordinates
|
||||
uniform vec2 depthTexCoordScale;
|
||||
// Everything about deferred buffer
|
||||
<@include DeferredBuffer.slh@>
|
||||
|
||||
// the radius (hard cutoff) of the light effect
|
||||
uniform float radius;
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#ifndef hifi_EventTypes_h
|
||||
#define hifi_EventTypes_h
|
||||
|
||||
#include <qscriptengine.h>
|
||||
#include <QScriptEngine>
|
||||
|
||||
void registerEventTypes(QScriptEngine* engine);
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#define hifi_KeyEvent_h
|
||||
|
||||
#include <QKeyEvent>
|
||||
#include <qscriptvalue.h>
|
||||
#include <QScriptValue>
|
||||
|
||||
class KeyEvent {
|
||||
public:
|
||||
|
|
|
@ -66,7 +66,7 @@ QScriptValue XMLHttpRequestClass::getStatus() const {
|
|||
return QScriptValue(200);
|
||||
case QNetworkReply::ContentNotFoundError:
|
||||
return QScriptValue(404);
|
||||
case QNetworkReply::ContentAccessDenied:
|
||||
case QNetworkReply::ContentConflictError:
|
||||
return QScriptValue(409);
|
||||
case QNetworkReply::TimeoutError:
|
||||
return QScriptValue(408);
|
||||
|
@ -89,7 +89,7 @@ QString XMLHttpRequestClass::getStatusText() const {
|
|||
return "OK";
|
||||
case QNetworkReply::ContentNotFoundError:
|
||||
return "Not Found";
|
||||
case QNetworkReply::ContentAccessDenied:
|
||||
case QNetworkReply::ContentConflictError:
|
||||
return "Conflict";
|
||||
case QNetworkReply::TimeoutError:
|
||||
return "Timeout";
|
||||
|
@ -196,8 +196,7 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a
|
|||
} else if (!_file->open(QIODevice::ReadOnly)) {
|
||||
qDebug() << "Can't open file " << _url.fileName();
|
||||
abortRequest();
|
||||
//_errorCode = QNetworkReply::ContentConflictError; // TODO: Use this status when update to Qt 5.3
|
||||
_errorCode = QNetworkReply::ContentAccessDenied;
|
||||
_errorCode = QNetworkReply::ContentConflictError;
|
||||
setReadyState(DONE);
|
||||
emit requestComplete();
|
||||
} else {
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include <unistd.h> // not on windows, not needed for mac or windows
|
||||
#endif
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QDebug>
|
||||
|
||||
const int BYTES_PER_COLOR = 3;
|
||||
const int BYTES_PER_FLAGS = 1;
|
||||
|
|
Loading…
Reference in a new issue