This commit is contained in:
Stephen Birarda 2015-05-15 10:20:12 -07:00
commit 6419a148d4
89 changed files with 3029 additions and 1958 deletions

38
cmake/externals/openvr/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,38 @@
include(ExternalProject)
include(SelectLibraryConfigurations)
set(EXTERNAL_NAME OpenVR)
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
ExternalProject_Add(
${EXTERNAL_NAME}
URL https://github.com/ValveSoftware/openvr/archive/0.9.0.zip
URL_MD5 4fbde7759f604aaa68b9c40d628cc34a
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
LOG_DOWNLOAD 1
)
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/headers CACHE TYPE INTERNAL)
if (WIN32)
# FIXME need to account for different architectures
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/win32/openvr_api.lib CACHE TYPE INTERNAL)
elseif(APPLE)
# FIXME need to account for different architectures
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/osx32/libopenvr_api.dylib CACHE TYPE INTERNAL)
elseif(NOT ANDROID)
# FIXME need to account for different architectures
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/linux32/libopenvr_api.so CACHE TYPE INTERNAL)
endif()

View file

@ -0,0 +1,21 @@
#
# FindLibOVR.cmake
#
# Try to find the LibOVR library to use the Oculus
# Once done this will define
#
# OPENVR_FOUND - system found LibOVR
# OPENVR_INCLUDE_DIRS - the LibOVR include directory
# OPENVR_LIBRARIES - Link this to use LibOVR
#
# 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 ANDROID)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(OPENVR DEFAULT_MSG OPENVR_INCLUDE_DIRS OPENVR_LIBRARIES)
endif()
mark_as_advanced(OPENVR_INCLUDE_DIRS OPENVR_LIBRARIES OPENVR_SEARCH_DIRS)

View file

@ -26,7 +26,7 @@ var viewHelpers = {
setting_value = _(values).valueForKeyPath(keypath);
if (!setting_value) {
if (setting_value === undefined || setting_value === null) {
if (_.has(setting, 'default')) {
setting_value = setting.default;
} else {

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,266 @@
//
// AirHockey.js
//
// Created by Philip Rosedale on January 26, 2015
// Copyright 2015 High Fidelity, Inc.
//
// AirHockey table and pucks
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var debugVisible = false;
var FIELD_WIDTH = 1.21;
var FIELD_LENGTH = 1.92;
var FLOOR_THICKNESS = 0.20;
var EDGE_THICKESS = 0.10;
var EDGE_HEIGHT = 0.10;
var DROP_HEIGHT = 0.3;
var PUCK_SIZE = 0.15;
var PUCK_THICKNESS = 0.05;
var PADDLE_SIZE = 0.15;
var PADDLE_THICKNESS = 0.05;
var GOAL_WIDTH = 0.35;
var GRAVITY = -9.8;
var LIFETIME = 6000;
var PUCK_DAMPING = 0.02;
var PADDLE_DAMPING = 0.35;
var ANGULAR_DAMPING = 0.4;
var PADDLE_ANGULAR_DAMPING = 0.75;
var MODEL_SCALE = 1.52;
var MODEL_OFFSET = { x: 0, y: -0.19, z: 0 };
var scoreSound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Collisions-hitsandslaps/airhockey_score.wav");
var polyTable = "https://hifi-public.s3.amazonaws.com/ozan/props/airHockeyTable/airHockeyTableForPolyworld.fbx"
var normalTable = "https://hifi-public.s3.amazonaws.com/ozan/props/airHockeyTable/airHockeyTable.fbx"
var hitSound1 = "https://s3.amazonaws.com/hifi-public/sounds/Collisions-hitsandslaps/airhockey_hit1.wav"
var hitSound2 = "https://s3.amazonaws.com/hifi-public/sounds/Collisions-hitsandslaps/airhockey_hit2.wav"
var hitSideSound = "https://s3.amazonaws.com/hifi-public/sounds/Collisions-hitsandslaps/airhockey_hit3.wav"
var puckModel = "https://hifi-public.s3.amazonaws.com/ozan/props/airHockeyTable/airHockeyPuck.fbx"
var puckCollisionModel = "http://headache.hungry.com/~seth/hifi/airHockeyPuck-hull.obj"
var paddleModel = "https://hifi-public.s3.amazonaws.com/ozan/props/airHockeyTable/airHockeyPaddle.obj"
var paddleCollisionModel = "http://headache.hungry.com/~seth/hifi/paddle-hull.obj"
var center = Vec3.sum(MyAvatar.position, Vec3.multiply((FIELD_WIDTH + FIELD_LENGTH) * 0.60, Quat.getFront(Camera.getOrientation())));
var edgeRestitution = 0.9;
var floorFriction = 0.01;
var floor = Entities.addEntity(
{ type: "Box",
position: Vec3.subtract(center, { x: 0, y: 0, z: 0 }),
dimensions: { x: FIELD_WIDTH, y: FLOOR_THICKNESS, z: FIELD_LENGTH },
color: { red: 128, green: 128, blue: 128 },
gravity: { x: 0, y: 0, z: 0 },
ignoreCollisions: false,
locked: true,
friction: floorFriction,
visible: debugVisible,
lifetime: LIFETIME });
var edge1 = Entities.addEntity(
{ type: "Box",
collisionSoundURL: hitSideSound,
position: Vec3.sum(center, { x: FIELD_WIDTH / 2.0, y: FLOOR_THICKNESS / 2.0, z: 0 }),
dimensions: { x: EDGE_THICKESS, y: EDGE_HEIGHT, z: FIELD_LENGTH + EDGE_THICKESS },
color: { red: 100, green: 100, blue: 100 },
gravity: { x: 0, y: 0, z: 0 },
ignoreCollisions: false,
visible: debugVisible,
restitution: edgeRestitution,
locked: true,
lifetime: LIFETIME });
var edge2 = Entities.addEntity(
{ type: "Box",
collisionSoundURL: hitSideSound,
position: Vec3.sum(center, { x: -FIELD_WIDTH / 2.0, y: FLOOR_THICKNESS / 2.0, z: 0 }),
dimensions: { x: EDGE_THICKESS, y: EDGE_HEIGHT, z: FIELD_LENGTH + EDGE_THICKESS },
color: { red: 100, green: 100, blue: 100 },
gravity: { x: 0, y: 0, z: 0 },
ignoreCollisions: false,
visible: debugVisible,
restitution: edgeRestitution,
locked: true,
lifetime: LIFETIME });
var edge3a = Entities.addEntity(
{ type: "Box",
collisionSoundURL: hitSideSound,
position: Vec3.sum(center, { x: FIELD_WIDTH / 4.0 + (GOAL_WIDTH / 4.0), y: FLOOR_THICKNESS / 2.0, z: -FIELD_LENGTH / 2.0 }),
dimensions: { x: FIELD_WIDTH / 2.0 - GOAL_WIDTH / 2.0, y: EDGE_HEIGHT, z: EDGE_THICKESS },
color: { red: 100, green: 100, blue: 100 },
gravity: { x: 0, y: 0, z: 0 },
ignoreCollisions: false,
visible: debugVisible,
restitution: edgeRestitution,
locked: true,
lifetime: LIFETIME });
var edge3b = Entities.addEntity(
{ type: "Box",
collisionSoundURL: hitSideSound,
position: Vec3.sum(center, { x: -FIELD_WIDTH / 4.0 - (GOAL_WIDTH / 4.0), y: FLOOR_THICKNESS / 2.0, z: -FIELD_LENGTH / 2.0 }),
dimensions: { x: FIELD_WIDTH / 2.0 - GOAL_WIDTH / 2.0, y: EDGE_HEIGHT, z: EDGE_THICKESS },
color: { red: 100, green: 100, blue: 100 },
gravity: { x: 0, y: 0, z: 0 },
ignoreCollisions: false,
visible: debugVisible,
restitution: edgeRestitution,
locked: true,
lifetime: LIFETIME });
var edge4a = Entities.addEntity(
{ type: "Box",
collisionSoundURL: hitSideSound,
position: Vec3.sum(center, { x: FIELD_WIDTH / 4.0 + (GOAL_WIDTH / 4.0), y: FLOOR_THICKNESS / 2.0, z: FIELD_LENGTH / 2.0 }),
dimensions: { x: FIELD_WIDTH / 2.0 - GOAL_WIDTH / 2.0, y: EDGE_HEIGHT, z: EDGE_THICKESS },
color: { red: 100, green: 100, blue: 100 },
gravity: { x: 0, y: 0, z: 0 },
ignoreCollisions: false,
visible: debugVisible,
restitution: edgeRestitution,
locked: true,
lifetime: LIFETIME });
var edge4b = Entities.addEntity(
{ type: "Box",
collisionSoundURL: hitSideSound,
position: Vec3.sum(center, { x: -FIELD_WIDTH / 4.0 - (GOAL_WIDTH / 4.0), y: FLOOR_THICKNESS / 2.0, z: FIELD_LENGTH / 2.0 }),
dimensions: { x: FIELD_WIDTH / 2.0 - GOAL_WIDTH / 2.0, y: EDGE_HEIGHT, z: EDGE_THICKESS },
color: { red: 100, green: 100, blue: 100 },
gravity: { x: 0, y: 0, z: 0 },
ignoreCollisions: false,
visible: debugVisible,
restitution: edgeRestitution,
locked: true,
lifetime: LIFETIME });
var table = Entities.addEntity(
{ type: "Model",
modelURL: polyTable,
dimensions: Vec3.multiply({ x: 0.8, y: 0.45, z: 1.31 }, MODEL_SCALE),
position: Vec3.sum(center, MODEL_OFFSET),
ignoreCollisions: false,
visible: true,
locked: true,
lifetime: LIFETIME });
var puck;
var paddle1, paddle2;
// Create pucks
function makeNewProp(which) {
if (which == "puck") {
return Entities.addEntity(
{ type: "Model",
modelURL: puckModel,
compoundShapeURL: puckCollisionModel,
collisionSoundURL: hitSound1,
position: Vec3.sum(center, { x: 0, y: DROP_HEIGHT, z: 0 }),
dimensions: { x: PUCK_SIZE, y: PUCK_THICKNESS, z: PUCK_SIZE },
gravity: { x: 0, y: GRAVITY, z: 0 },
velocity: { x: 0, y: 0.05, z: 0 },
ignoreCollisions: false,
damping: PUCK_DAMPING,
angularDamping: ANGULAR_DAMPING,
lifetime: LIFETIME,
collisionsWillMove: true });
}
else if (which == "paddle1") {
return Entities.addEntity(
{ type: "Model",
modelURL: paddleModel,
compoundShapeURL: paddleCollisionModel,
collisionSoundURL: hitSound2,
position: Vec3.sum(center, { x: 0, y: DROP_HEIGHT * 1.5, z: FIELD_LENGTH * 0.35 }),
dimensions: { x: PADDLE_SIZE, y: PADDLE_THICKNESS, z: PADDLE_SIZE },
gravity: { x: 0, y: GRAVITY, z: 0 },
velocity: { x: 0, y: 0.07, z: 0 },
ignoreCollisions: false,
damping: PADDLE_DAMPING,
angularDamping: PADDLE_ANGULAR_DAMPING,
lifetime: LIFETIME,
collisionsWillMove: true });
}
else if (which == "paddle2") {
return Entities.addEntity(
{ type: "Model",
modelURL: paddleModel,
compoundShapeURL: paddleCollisionModel,
collisionSoundURL: hitSound2,
position: Vec3.sum(center, { x: 0, y: DROP_HEIGHT * 1.5, z: -FIELD_LENGTH * 0.35 }),
dimensions: { x: PADDLE_SIZE, y: PADDLE_THICKNESS, z: PADDLE_SIZE },
gravity: { x: 0, y: GRAVITY, z: 0 },
velocity: { x: 0, y: 0.07, z: 0 },
ignoreCollisions: false,
damping: PADDLE_DAMPING,
angularDamping: PADDLE_ANGULAR_DAMPING,
lifetime: LIFETIME,
collisionsWillMove: true });
}
}
puck = makeNewProp("puck");
paddle1 = makeNewProp("paddle1");
paddle2 = makeNewProp("paddle2");
function update(deltaTime) {
if (Math.random() < 0.1) {
puckProps = Entities.getEntityProperties(puck);
paddle1Props = Entities.getEntityProperties(paddle1);
paddle2Props = Entities.getEntityProperties(paddle2);
if (puckProps.position.y < (center.y - DROP_HEIGHT)) {
Audio.playSound(scoreSound, {
position: center,
volume: 1.0
});
Entities.deleteEntity(puck);
puck = makeNewProp("puck");
}
if (paddle1Props.position.y < (center.y - DROP_HEIGHT)) {
Entities.deleteEntity(paddle1);
paddle1 = makeNewProp("paddle1");
}
if (paddle2Props.position.y < (center.y - DROP_HEIGHT)) {
Entities.deleteEntity(paddle2);
paddle2 = makeNewProp("paddle2");
}
}
}
function scriptEnding() {
Entities.editEntity(edge1, { locked: false });
Entities.editEntity(edge2, { locked: false });
Entities.editEntity(edge3a, { locked: false });
Entities.editEntity(edge3b, { locked: false });
Entities.editEntity(edge4a, { locked: false });
Entities.editEntity(edge4b, { locked: false });
Entities.editEntity(floor, { locked: false });
Entities.editEntity(table, { locked: false });
Entities.deleteEntity(edge1);
Entities.deleteEntity(edge2);
Entities.deleteEntity(edge3a);
Entities.deleteEntity(edge3b);
Entities.deleteEntity(edge4a);
Entities.deleteEntity(edge4b);
Entities.deleteEntity(floor);
Entities.deleteEntity(puck);
Entities.deleteEntity(paddle1);
Entities.deleteEntity(paddle2);
Entities.deleteEntity(table);
}
Script.update.connect(update);
Script.scriptEnding.connect(scriptEnding);

View file

@ -0,0 +1,278 @@
// grab.js
// examples
//
// Created by Eric Levin on May 1, 2015
// Copyright 2015 High Fidelity, Inc.
//
// Grab's physically moveable entities with the mouse, by applying a spring force.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var isGrabbing = false;
var grabbedEntity = null;
var lineEntityID = null;
var prevMouse = {};
var deltaMouse = {
z: 0
}
var entityProps;
var moveUpDown = false;
var CLOSE_ENOUGH = 0.001;
var FULL_STRENGTH = 1.0;
var SPRING_RATE = 1.5;
var DAMPING_RATE = 0.80;
var ANGULAR_DAMPING_RATE = 0.40;
var SCREEN_TO_METERS = 0.001;
var currentPosition, currentVelocity, cameraEntityDistance, currentRotation;
var velocityTowardTarget, desiredVelocity, addedVelocity, newVelocity, dPosition, camYaw, distanceToTarget, targetPosition;
var originalGravity = {x: 0, y: 0, z: 0};
var shouldRotate = false;
var dQ, theta, axisAngle, dT;
var angularVelocity = {
x: 0,
y: 0,
z: 0
};
var grabSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/eric/sounds/CloseClamp.wav");
var releaseSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/eric/sounds/ReleaseClamp.wav");
var VOLUME = 0.10;
var DROP_DISTANCE = 5.0;
var DROP_COLOR = {
red: 200,
green: 200,
blue: 200
};
var DROP_WIDTH = 2;
var dropLine = Overlays.addOverlay("line3d", {
color: DROP_COLOR,
alpha: 1,
visible: false,
lineWidth: DROP_WIDTH
});
function vectorIsZero(v) {
return v.x == 0 && v.y == 0 && v.z == 0;
}
function nearLinePoint(targetPosition) {
// var handPosition = Vec3.sum(MyAvatar.position, {x:0, y:0.2, z:0});
var handPosition = MyAvatar.getRightPalmPosition();
var along = Vec3.subtract(targetPosition, handPosition);
along = Vec3.normalize(along);
along = Vec3.multiply(along, 0.4);
return Vec3.sum(handPosition, along);
}
function mousePressEvent(event) {
if (!event.isLeftButton) {
return;
}
var pickRay = Camera.computePickRay(event.x, event.y);
var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking
if (intersection.intersects && intersection.properties.collisionsWillMove) {
grabbedEntity = intersection.entityID;
var props = Entities.getEntityProperties(grabbedEntity)
isGrabbing = true;
originalGravity = props.gravity;
targetPosition = props.position;
currentPosition = props.position;
currentVelocity = props.velocity;
updateDropLine(targetPosition);
Entities.editEntity(grabbedEntity, {
gravity: {x: 0, y: 0, z: 0}
});
lineEntityID = Entities.addEntity({
type: "Line",
position: nearLinePoint(targetPosition),
dimensions: Vec3.subtract(targetPosition, nearLinePoint(targetPosition)),
color: { red: 255, green: 255, blue: 255 },
lifetime: 300 // if someone crashes while moving something, don't leave the line there forever.
});
Audio.playSound(grabSound, {
position: props.position,
volume: VOLUME
});
}
}
function updateDropLine(position) {
Overlays.editOverlay(dropLine, {
visible: true,
start: {
x: position.x,
y: position.y + DROP_DISTANCE,
z: position.z
},
end: {
x: position.x,
y: position.y - DROP_DISTANCE,
z: position.z
}
})
}
function mouseReleaseEvent() {
if (isGrabbing) {
isGrabbing = false;
// only restore the original gravity if it's not zero. This is to avoid...
// 1. interface A grabs an entity and locally saves off its gravity
// 2. interface A sets the entity's gravity to zero
// 3. interface B grabs the entity and saves off its gravity (which is zero)
// 4. interface A releases the entity and puts the original gravity back
// 5. interface B releases the entity and puts the original gravity back (to zero)
if (!vectorIsZero(originalGravity)) {
Entities.editEntity(grabbedEntity, {
gravity: originalGravity
});
}
Overlays.editOverlay(dropLine, {
visible: false
});
targetPosition = null;
Entities.deleteEntity(lineEntityID);
Audio.playSound(releaseSound, {
position: entityProps.position,
volume: VOLUME
});
}
}
function mouseMoveEvent(event) {
if (isGrabbing) {
// see if something added/restored gravity
var props = Entities.getEntityProperties(grabbedEntity);
if (!vectorIsZero(props.gravity)) {
originalGravity = props.gravity;
}
deltaMouse.x = event.x - prevMouse.x;
if (!moveUpDown) {
deltaMouse.z = event.y - prevMouse.y;
deltaMouse.y = 0;
} else {
deltaMouse.y = (event.y - prevMouse.y) * -1;
deltaMouse.z = 0;
}
// Update the target position by the amount the mouse moved
camYaw = Quat.safeEulerAngles(Camera.getOrientation()).y;
dPosition = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, camYaw, 0), deltaMouse);
if (!shouldRotate) {
// Adjust target position for the object by the mouse move
cameraEntityDistance = Vec3.distance(Camera.getPosition(), currentPosition);
// Scale distance we want to move by the distance from the camera to the grabbed object
// TODO: Correct SCREEN_TO_METERS to be correct for the actual FOV, resolution
targetPosition = Vec3.sum(targetPosition, Vec3.multiply(dPosition, cameraEntityDistance * SCREEN_TO_METERS));
} else if (shouldRotate) {
var transformedDeltaMouse = {
x: deltaMouse.z,
y: deltaMouse.x,
z: deltaMouse.y
};
transformedDeltaMouse = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, camYaw, 0), transformedDeltaMouse);
dQ = Quat.fromVec3Degrees(transformedDeltaMouse);
theta = 2 * Math.acos(dQ.w);
axisAngle = Quat.axis(dQ);
angularVelocity = Vec3.multiply((theta / dT), axisAngle);
}
Entities.editEntity(lineEntityID, {
position: nearLinePoint(targetPosition),
dimensions: Vec3.subtract(targetPosition, nearLinePoint(targetPosition))
});
}
prevMouse.x = event.x;
prevMouse.y = event.y;
}
function keyReleaseEvent(event) {
if (event.text === "SHIFT") {
moveUpDown = false;
}
if (event.text === "SPACE") {
shouldRotate = false;
}
}
function keyPressEvent(event) {
if (event.text === "SHIFT") {
moveUpDown = true;
}
if (event.text === "SPACE") {
shouldRotate = true;
}
}
function update(deltaTime) {
dT = deltaTime;
if (isGrabbing) {
entityProps = Entities.getEntityProperties(grabbedEntity);
currentPosition = entityProps.position;
currentVelocity = entityProps.velocity;
currentRotation = entityProps.rotation;
var dPosition = Vec3.subtract(targetPosition, currentPosition);
distanceToTarget = Vec3.length(dPosition);
if (distanceToTarget > CLOSE_ENOUGH) {
// compute current velocity in the direction we want to move
velocityTowardTarget = Vec3.dot(currentVelocity, Vec3.normalize(dPosition));
velocityTowardTarget = Vec3.multiply(Vec3.normalize(dPosition), velocityTowardTarget);
// compute the speed we would like to be going toward the target position
desiredVelocity = Vec3.multiply(dPosition, (1.0 / deltaTime) * SPRING_RATE);
// compute how much we want to add to the existing velocity
addedVelocity = Vec3.subtract(desiredVelocity, velocityTowardTarget);
// If target is too far, roll off the force as inverse square of distance
if (distanceToTarget / cameraEntityDistance > FULL_STRENGTH) {
addedVelocity = Vec3.multiply(addedVelocity, Math.pow(FULL_STRENGTH / distanceToTarget, 2.0));
}
newVelocity = Vec3.sum(currentVelocity, addedVelocity);
// Add Damping
newVelocity = Vec3.subtract(newVelocity, Vec3.multiply(newVelocity, DAMPING_RATE));
// Update entity
} else {
newVelocity = {x: 0, y: 0, z: 0};
}
if (shouldRotate) {
angularVelocity = Vec3.subtract(angularVelocity, Vec3.multiply(angularVelocity, ANGULAR_DAMPING_RATE));
} else {
angularVelocity = entityProps.angularVelocity;
}
Entities.editEntity(grabbedEntity, {
position: currentPosition,
rotation: currentRotation,
velocity: newVelocity,
angularVelocity: angularVelocity
});
updateDropLine(targetPosition);
}
}
Controller.mouseMoveEvent.connect(mouseMoveEvent);
Controller.mousePressEvent.connect(mousePressEvent);
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
Controller.keyPressEvent.connect(keyPressEvent);
Controller.keyReleaseEvent.connect(keyReleaseEvent);
Script.update.connect(update);

View file

@ -0,0 +1,303 @@
//
// hydraGrabHockey.js
// examples
//
// Created by Eric Levin on 5/14/15.
// Copyright 2015 High Fidelity, Inc.
//
// This script allows you to grab and move physical objects with the hydra
// Same as hydraGrab.js, but you object movement is constrained to xz plane and cannot rotate object
//
//
// Using the hydras :
// grab physical entities with the right hydra trigger
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var addedVelocity, newVelocity, angularVelocity, dT, cameraEntityDistance;
var LEFT = 0;
var RIGHT = 1;
var LASER_WIDTH = 3;
var LASER_COLOR = {
red: 50,
green: 150,
blue: 200
};
var LASER_HOVER_COLOR = {
red: 200,
green: 50,
blue: 50
};
var DROP_DISTANCE = 5.0;
var DROP_COLOR = {
red: 200,
green: 200,
blue: 200
};
var FULL_STRENGTH = 0.2;
var LASER_LENGTH_FACTOR = 500;
var CLOSE_ENOUGH = 0.001;
var SPRING_RATE = 1.5;
var DAMPING_RATE = 0.8;
var SCREEN_TO_METERS = 0.001;
var DISTANCE_SCALE_FACTOR = 1000
var grabSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/eric/sounds/CloseClamp.wav");
var releaseSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/eric/sounds/ReleaseClamp.wav");
function getRayIntersection(pickRay) {
var intersection = Entities.findRayIntersection(pickRay, true);
return intersection;
}
function controller(side) {
this.triggerHeld = false;
this.triggerThreshold = 0.9;
this.side = side;
this.palm = 2 * side;
this.tip = 2 * side + 1;
this.trigger = side;
this.originalGravity = {
x: 0,
y: 0,
z: 0
};
this.laser = Overlays.addOverlay("line3d", {
start: {
x: 0,
y: 0,
z: 0
},
end: {
x: 0,
y: 0,
z: 0
},
color: LASER_COLOR,
alpha: 1,
lineWidth: LASER_WIDTH,
anchor: "MyAvatar"
});
this.dropLine = Overlays.addOverlay("line3d", {
color: DROP_COLOR,
alpha: 1,
visible: false,
lineWidth: 2
});
this.update = function(deltaTime) {
this.updateControllerState();
this.moveLaser();
this.checkTrigger();
this.checkEntityIntersection();
if (this.grabbing) {
this.updateEntity(deltaTime);
}
this.oldPalmPosition = this.palmPosition;
this.oldTipPosition = this.tipPosition;
}
this.updateEntity = function(deltaTime) {
this.dControllerPosition = Vec3.subtract(this.palmPosition, this.oldPalmPosition);
this.dControllerPosition.y = 0;
this.cameraEntityDistance = Vec3.distance(Camera.getPosition(), this.currentPosition);
this.targetPosition = Vec3.sum(this.targetPosition, Vec3.multiply(this.dControllerPosition, this.cameraEntityDistance * SCREEN_TO_METERS * DISTANCE_SCALE_FACTOR));
this.entityProps = Entities.getEntityProperties(this.grabbedEntity);
this.currentPosition = this.entityProps.position;
this.currentVelocity = this.entityProps.velocity;
var dPosition = Vec3.subtract(this.targetPosition, this.currentPosition);
this.distanceToTarget = Vec3.length(dPosition);
if (this.distanceToTarget > CLOSE_ENOUGH) {
// compute current velocity in the direction we want to move
this.velocityTowardTarget = Vec3.dot(this.currentVelocity, Vec3.normalize(dPosition));
this.velocityTowardTarget = Vec3.multiply(Vec3.normalize(dPosition), this.velocityTowardTarget);
// compute the speed we would like to be going toward the target position
this.desiredVelocity = Vec3.multiply(dPosition, (1.0 / deltaTime) * SPRING_RATE);
// compute how much we want to add to the existing velocity
this.addedVelocity = Vec3.subtract(this.desiredVelocity, this.velocityTowardTarget);
//If target is to far, roll off force as inverse square of distance
if(this.distanceToTarget/ this.cameraEntityDistance > FULL_STRENGTH) {
this.addedVelocity = Vec3.multiply(this.addedVelocity, Math.pow(FULL_STRENGTH/ this.distanceToTarget, 2.0));
}
this.newVelocity = Vec3.sum(this.currentVelocity, this.addedVelocity);
this.newVelocity = Vec3.subtract(this.newVelocity, Vec3.multiply(this.newVelocity, DAMPING_RATE));
} else {
this.newVelocity = {
x: 0,
y: 0,
z: 0
};
}
Entities.editEntity(this.grabbedEntity, {
velocity: this.newVelocity,
});
this.updateDropLine(this.targetPosition);
}
this.updateControllerState = function() {
this.palmPosition = Controller.getSpatialControlPosition(this.palm);
this.tipPosition = Controller.getSpatialControlPosition(this.tip);
this.triggerValue = Controller.getTriggerValue(this.trigger);
}
this.checkTrigger = function() {
if (this.triggerValue > this.triggerThreshold && !this.triggerHeld) {
this.triggerHeld = true;
} else if (this.triggerValue < this.triggerThreshold && this.triggerHeld) {
this.triggerHeld = false;
if (this.grabbing) {
this.release();
}
}
}
this.updateDropLine = function(position) {
Overlays.editOverlay(this.dropLine, {
visible: true,
start: {
x: position.x,
y: position.y + DROP_DISTANCE,
z: position.z
},
end: {
x: position.x,
y: position.y - DROP_DISTANCE,
z: position.z
}
});
}
this.checkEntityIntersection = function() {
var pickRay = {
origin: this.palmPosition,
direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition))
};
var intersection = getRayIntersection(pickRay, true);
if (intersection.intersects && intersection.properties.collisionsWillMove) {
this.laserWasHovered = true;
if (this.triggerHeld && !this.grabbing) {
this.grab(intersection.entityID);
}
Overlays.editOverlay(this.laser, {
color: LASER_HOVER_COLOR
});
} else if (this.laserWasHovered) {
this.laserWasHovered = false;
Overlays.editOverlay(this.laser, {
color: LASER_COLOR
});
}
}
this.grab = function(entityId) {
this.grabbing = true;
this.grabbedEntity = entityId;
this.entityProps = Entities.getEntityProperties(this.grabbedEntity);
this.targetPosition = this.entityProps.position;
this.currentPosition = this.targetPosition;
this.oldPalmPosition = this.palmPosition;
this.originalGravity = this.entityProps.gravity;
Entities.editEntity(this.grabbedEntity, {
gravity: {
x: 0,
y: 0,
z: 0
}
});
Overlays.editOverlay(this.laser, {
visible: false
});
Audio.playSound(grabSound, {
position: this.entityProps.position,
volume: 0.25
});
}
this.release = function() {
this.grabbing = false;
this.grabbedEntity = null;
Overlays.editOverlay(this.laser, {
visible: true
});
Overlays.editOverlay(this.dropLine, {
visible: false
});
Audio.playSound(releaseSound, {
position: this.entityProps.position,
volume: 0.25
});
// only restore the original gravity if it's not zero. This is to avoid...
// 1. interface A grabs an entity and locally saves off its gravity
// 2. interface A sets the entity's gravity to zero
// 3. interface B grabs the entity and saves off its gravity (which is zero)
// 4. interface A releases the entity and puts the original gravity back
// 5. interface B releases the entity and puts the original gravity back (to zero)
if(vectorIsZero(this.originalGravity)) {
Entities.editEntity(this.grabbedEntity, {
gravity: this.originalGravity
});
}
}
this.moveLaser = function() {
var inverseRotation = Quat.inverse(MyAvatar.orientation);
var startPosition = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.palmPosition, MyAvatar.position));
// startPosition = Vec3.multiply(startPosition, 1 / MyAvatar.scale);
var direction = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.tipPosition, this.palmPosition));
direction = Vec3.multiply(direction, LASER_LENGTH_FACTOR / (Vec3.length(direction) * MyAvatar.scale));
var endPosition = Vec3.sum(startPosition, direction);
Overlays.editOverlay(this.laser, {
start: startPosition,
end: endPosition
});
}
this.cleanup = function() {
Overlays.deleteOverlay(this.laser);
Overlays.deleteOverlay(this.dropLine);
}
}
function update(deltaTime) {
rightController.update(deltaTime);
leftController.update(deltaTime);
}
function scriptEnding() {
rightController.cleanup();
leftController.cleanup();
}
function vectorIsZero(v) {
return v.x === 0 && v.y === 0 && v.z === 0;
}
var rightController = new controller(RIGHT);
var leftController = new controller(LEFT);
Script.update.connect(update);
Script.scriptEnding.connect(scriptEnding);

View file

@ -17,6 +17,8 @@ const BASE_DIMENSION = { x: 7, y: 2, z: 7 };
const BLOCKS_PER_LAYER = 3;
const BLOCK_SIZE = {x: 0.2, y: 0.1, z: 0.8};
const BLOCK_SPACING = BLOCK_SIZE.x / 3;
// BLOCK_HEIGHT_VARIATION removes a random percentages of the default block height per block. (for example 0.001 %)
const BLOCK_HEIGHT_VARIATION = 0.001;
const GRAVITY = {x: 0, y: -2.8, z: 0};
const DENSITY = 2000;
const DAMPING_FACTOR = 0.98;
@ -24,6 +26,7 @@ const ANGULAR_DAMPING_FACTOR = 0.8;
const SPAWN_DISTANCE = 3;
const BLOCK_YAW_OFFSET = 45;
const BUTTON_DIMENSIONS = {width: 49, height: 49};
const MAXIMUM_PERCENTAGE = 100.0;
var windowWidth = Window.innerWidth;
var size;
@ -94,7 +97,11 @@ function resetBlocks() {
modelURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/block.fbx',
shapeType: 'box',
name: 'PlankyBlock' + ((layerIndex * BLOCKS_PER_LAYER) + blockIndex),
dimensions: BLOCK_SIZE,
dimensions: {
x: BLOCK_SIZE.x,
y: BLOCK_SIZE.y - ((BLOCK_SIZE.y * (BLOCK_HEIGHT_VARIATION / MAXIMUM_PERCENTAGE)) * Math.random()),
z: BLOCK_SIZE.z
},
position: {
x: basePosition.x + localTransform.x,
y: basePosition.y + localTransform.y,

View file

@ -76,7 +76,7 @@ function mousePressEvent(event) {
return;
}
var pickRay = Camera.computePickRay(event.x, event.y);
var intersection = Entities.findRayIntersection(pickRay);
var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking
if (intersection.intersects && intersection.properties.collisionsWillMove) {
grabbedEntity = intersection.entityID;
var props = Entities.getEntityProperties(grabbedEntity)

View file

@ -233,6 +233,9 @@
var elAngularVelocityZ = document.getElementById("property-avel-z");
var elAngularDamping = document.getElementById("property-adamping");
var elRestitution = document.getElementById("property-restitution");
var elFriction = document.getElementById("property-friction");
var elGravityX = document.getElementById("property-grav-x");
var elGravityY = document.getElementById("property-grav-y");
var elGravityZ = document.getElementById("property-grav-z");
@ -244,6 +247,7 @@
var elDensity = document.getElementById("property-density");
var elIgnoreForCollisions = document.getElementById("property-ignore-for-collisions");
var elCollisionsWillMove = document.getElementById("property-collisions-will-move");
var elCollisionSoundURL = document.getElementById("property-collision-sound-url");
var elLifetime = document.getElementById("property-lifetime");
var elScriptURL = document.getElementById("property-script-url");
var elUserData = document.getElementById("property-user-data");
@ -426,6 +430,9 @@
elAngularVelocityZ.value = (properties.angularVelocity.z * RADIANS_TO_DEGREES).toFixed(2);
elAngularDamping.value = properties.angularDamping.toFixed(2);
elRestitution.value = properties.restitution.toFixed(2);
elFriction.value = properties.friction.toFixed(2);
elGravityX.value = properties.gravity.x.toFixed(2);
elGravityY.value = properties.gravity.y.toFixed(2);
elGravityZ.value = properties.gravity.z.toFixed(2);
@ -437,6 +444,7 @@
elDensity.value = properties.density.toFixed(2);
elIgnoreForCollisions.checked = properties.ignoreForCollisions;
elCollisionsWillMove.checked = properties.collisionsWillMove;
elCollisionSoundURL.value = properties.collisionSoundURL;
elLifetime.value = properties.lifetime;
elScriptURL.value = properties.script;
elUserData.value = properties.userData;
@ -605,7 +613,10 @@
elAngularVelocityX.addEventListener('change', angularVelocityChangeFunction);
elAngularVelocityY.addEventListener('change', angularVelocityChangeFunction);
elAngularVelocityZ.addEventListener('change', angularVelocityChangeFunction);
elAngularDamping.addEventListener('change', createEmitNumberPropertyUpdateFunction('angularDamping'))
elAngularDamping.addEventListener('change', createEmitNumberPropertyUpdateFunction('angularDamping'));
elRestitution.addEventListener('change', createEmitNumberPropertyUpdateFunction('restitution'));
elFriction.addEventListener('change', createEmitNumberPropertyUpdateFunction('friction'));
var gravityChangeFunction = createEmitVec3PropertyUpdateFunction(
'gravity', elGravityX, elGravityY, elGravityZ);
@ -622,6 +633,8 @@
elDensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('density'));
elIgnoreForCollisions.addEventListener('change', createEmitCheckedPropertyUpdateFunction('ignoreForCollisions'));
elCollisionsWillMove.addEventListener('change', createEmitCheckedPropertyUpdateFunction('collisionsWillMove'));
elCollisionSoundURL.addEventListener('change', createEmitTextPropertyUpdateFunction('collisionSoundURL'));
elLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('lifetime'));
elScriptURL.addEventListener('change', createEmitTextPropertyUpdateFunction('script'));
elUserData.addEventListener('change', createEmitTextPropertyUpdateFunction('userData'));
@ -959,6 +972,18 @@
<input class="coord" type='number' id="property-adamping"></input>
</div>
</div>
<div class="property">
<div class="label">Restitution</div>
<div class="value">
<input class="coord" type='number' id="property-restitution"></input>
</div>
</div>
<div class="property">
<div class="label">Friction</div>
<div class="value">
<input class="coord" type='number' id="property-friction"></input>
</div>
</div>
<div class="property">
<div class="label">Gravity</div>
@ -999,6 +1024,13 @@
</span>
</div>
<div class="property">
<div class="label">Collision Sound URL</div>
<div class="value">
<input id="property-collision-sound-url" class="url"></input>
</div>
</div>
<div class="property">
<div class="label">Lifetime</div>
<div class="value">

View file

@ -243,7 +243,6 @@ table#properties-list {
#properties-list .label {
font-weight: bold;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;

View file

@ -185,6 +185,8 @@ EntityPropertyDialogBox = (function () {
index++;
array.push({ label: "Collisions Will Move:", type: "checkbox", value: properties.collisionsWillMove });
index++;
array.push({ label: "Collision Sound URL:", value: properties.collisionSoundURL });
index++;
array.push({ label: "Lifetime:", value: properties.lifetime.toFixed(decimals) });
index++;

View file

@ -36,8 +36,22 @@ endif ()
configure_file(InterfaceConfig.h.in "${PROJECT_BINARY_DIR}/includes/InterfaceConfig.h")
configure_file(InterfaceVersion.h.in "${PROJECT_BINARY_DIR}/includes/InterfaceVersion.h")
macro(GroupSources curdir)
file(GLOB children RELATIVE ${PROJECT_SOURCE_DIR}/${curdir} ${PROJECT_SOURCE_DIR}/${curdir}/*)
foreach(child ${children})
if(IS_DIRECTORY ${PROJECT_SOURCE_DIR}/${curdir}/${child})
GroupSources(${curdir}/${child})
else()
string(REPLACE "/" "\\" groupname ${curdir})
source_group(${groupname} FILES ${PROJECT_SOURCE_DIR}/${curdir}/${child})
endif()
endforeach()
endmacro()
# grab the implementation and header files from src dirs
file(GLOB_RECURSE INTERFACE_SRCS "src/*.cpp" "src/*.h")
GroupSources("src")
# Add SpeechRecognizer if on Windows or OS X, otherwise remove
if (WIN32)
@ -58,6 +72,7 @@ find_package(Qt5 COMPONENTS Gui Multimedia Network OpenGL Qml Quick Script Svg W
# grab the ui files in resources/ui
file (GLOB_RECURSE QT_UI_FILES ui/*.ui)
source_group("UI Files" FILES ${QT_UI_FILES})
# have qt5 wrap them and generate the appropriate header files
qt5_wrap_ui(QT_UI_HEADERS "${QT_UI_FILES}")

View file

@ -839,6 +839,11 @@ void Application::paintGL() {
PerformanceWarning warn(showWarnings, "Application::paintGL()");
resizeGL();
{
PerformanceTimer perfTimer("renderOverlay");
_applicationOverlay.renderOverlay();
}
glEnable(GL_LINE_SMOOTH);
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
@ -921,13 +926,9 @@ void Application::paintGL() {
glBlitFramebuffer(0, 0, _renderResolution.x, _renderResolution.y,
0, 0, _glWidget->getDeviceSize().width(), _glWidget->getDeviceSize().height(),
GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
{
PerformanceTimer perfTimer("renderOverlay");
_applicationOverlay.renderOverlay();
_applicationOverlay.displayOverlayTexture();
}
_applicationOverlay.displayOverlayTexture();
}
if (!OculusManager::isConnected() || OculusManager::allowSwap()) {
@ -2455,7 +2456,7 @@ void Application::update(float deltaTime) {
if (_physicsEngine.hasOutgoingChanges()) {
_entitySimulation.lock();
_entitySimulation.handleOutgoingChanges(_physicsEngine.getOutgoingChanges());
_entitySimulation.handleOutgoingChanges(_physicsEngine.getOutgoingChanges(), _physicsEngine.getSessionID());
_entitySimulation.handleCollisionEvents(_physicsEngine.getCollisionEvents());
_entitySimulation.unlock();
_physicsEngine.dumpStatsIfNecessary();
@ -3078,7 +3079,11 @@ PickRay Application::computePickRay(float x, float y) const {
if (isHMDMode()) {
ApplicationOverlay::computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction);
} else {
getViewFrustum()->computePickRay(x, y, result.origin, result.direction);
if (activeRenderingThread) {
getDisplayViewFrustum()->computePickRay(x, y, result.origin, result.direction);
} else {
getViewFrustum()->computePickRay(x, y, result.origin, result.direction);
}
}
return result;
}
@ -3133,6 +3138,16 @@ ViewFrustum* Application::getDisplayViewFrustum() {
return &_displayViewFrustum;
}
const ViewFrustum* Application::getDisplayViewFrustum() const {
#ifdef DEBUG
if (QThread::currentThread() != activeRenderingThread) {
// FIXME, should this be an assert?
qWarning() << "Calling Application::getDisplayViewFrustum() from outside the active rendering thread or outside rendering, did you mean Application::getViewFrustum()?";
}
#endif
return &_displayViewFrustum;
}
void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs::RenderSide renderSide) {
activeRenderingThread = QThread::currentThread();
PROFILE_RANGE(__FUNCTION__);
@ -3362,7 +3377,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity(), skyStage->getSunLight()->getAmbientIntensity());
DependencyManager::get<DeferredLightingEffect>()->setGlobalAtmosphere(skyStage->getAtmosphere());
// NOt yet DependencyManager::get<DeferredLightingEffect>()->setGlobalSkybox(skybox);
DependencyManager::get<DeferredLightingEffect>()->setGlobalSkybox(skybox);
PROFILE_RANGE("DeferredLighting");
PerformanceTimer perfTimer("lighting");

View file

@ -205,6 +205,7 @@ public:
// which might be different from the viewFrustum, i.e. shadowmap
// passes, mirror window passes, etc
ViewFrustum* getDisplayViewFrustum();
const ViewFrustum* getDisplayViewFrustum() const;
ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; }
const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; }
EntityTreeRenderer* getEntities() { return &_entities; }

View file

@ -520,12 +520,6 @@ void OculusManager::display(QGLWidget * glCanvas, const glm::quat &bodyOrientati
return;
}
ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay();
// We only need to render the overlays to a texture once, then we just render the texture on the hemisphere
// PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay()
applicationOverlay.renderOverlay();
//Bind our framebuffer object. If we are rendering the glow effect, we let the glow effect shader take care of it
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) {
DependencyManager::get<GlowEffect>()->prepare();
@ -614,9 +608,8 @@ void OculusManager::display(QGLWidget * glCanvas, const glm::quat &bodyOrientati
//glTranslatef(_eyeRenderDesc[eye].ViewAdjust.x, _eyeRenderDesc[eye].ViewAdjust.y, _eyeRenderDesc[eye].ViewAdjust.z);
_camera->setEyeOffsetPosition(glm::vec3(-_eyeRenderDesc[eye].HmdToEyeViewOffset.x, -_eyeRenderDesc[eye].HmdToEyeViewOffset.y, -_eyeRenderDesc[eye].HmdToEyeViewOffset.z));
Application::getInstance()->displaySide(*_camera, false, RenderArgs::MONO);
applicationOverlay.displayOverlayTextureHmd(*_camera);
qApp->displaySide(*_camera, false, RenderArgs::MONO);
qApp->getApplicationOverlay().displayOverlayTextureHmd(*_camera);
});
_activeEye = ovrEye_Count;

View file

@ -92,74 +92,40 @@ void TV3DManager::display(Camera& whichCamera) {
int portalW = deviceSize.width() / 2;
int portalH = deviceSize.height();
ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay();
// We only need to render the overlays to a texture once, then we just render the texture as a quad
// PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay()
applicationOverlay.renderOverlay();
DependencyManager::get<GlowEffect>()->prepare();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_SCISSOR_TEST);
// render left side view
glViewport(portalX, portalY, portalW, portalH);
glScissor(portalX, portalY, portalW, portalH);
Camera eyeCamera;
eyeCamera.setRotation(whichCamera.getRotation());
eyeCamera.setPosition(whichCamera.getPosition());
glEnable(GL_SCISSOR_TEST);
glPushMatrix();
{
_activeEye = &_leftEye;
forEachEye([&](eyeFrustum& eye){
_activeEye = &eye;
glViewport(portalX, portalY, portalW, portalH);
glScissor(portalX, portalY, portalW, portalH);
glMatrixMode(GL_PROJECTION);
glLoadIdentity(); // reset projection matrix
glFrustum(_leftEye.left, _leftEye.right, _leftEye.bottom, _leftEye.top, nearZ, farZ); // set left view frustum
glFrustum(eye.left, eye.right, eye.bottom, eye.top, nearZ, farZ); // set left view frustum
GLfloat p[4][4];
// Really?
glGetFloatv(GL_PROJECTION_MATRIX, &(p[0][0]));
float cotangent = p[1][1];
GLfloat fov = atan(1.0f / cotangent);
glTranslatef(_leftEye.modelTranslation, 0.0, 0.0); // translate to cancel parallax
glTranslatef(eye.modelTranslation, 0.0, 0.0); // translate to cancel parallax
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
eyeCamera.setEyeOffsetPosition(glm::vec3(-_activeEye->modelTranslation,0,0));
Application::getInstance()->displaySide(eyeCamera, false, RenderArgs::MONO);
applicationOverlay.displayOverlayTextureStereo(whichCamera, _aspect, fov);
qApp->displaySide(eyeCamera, false, RenderArgs::MONO);
qApp->getApplicationOverlay().displayOverlayTextureStereo(whichCamera, _aspect, fov);
_activeEye = NULL;
}
glPopMatrix();
glDisable(GL_SCISSOR_TEST);
// render right side view
portalX = deviceSize.width() / 2;
glEnable(GL_SCISSOR_TEST);
// render left side view
glViewport(portalX, portalY, portalW, portalH);
glScissor(portalX, portalY, portalW, portalH);
glPushMatrix();
{
_activeEye = &_rightEye;
glMatrixMode(GL_PROJECTION);
glLoadIdentity(); // reset projection matrix
glFrustum(_rightEye.left, _rightEye.right, _rightEye.bottom, _rightEye.top, nearZ, farZ); // set right view frustum
GLfloat p[4][4];
glGetFloatv(GL_PROJECTION_MATRIX, &(p[0][0]));
GLfloat cotangent = p[1][1];
GLfloat fov = atan(1.0f / cotangent);
glTranslatef(_rightEye.modelTranslation, 0.0, 0.0); // translate to cancel parallax
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
eyeCamera.setEyeOffsetPosition(glm::vec3(-_activeEye->modelTranslation,0,0));
Application::getInstance()->displaySide(eyeCamera, false, RenderArgs::MONO);
applicationOverlay.displayOverlayTextureStereo(whichCamera, _aspect, fov);
_activeEye = NULL;
}
}, [&]{
// render right side view
portalX = deviceSize.width() / 2;
});
glPopMatrix();
glDisable(GL_SCISSOR_TEST);
@ -167,11 +133,13 @@ void TV3DManager::display(Camera& whichCamera) {
auto fboSize = finalFbo->getSize();
// Get the ACTUAL device size for the BLIT
deviceSize = qApp->getDeviceSize();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo));
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, fboSize.x, fboSize.y,
0, 0, deviceSize.width(), deviceSize.height(),
GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
// reset the viewport to how we started
glViewport(0, 0, deviceSize.width(), deviceSize.height());

View file

@ -44,6 +44,20 @@ private:
static eyeFrustum _leftEye;
static eyeFrustum _rightEye;
static eyeFrustum* _activeEye;
// The first function is the code executed for each eye
// while the second is code to be executed between the two eyes.
// The use case here is to modify the output viewport coordinates
// for the new eye.
// FIXME: we'd like to have a default empty lambda for the second parameter,
// but gcc 4.8.1 complains about it due to a bug. See
// http://stackoverflow.com/questions/25490662/lambda-as-default-parameter-to-a-member-function-template
template<typename F, typename FF>
static void forEachEye(F f, FF ff) {
f(_leftEye);
ff();
f(_rightEye);
}
};
#endif // hifi_TV3DManager_h

View file

@ -15,7 +15,6 @@
#include <Application.h>
#include <avatar/AvatarManager.h>
#include <devices/OculusManager.h>
#include <LODManager.h>
#include "BillboardOverlay.h"
@ -292,8 +291,8 @@ void Overlays::deleteOverlay(unsigned int id) {
unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {
glm::vec2 pointCopy = point;
if (OculusManager::isConnected()) {
pointCopy = Application::getInstance()->getApplicationOverlay().screenToOverlay(point);
if (qApp->isHMDMode()) {
pointCopy = qApp->getApplicationOverlay().screenToOverlay(point);
}
QReadLocker lock(&_lock);

View file

@ -26,6 +26,7 @@
#include <SceneScriptingInterface.h>
#include <ScriptEngine.h>
#include <TextureCache.h>
#include <SoundCache.h>
#include "EntityTreeRenderer.h"
@ -46,6 +47,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
_wantScripts(wantScripts),
_entitiesScriptEngine(NULL),
_sandboxScriptEngine(NULL),
_localAudioInterface(NULL),
_lastMouseEventValid(false),
_viewState(viewState),
_scriptingServices(scriptingServices),
@ -848,9 +850,18 @@ RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(cons
}
void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityScriptingInterface) {
connect(this, &EntityTreeRenderer::mousePressOnEntity, entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity);
connect(this, &EntityTreeRenderer::mouseMoveOnEntity, entityScriptingInterface, &EntityScriptingInterface::mouseMoveOnEntity);
connect(this, &EntityTreeRenderer::mouseReleaseOnEntity, entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity);
connect(this, &EntityTreeRenderer::mousePressOnEntity, entityScriptingInterface,
[=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId){
entityScriptingInterface->mousePressOnEntity(intersection.entityID, MouseEvent(*event, deviceId));
});
connect(this, &EntityTreeRenderer::mouseMoveOnEntity, entityScriptingInterface,
[=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId) {
entityScriptingInterface->mouseMoveOnEntity(intersection.entityID, MouseEvent(*event, deviceId));
});
connect(this, &EntityTreeRenderer::mouseReleaseOnEntity, entityScriptingInterface,
[=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId) {
entityScriptingInterface->mouseReleaseOnEntity(intersection.entityID, MouseEvent(*event, deviceId));
});
connect(this, &EntityTreeRenderer::clickDownOnEntity, entityScriptingInterface, &EntityScriptingInterface::clickDownOnEntity);
connect(this, &EntityTreeRenderer::holdingClickOnEntity, entityScriptingInterface, &EntityScriptingInterface::holdingClickOnEntity);
@ -898,7 +909,7 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event, unsigned int device
RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking);
if (rayPickResult.intersects) {
//qCDebug(entitiesrenderer) << "mousePressEvent over entity:" << rayPickResult.entityID;
emit mousePressOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID));
emit mousePressOnEntity(rayPickResult, event, deviceID);
QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID);
QScriptValue entityScript = loadEntityScript(rayPickResult.entity);
@ -928,7 +939,7 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event, unsigned int devi
RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking);
if (rayPickResult.intersects) {
//qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID;
emit mouseReleaseOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID));
emit mouseReleaseOnEntity(rayPickResult, event, deviceID);
QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID);
QScriptValue entityScript = loadEntityScript(rayPickResult.entity);
@ -977,7 +988,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI
}
//qCDebug(entitiesrenderer) << "mouseMoveEvent over entity:" << rayPickResult.entityID;
emit mouseMoveOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID));
emit mouseMoveOnEntity(rayPickResult, event, deviceID);
if (entityScript.property("mouseMoveOnEntity").isValid()) {
entityScript.property("mouseMoveOnEntity").call(entityScript, entityScriptArgs);
}
@ -1098,13 +1109,84 @@ void EntityTreeRenderer::changingEntityID(const EntityItemID& oldEntityID, const
}
}
void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB,
void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision) {
EntityItem* entity = entityTree->findEntityByEntityItemID(id);
QUuid simulatorID = entity->getSimulatorID();
if (simulatorID.isNull() || (simulatorID != myNodeID)) {
return; // Only one injector per simulation, please.
}
const QString& collisionSoundURL = entity->getCollisionSoundURL();
if (collisionSoundURL.isEmpty()) {
return;
}
const float mass = entity->computeMass();
const float COLLISION_PENTRATION_TO_VELOCITY = 50; // as a subsitute for RELATIVE entity->getVelocity()
const float linearVelocity = glm::length(collision.penetration) * COLLISION_PENTRATION_TO_VELOCITY;
const float energy = mass * linearVelocity * linearVelocity / 2.0f;
const glm::vec3 position = collision.contactPoint;
const float COLLISION_ENERGY_AT_FULL_VOLUME = 1.0f;
const float COLLISION_MINIMUM_VOLUME = 0.001f;
const float energyFactorOfFull = fmin(1.0f, energy / COLLISION_ENERGY_AT_FULL_VOLUME);
if (energyFactorOfFull < COLLISION_MINIMUM_VOLUME) {
return;
}
SharedSoundPointer sound = DependencyManager::get<SoundCache>().data()->getSound(QUrl(collisionSoundURL));
if (!sound->isReady()) {
return;
}
// This is a hack. Quiet sound aren't really heard at all, so we compress everything to the range [1-c, 1], if we play it all.
const float COLLISION_SOUND_COMPRESSION_RANGE = 0.95f;
float volume = energyFactorOfFull;
volume = (volume * COLLISION_SOUND_COMPRESSION_RANGE) + (1.0f - COLLISION_SOUND_COMPRESSION_RANGE);
// This is quite similar to AudioScriptingInterface::playSound() and should probably be refactored.
AudioInjectorOptions options;
options.stereo = sound->isStereo();
options.position = position;
options.volume = volume;
AudioInjector* injector = new AudioInjector(sound.data(), options);
injector->setLocalAudioInterface(_localAudioInterface);
QThread* injectorThread = new QThread();
injectorThread->setObjectName("Audio Injector Thread");
injector->moveToThread(injectorThread);
// start injecting when the injector thread starts
connect(injectorThread, &QThread::started, injector, &AudioInjector::injectAudio);
// connect the right slots and signals for AudioInjector and thread cleanup
connect(injector, &AudioInjector::destroyed, injectorThread, &QThread::quit);
connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater);
injectorThread->start();
}
void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB,
const Collision& collision) {
// If we don't have a tree, or we're in the process of shutting down, then don't
// process these events.
if (!_tree || _shuttingDown) {
return;
}
// Don't respond to small continuous contacts. It causes deadlocks when locking the entityTree.
// Note that any entity script is likely to Entities.getEntityProperties(), which locks the tree.
const float COLLISION_MINUMUM_PENETRATION = 0.001;
if ((collision.type != CONTACT_EVENT_TYPE_START) && (glm::length(collision.penetration) < COLLISION_MINUMUM_PENETRATION)) {
return;
}
// See if we should play sounds
EntityTree* entityTree = static_cast<EntityTree*>(_tree);
if (!entityTree->tryLockForRead()) {
// I don't know why this can happen, but if it does,
// the consequences are a deadlock, so bail.
qCDebug(entitiesrenderer) << "NOTICE: skipping collision type " << collision.type << " penetration " << glm::length(collision.penetration);
return;
}
const QUuid& myNodeID = DependencyManager::get<NodeList>()->getSessionUUID();
playEntityCollisionSound(myNodeID, entityTree, idA, collision);
playEntityCollisionSound(myNodeID, entityTree, idB, collision);
entityTree->unlock();
// And now the entity scripts
QScriptValue entityScriptA = loadEntityScript(idA);
if (entityScriptA.property("collisionWithEntity").isValid()) {
QScriptValueList args;

View file

@ -20,6 +20,7 @@
#include <MouseEvent.h>
#include <OctreeRenderer.h>
#include <ScriptCache.h>
#include <AbstractAudioInterface.h>
class AbstractScriptingServicesInterface;
class AbstractViewStateInterface;
@ -92,9 +93,9 @@ public:
virtual void errorInLoadingScript(const QUrl& url);
signals:
void mousePressOnEntity(const EntityItemID& entityItemID, const MouseEvent& event);
void mouseMoveOnEntity(const EntityItemID& entityItemID, const MouseEvent& event);
void mouseReleaseOnEntity(const EntityItemID& entityItemID, const MouseEvent& event);
void mousePressOnEntity(const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId);
void mouseMoveOnEntity(const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId);
void mouseReleaseOnEntity(const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId);
void clickDownOnEntity(const EntityItemID& entityItemID, const MouseEvent& event);
void holdingClickOnEntity(const EntityItemID& entityItemID, const MouseEvent& event);
@ -155,6 +156,9 @@ private:
QHash<EntityItemID, EntityScriptDetails> _entityScripts;
void playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision);
AbstractAudioInterface* _localAudioInterface; // So we can render collision sounds
bool _lastMouseEventValid;
MouseEvent _lastMouseEvent;
AbstractViewStateInterface* _viewState;

View file

@ -23,6 +23,8 @@
#include <TextureCache.h>
#include <gpu/GLBackend.h>
#include "EntityTreeRenderer.h"
const int FIXED_FONT_POINT_SIZE = 40;
const float DPI = 30.47;
const float METERS_TO_INCHES = 39.3701;
@ -63,6 +65,7 @@ RenderableWebEntityItem::~RenderableWebEntityItem() {
void RenderableWebEntityItem::render(RenderArgs* args) {
QOpenGLContext * currentContext = QOpenGLContext::currentContext();
QSurface * currentSurface = currentContext->surface();
if (!_webSurface) {
_webSurface = new OffscreenQmlSurface();
_webSurface->create(currentContext);
@ -89,6 +92,52 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
_webSurface->doneCurrent();
}
});
auto forwardMouseEvent = [=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId) {
// Ignore mouse interaction if we're locked
if (this->getLocked()) {
return;
}
if (intersection.entityID.id == getID()) {
if (event->button() == Qt::MouseButton::RightButton) {
if (event->type() == QEvent::MouseButtonRelease) {
AbstractViewStateInterface::instance()->postLambdaEvent([this] {
QMetaObject::invokeMethod(_webSurface->getRootItem(), "goBack");
});
}
return;
}
if (event->button() == Qt::MouseButton::MiddleButton) {
if (event->type() == QEvent::MouseButtonRelease) {
AbstractViewStateInterface::instance()->postLambdaEvent([this] {
_webSurface->getRootItem()->setProperty("url", _sourceUrl);
});
}
return;
}
// Map the intersection point to an actual offscreen pixel
glm::vec3 point = intersection.intersection;
point -= getPosition();
point = glm::inverse(getRotation()) * point;
point /= _dimensions;
point += 0.5f;
point.y = 1.0f - point.y;
point *= _dimensions * METERS_TO_INCHES * DPI;
// Forward the mouse event.
QMouseEvent mappedEvent(event->type(),
QPoint((int)point.x, (int)point.y),
event->screenPos(), event->button(),
event->buttons(), event->modifiers());
QCoreApplication::sendEvent(_webSurface->getWindow(), &mappedEvent);
}
};
EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(args->_renderer);
QObject::connect(renderer, &EntityTreeRenderer::mousePressOnEntity, forwardMouseEvent);
QObject::connect(renderer, &EntityTreeRenderer::mouseReleaseOnEntity, forwardMouseEvent);
QObject::connect(renderer, &EntityTreeRenderer::mouseMoveOnEntity, forwardMouseEvent);
}
glm::vec2 dims = glm::vec2(_dimensions);
@ -106,8 +155,6 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
glm::vec3 halfDimensions = dimensions / 2.0f;
glm::quat rotation = getRotation();
//qCDebug(entitytree) << "RenderableWebEntityItem::render() id:" << getEntityItemID() << "text:" << getText();
glPushMatrix();
{
glTranslatef(position.x, position.y, position.z);

View file

@ -33,23 +33,23 @@ AtmospherePropertyGroup::AtmospherePropertyGroup() {
}
void AtmospherePropertyGroup::copyToScriptValue(QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_VEC3(Atmosphere, atmosphere, Center, center);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, Center, center);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, InnerRadius, innerRadius);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, OuterRadius, outerRadius);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, MieScattering, mieScattering);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, RayleighScattering, rayleighScattering);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_VEC3(Atmosphere, atmosphere, ScatteringWavelengths, scatteringWavelengths);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, ScatteringWavelengths, scatteringWavelengths);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, HasStars, hasStars);
}
void AtmospherePropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) {
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_VEC3(atmosphere, center, setCenter);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(atmosphere, innerRadius, setInnerRadius);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(atmosphere, outerRadius, setOuterRadius);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(atmosphere, mieScattering, setMieScattering);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(atmosphere, rayleighScattering, setRayleighScattering);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_VEC3(atmosphere, scatteringWavelengths, setScatteringWavelengths);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_BOOL(atmosphere, hasStars, setHasStars);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(atmosphere, center, glmVec3, setCenter);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(atmosphere, innerRadius, float, setInnerRadius);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(atmosphere, outerRadius, float, setOuterRadius);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(atmosphere, mieScattering, float, setMieScattering);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(atmosphere, rayleighScattering, float, setRayleighScattering);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(atmosphere, scatteringWavelengths, glmVec3, setScatteringWavelengths);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(atmosphere, hasStars, bool, setHasStars);
}
void AtmospherePropertyGroup::debugDump() const {
@ -72,13 +72,13 @@ bool AtmospherePropertyGroup::appentToEditPacket(OctreePacketData* packetData,
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_CENTER, appendValue, getCenter());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_INNER_RADIUS, appendValue, getInnerRadius());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_OUTER_RADIUS, appendValue, getOuterRadius());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_MIE_SCATTERING, appendValue, getMieScattering());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_RAYLEIGH_SCATTERING, appendValue, getRayleighScattering());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_SCATTERING_WAVELENGTHS, appendValue, getScatteringWavelengths());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_HAS_STARS, appendValue, getHasStars());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_CENTER, getCenter());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_INNER_RADIUS, getInnerRadius());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_OUTER_RADIUS, getOuterRadius());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_MIE_SCATTERING, getMieScattering());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_RAYLEIGH_SCATTERING, getRayleighScattering());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_SCATTERING_WAVELENGTHS, getScatteringWavelengths());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_HAS_STARS, getHasStars());
return true;
}
@ -89,13 +89,13 @@ bool AtmospherePropertyGroup::decodeFromEditPacket(EntityPropertyFlags& property
int bytesRead = 0;
bool overwriteLocalData = true;
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_CENTER, glm::vec3, _center);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_INNER_RADIUS, float, _innerRadius);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_OUTER_RADIUS, float, _outerRadius);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_MIE_SCATTERING, float, _mieScattering);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_RAYLEIGH_SCATTERING, float, _rayleighScattering);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_SCATTERING_WAVELENGTHS, glm::vec3, _scatteringWavelengths);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_HAS_STARS, bool, _hasStars);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_CENTER, glm::vec3, setCenter);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_INNER_RADIUS, float, setInnerRadius);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_OUTER_RADIUS, float, setOuterRadius);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_MIE_SCATTERING, float, setMieScattering);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_RAYLEIGH_SCATTERING, float, setRayleighScattering);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_SCATTERING_WAVELENGTHS, glm::vec3, setScatteringWavelengths);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_HAS_STARS, bool, setHasStars);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ATMOSPHERE_CENTER, Center);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ATMOSPHERE_INNER_RADIUS, InnerRadius);
@ -183,13 +183,13 @@ void AtmospherePropertyGroup::appendSubclassData(OctreePacketData* packetData, E
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_CENTER, appendValue, getCenter());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_INNER_RADIUS, appendValue, getInnerRadius());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_OUTER_RADIUS, appendValue, getOuterRadius());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_MIE_SCATTERING, appendValue, getMieScattering());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_RAYLEIGH_SCATTERING, appendValue, getRayleighScattering());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_SCATTERING_WAVELENGTHS, appendValue, getScatteringWavelengths());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_HAS_STARS, appendValue, getHasStars());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_CENTER, getCenter());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_INNER_RADIUS, getInnerRadius());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_OUTER_RADIUS, getOuterRadius());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_MIE_SCATTERING, getMieScattering());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_RAYLEIGH_SCATTERING, getRayleighScattering());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_SCATTERING_WAVELENGTHS, getScatteringWavelengths());
APPEND_ENTITY_PROPERTY(PROP_ATMOSPHERE_HAS_STARS, getHasStars());
}
int AtmospherePropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
@ -199,13 +199,13 @@ int AtmospherePropertyGroup::readEntitySubclassDataFromBuffer(const unsigned cha
int bytesRead = 0;
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_CENTER, glm::vec3, _center);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_INNER_RADIUS, float, _innerRadius);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_OUTER_RADIUS, float, _outerRadius);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_MIE_SCATTERING, float, _mieScattering);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_RAYLEIGH_SCATTERING, float, _rayleighScattering);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_SCATTERING_WAVELENGTHS, glm::vec3, _scatteringWavelengths);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_HAS_STARS, bool, _hasStars);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_CENTER, glm::vec3, setCenter);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_INNER_RADIUS, float, setInnerRadius);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_OUTER_RADIUS, float, setOuterRadius);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_MIE_SCATTERING, float, setMieScattering);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_RAYLEIGH_SCATTERING, float, setRayleighScattering);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_SCATTERING_WAVELENGTHS, glm::vec3, setScatteringWavelengths);
READ_ENTITY_PROPERTY(PROP_ATMOSPHERE_HAS_STARS, bool, setHasStars);
return bytesRead;
}

View file

@ -71,7 +71,7 @@ int BoxEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, i
int bytesRead = 0;
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color);
READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor);
return bytesRead;
}
@ -94,7 +94,7 @@ void BoxEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitst
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor());
APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor());
}
void BoxEntityItem::debugDump() const {

View file

@ -19,6 +19,7 @@
#include <PhysicsHelpers.h>
#include <RegisteredMetaTypes.h>
#include <SharedUtil.h> // usecTimestampNow()
#include <SoundCache.h>
#include "EntityScriptingInterface.h"
#include "EntityItem.h"
@ -50,8 +51,11 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) :
_gravity(ENTITY_ITEM_DEFAULT_GRAVITY),
_acceleration(ENTITY_ITEM_DEFAULT_ACCELERATION),
_damping(ENTITY_ITEM_DEFAULT_DAMPING),
_restitution(ENTITY_ITEM_DEFAULT_RESTITUTION),
_friction(ENTITY_ITEM_DEFAULT_FRICTION),
_lifetime(ENTITY_ITEM_DEFAULT_LIFETIME),
_script(ENTITY_ITEM_DEFAULT_SCRIPT),
_collisionSoundURL(ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL),
_registrationPoint(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT),
_angularVelocity(ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY),
_angularDamping(ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING),
@ -98,8 +102,11 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
requestedProperties += PROP_GRAVITY;
requestedProperties += PROP_ACCELERATION;
requestedProperties += PROP_DAMPING;
requestedProperties += PROP_RESTITUTION;
requestedProperties += PROP_FRICTION;
requestedProperties += PROP_LIFETIME;
requestedProperties += PROP_SCRIPT;
requestedProperties += PROP_COLLISION_SOUND_URL;
requestedProperties += PROP_REGISTRATION_POINT;
requestedProperties += PROP_ANGULAR_VELOCITY;
requestedProperties += PROP_ANGULAR_DAMPING;
@ -216,27 +223,30 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
// PROP_PAGED_PROPERTY,
// PROP_CUSTOM_PROPERTIES_INCLUDED,
APPEND_ENTITY_PROPERTY(PROP_POSITION, appendPosition, getPosition());
APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, appendValue, getDimensions()); // NOTE: PROP_RADIUS obsolete
APPEND_ENTITY_PROPERTY(PROP_ROTATION, appendValue, getRotation());
APPEND_ENTITY_PROPERTY(PROP_DENSITY, appendValue, getDensity());
APPEND_ENTITY_PROPERTY(PROP_VELOCITY, appendValue, getVelocity());
APPEND_ENTITY_PROPERTY(PROP_GRAVITY, appendValue, getGravity());
APPEND_ENTITY_PROPERTY(PROP_ACCELERATION, appendValue, getAcceleration());
APPEND_ENTITY_PROPERTY(PROP_DAMPING, appendValue, getDamping());
APPEND_ENTITY_PROPERTY(PROP_LIFETIME, appendValue, getLifetime());
APPEND_ENTITY_PROPERTY(PROP_SCRIPT, appendValue, getScript());
APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, appendValue, getRegistrationPoint());
APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, appendValue, getAngularVelocity());
APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, appendValue, getAngularDamping());
APPEND_ENTITY_PROPERTY(PROP_VISIBLE, appendValue, getVisible());
APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, appendValue, getIgnoreForCollisions());
APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, appendValue, getCollisionsWillMove());
APPEND_ENTITY_PROPERTY(PROP_LOCKED, appendValue, getLocked());
APPEND_ENTITY_PROPERTY(PROP_USER_DATA, appendValue, getUserData());
APPEND_ENTITY_PROPERTY(PROP_SIMULATOR_ID, appendValue, getSimulatorID());
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, appendValue, getMarketplaceID());
APPEND_ENTITY_PROPERTY(PROP_NAME, appendValue, getName());
APPEND_ENTITY_PROPERTY(PROP_POSITION, getPosition());
APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, getDimensions()); // NOTE: PROP_RADIUS obsolete
APPEND_ENTITY_PROPERTY(PROP_ROTATION, getRotation());
APPEND_ENTITY_PROPERTY(PROP_DENSITY, getDensity());
APPEND_ENTITY_PROPERTY(PROP_VELOCITY, getVelocity());
APPEND_ENTITY_PROPERTY(PROP_GRAVITY, getGravity());
APPEND_ENTITY_PROPERTY(PROP_ACCELERATION, getAcceleration());
APPEND_ENTITY_PROPERTY(PROP_DAMPING, getDamping());
APPEND_ENTITY_PROPERTY(PROP_RESTITUTION, getRestitution());
APPEND_ENTITY_PROPERTY(PROP_FRICTION, getFriction());
APPEND_ENTITY_PROPERTY(PROP_LIFETIME, getLifetime());
APPEND_ENTITY_PROPERTY(PROP_SCRIPT, getScript());
APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, getRegistrationPoint());
APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, getAngularVelocity());
APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, getAngularDamping());
APPEND_ENTITY_PROPERTY(PROP_VISIBLE, getVisible());
APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, getIgnoreForCollisions());
APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, getCollisionsWillMove());
APPEND_ENTITY_PROPERTY(PROP_LOCKED, getLocked());
APPEND_ENTITY_PROPERTY(PROP_USER_DATA, getUserData());
APPEND_ENTITY_PROPERTY(PROP_SIMULATOR_ID, getSimulatorID());
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, getMarketplaceID());
APPEND_ENTITY_PROPERTY(PROP_NAME, getName());
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, getCollisionSoundURL());
appendSubclassData(packetData, params, entityTreeElementExtraEncodeData,
requestedProperties,
@ -511,9 +521,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
bytesRead += propertyFlags.getEncodedLength();
bool useMeters = (args.bitstreamVersion >= VERSION_ENTITIES_USE_METERS_AND_RADIANS);
if (useMeters) {
READ_ENTITY_PROPERTY_SETTER(PROP_POSITION, glm::vec3, updatePosition);
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition);
} else {
READ_ENTITY_PROPERTY_SETTER(PROP_POSITION, glm::vec3, updatePositionInDomainUnits);
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePositionInDomainUnits);
}
// Old bitstreams had PROP_RADIUS, new bitstreams have PROP_DIMENSIONS
@ -529,51 +539,53 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
}
} else {
if (useMeters) {
READ_ENTITY_PROPERTY_SETTER(PROP_DIMENSIONS, glm::vec3, updateDimensions);
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions);
} else {
READ_ENTITY_PROPERTY_SETTER(PROP_DIMENSIONS, glm::vec3, updateDimensionsInDomainUnits);
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensionsInDomainUnits);
}
}
READ_ENTITY_PROPERTY_QUAT_SETTER(PROP_ROTATION, updateRotation);
READ_ENTITY_PROPERTY_SETTER(PROP_DENSITY, float, updateDensity);
READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation);
READ_ENTITY_PROPERTY(PROP_DENSITY, float, updateDensity);
if (useMeters) {
READ_ENTITY_PROPERTY_SETTER(PROP_VELOCITY, glm::vec3, updateVelocity);
READ_ENTITY_PROPERTY_SETTER(PROP_GRAVITY, glm::vec3, updateGravity);
READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocity);
READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravity);
} else {
READ_ENTITY_PROPERTY_SETTER(PROP_VELOCITY, glm::vec3, updateVelocityInDomainUnits);
READ_ENTITY_PROPERTY_SETTER(PROP_GRAVITY, glm::vec3, updateGravityInDomainUnits);
READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocityInDomainUnits);
READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravityInDomainUnits);
}
if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION) {
READ_ENTITY_PROPERTY_SETTER(PROP_ACCELERATION, glm::vec3, setAcceleration);
READ_ENTITY_PROPERTY(PROP_ACCELERATION, glm::vec3, setAcceleration);
}
READ_ENTITY_PROPERTY(PROP_DAMPING, float, _damping);
READ_ENTITY_PROPERTY_SETTER(PROP_LIFETIME, float, updateLifetime);
READ_ENTITY_PROPERTY_STRING(PROP_SCRIPT, setScript);
READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, _registrationPoint);
READ_ENTITY_PROPERTY(PROP_DAMPING, float, updateDamping);
READ_ENTITY_PROPERTY(PROP_RESTITUTION, float, updateRestitution);
READ_ENTITY_PROPERTY(PROP_FRICTION, float, updateFriction);
READ_ENTITY_PROPERTY(PROP_LIFETIME, float, updateLifetime);
READ_ENTITY_PROPERTY(PROP_SCRIPT, QString, setScript);
READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint);
if (useMeters) {
READ_ENTITY_PROPERTY_SETTER(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity);
READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity);
} else {
READ_ENTITY_PROPERTY_SETTER(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocityInDegrees);
READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocityInDegrees);
}
READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, _angularDamping);
READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, _visible);
READ_ENTITY_PROPERTY_SETTER(PROP_IGNORE_FOR_COLLISIONS, bool, updateIgnoreForCollisions);
READ_ENTITY_PROPERTY_SETTER(PROP_COLLISIONS_WILL_MOVE, bool, updateCollisionsWillMove);
READ_ENTITY_PROPERTY(PROP_LOCKED, bool, _locked);
READ_ENTITY_PROPERTY_STRING(PROP_USER_DATA, setUserData);
READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, updateAngularDamping);
READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible);
READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, updateIgnoreForCollisions);
READ_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, bool, updateCollisionsWillMove);
READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked);
READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData);
if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION) {
READ_ENTITY_PROPERTY_UUID(PROP_SIMULATOR_ID, setSimulatorID);
READ_ENTITY_PROPERTY(PROP_SIMULATOR_ID, QUuid, updateSimulatorID);
}
if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_MARKETPLACE_ID) {
READ_ENTITY_PROPERTY_STRING(PROP_MARKETPLACE_ID, setMarketplaceID);
READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
}
READ_ENTITY_PROPERTY_STRING(PROP_NAME, setName);
READ_ENTITY_PROPERTY(PROP_NAME, QString, setName);
READ_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData);
////////////////////////////////////
@ -584,7 +596,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
//
// TODO: Remove this conde once we've sufficiently migrated content past this damaged version
if (args.bitstreamVersion == VERSION_ENTITIES_HAS_MARKETPLACE_ID_DAMAGED) {
READ_ENTITY_PROPERTY_STRING(PROP_MARKETPLACE_ID, setMarketplaceID);
READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
}
if (overwriteLocalData && (getDirtyFlags() & (EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES))) {
@ -693,17 +705,6 @@ void EntityItem::setMass(float mass) {
}
}
const float DEFAULT_ENTITY_RESTITUTION = 0.5f;
const float DEFAULT_ENTITY_FRICTION = 0.5f;
float EntityItem::getRestitution() const {
return DEFAULT_ENTITY_RESTITUTION;
}
float EntityItem::getFriction() const {
return DEFAULT_ENTITY_FRICTION;
}
void EntityItem::simulate(const quint64& now) {
if (_lastSimulated == 0) {
_lastSimulated = now;
@ -896,8 +897,11 @@ EntityItemProperties EntityItem::getProperties() const {
COPY_ENTITY_PROPERTY_TO_PROPERTIES(gravity, getGravity);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(acceleration, getAcceleration);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(damping, getDamping);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(restitution, getRestitution);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(friction, getFriction);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lifetime, getLifetime);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(script, getScript);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionSoundURL, getCollisionSoundURL);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(registrationPoint, getRegistrationPoint);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(angularVelocity, getAngularVelocity);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(angularDamping, getAngularDamping);
@ -928,8 +932,11 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, updateGravity);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(acceleration, setAcceleration);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(damping, updateDamping);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(restitution, updateRestitution);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(friction, updateFriction);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, updateLifetime);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionSoundURL, setCollisionSoundURL);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularVelocity, updateAngularVelocity);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularDamping, updateAngularDamping);
@ -940,7 +947,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, updateCollisionsWillMove);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(locked, setLocked);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(userData, setUserData);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulatorID, setSimulatorID);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulatorID, updateSimulatorID);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(marketplaceID, setMarketplaceID);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(name, setName);
@ -1185,16 +1192,16 @@ void EntityItem::updateVelocityInDomainUnits(const glm::vec3& value) {
void EntityItem::updateVelocity(const glm::vec3& value) {
auto delta = glm::distance(_velocity, value);
if (delta > IGNORE_LINEAR_VELOCITY_DELTA) {
_dirtyFlags |= EntityItem::DIRTY_LINEAR_VELOCITY;
const float MIN_LINEAR_SPEED = 0.001f;
if (glm::length(value) < MIN_LINEAR_SPEED) {
_velocity = ENTITY_ITEM_ZERO_VEC3;
} else {
_velocity = value;
}
_dirtyFlags |= EntityItem::DIRTY_LINEAR_VELOCITY;
if (delta > ACTIVATION_LINEAR_VELOCITY_DELTA) {
_dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION;
// only activate when setting non-zero velocity
if (delta > ACTIVATION_LINEAR_VELOCITY_DELTA) {
_dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION;
}
}
}
}
@ -1232,9 +1239,10 @@ void EntityItem::updateAngularVelocity(const glm::vec3& value) {
_angularVelocity = ENTITY_ITEM_ZERO_VEC3;
} else {
_angularVelocity = value;
}
if (delta > ACTIVATION_ANGULAR_VELOCITY_DELTA) {
_dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION;
// only activate when setting non-zero velocity
if (delta > ACTIVATION_ANGULAR_VELOCITY_DELTA) {
_dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION;
}
}
}
}
@ -1261,6 +1269,32 @@ void EntityItem::updateCollisionsWillMove(bool value) {
}
}
void EntityItem::updateRestitution(float value) {
float clampedValue = glm::max(glm::min(ENTITY_ITEM_MAX_RESTITUTION, value), ENTITY_ITEM_MIN_RESTITUTION);
if (_restitution != clampedValue) {
_restitution = clampedValue;
_dirtyFlags |= EntityItem::DIRTY_MATERIAL;
}
}
void EntityItem::updateFriction(float value) {
float clampedValue = glm::max(glm::min(ENTITY_ITEM_MAX_FRICTION, value), ENTITY_ITEM_MIN_FRICTION);
if (_friction != clampedValue) {
_friction = clampedValue;
_dirtyFlags |= EntityItem::DIRTY_MATERIAL;
}
}
void EntityItem::setRestitution(float value) {
float clampedValue = glm::max(glm::min(ENTITY_ITEM_MAX_RESTITUTION, value), ENTITY_ITEM_MIN_RESTITUTION);
_restitution = clampedValue;
}
void EntityItem::setFriction(float value) {
float clampedValue = glm::max(glm::min(ENTITY_ITEM_MAX_FRICTION, value), ENTITY_ITEM_MIN_FRICTION);
_friction = clampedValue;
}
void EntityItem::updateLifetime(float value) {
if (_lifetime != value) {
_lifetime = value;
@ -1269,8 +1303,14 @@ void EntityItem::updateLifetime(float value) {
}
void EntityItem::setSimulatorID(const QUuid& value) {
_simulatorID = value;
_simulatorIDChangedTime = usecTimestampNow();
}
void EntityItem::updateSimulatorID(const QUuid& value) {
if (_simulatorID != value) {
_simulatorID = value;
_simulatorIDChangedTime = usecTimestampNow();
_dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID;
}
}

View file

@ -82,6 +82,7 @@ public:
DIRTY_UPDATEABLE = 0x0200,
DIRTY_MATERIAL = 0x00400,
DIRTY_PHYSICS_ACTIVATION = 0x0800, // we want to activate the object
DIRTY_SIMULATOR_ID = 0x1000,
DIRTY_TRANSFORM = DIRTY_POSITION | DIRTY_ROTATION,
DIRTY_VELOCITIES = DIRTY_LINEAR_VELOCITY | DIRTY_ANGULAR_VELOCITY
};
@ -221,8 +222,11 @@ public:
float getDamping() const { return _damping; }
void setDamping(float value) { _damping = value; }
float getRestitution() const;
float getFriction() const;
float getRestitution() const { return _restitution; }
void setRestitution(float value);
float getFriction() const { return _friction; }
void setFriction(float value);
// lifetime related properties.
float getLifetime() const { return _lifetime; } /// get the lifetime in seconds for the entity
@ -246,6 +250,8 @@ public:
const QString& getScript() const { return _script; }
void setScript(const QString& value) { _script = value; }
const QString& getCollisionSoundURL() const { return _collisionSoundURL; }
void setCollisionSoundURL(const QString& value) { _collisionSoundURL = value; }
const glm::vec3& getRegistrationPoint() const { return _registrationPoint; } /// registration point as ratio of entity
@ -284,6 +290,7 @@ public:
QUuid getSimulatorID() const { return _simulatorID; }
void setSimulatorID(const QUuid& value);
void updateSimulatorID(const QUuid& value);
quint64 getSimulatorIDChangedTime() const { return _simulatorIDChangedTime; }
const QString& getMarketplaceID() const { return _marketplaceID; }
@ -312,6 +319,8 @@ public:
void updateVelocityInDomainUnits(const glm::vec3& value);
void updateVelocity(const glm::vec3& value);
void updateDamping(float value);
void updateRestitution(float value);
void updateFriction(float value);
void updateGravityInDomainUnits(const glm::vec3& value);
void updateGravity(const glm::vec3& value);
void updateAngularVelocity(const glm::vec3& value);
@ -373,8 +382,11 @@ protected:
glm::vec3 _gravity;
glm::vec3 _acceleration;
float _damping;
float _restitution;
float _friction;
float _lifetime;
QString _script;
QString _collisionSoundURL;
glm::vec3 _registrationPoint;
glm::vec3 _angularVelocity;
float _angularDamping;

View file

@ -44,8 +44,11 @@ EntityItemProperties::EntityItemProperties() :
CONSTRUCT_PROPERTY(gravity, ENTITY_ITEM_DEFAULT_GRAVITY),
CONSTRUCT_PROPERTY(acceleration, ENTITY_ITEM_DEFAULT_ACCELERATION),
CONSTRUCT_PROPERTY(damping, ENTITY_ITEM_DEFAULT_DAMPING),
CONSTRUCT_PROPERTY(restitution, ENTITY_ITEM_DEFAULT_RESTITUTION),
CONSTRUCT_PROPERTY(friction, ENTITY_ITEM_DEFAULT_FRICTION),
CONSTRUCT_PROPERTY(lifetime, ENTITY_ITEM_DEFAULT_LIFETIME),
CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT),
CONSTRUCT_PROPERTY(collisionSoundURL, ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL),
CONSTRUCT_PROPERTY(color, ),
CONSTRUCT_PROPERTY(modelURL, ""),
CONSTRUCT_PROPERTY(compoundShapeURL, ""),
@ -286,8 +289,11 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_GRAVITY, gravity);
CHECK_PROPERTY_CHANGE(PROP_ACCELERATION, acceleration);
CHECK_PROPERTY_CHANGE(PROP_DAMPING, damping);
CHECK_PROPERTY_CHANGE(PROP_RESTITUTION, restitution);
CHECK_PROPERTY_CHANGE(PROP_FRICTION, friction);
CHECK_PROPERTY_CHANGE(PROP_LIFETIME, lifetime);
CHECK_PROPERTY_CHANGE(PROP_SCRIPT, script);
CHECK_PROPERTY_CHANGE(PROP_COLLISION_SOUND_URL, collisionSoundURL);
CHECK_PROPERTY_CHANGE(PROP_COLOR, color);
CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL);
CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL);
@ -350,16 +356,18 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
}
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(type, EntityTypes::getEntityTypeName(_type));
COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(position);
COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(dimensions);
COPY_PROPERTY_TO_QSCRIPTVALUE(position);
COPY_PROPERTY_TO_QSCRIPTVALUE(dimensions);
if (!skipDefaults) {
COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(naturalDimensions); // gettable, but not settable
COPY_PROPERTY_TO_QSCRIPTVALUE(naturalDimensions); // gettable, but not settable
}
COPY_PROPERTY_TO_QSCRIPTVALUE_QUAT(rotation);
COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(velocity);
COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(gravity);
COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(acceleration);
COPY_PROPERTY_TO_QSCRIPTVALUE(rotation);
COPY_PROPERTY_TO_QSCRIPTVALUE(velocity);
COPY_PROPERTY_TO_QSCRIPTVALUE(gravity);
COPY_PROPERTY_TO_QSCRIPTVALUE(acceleration);
COPY_PROPERTY_TO_QSCRIPTVALUE(damping);
COPY_PROPERTY_TO_QSCRIPTVALUE(restitution);
COPY_PROPERTY_TO_QSCRIPTVALUE(friction);
COPY_PROPERTY_TO_QSCRIPTVALUE(density);
COPY_PROPERTY_TO_QSCRIPTVALUE(lifetime);
if (!skipDefaults) {
@ -367,11 +375,11 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(ageAsText, formatSecondsElapsed(getAge())); // gettable, but not settable
}
COPY_PROPERTY_TO_QSCRIPTVALUE(script);
COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(registrationPoint);
COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(angularVelocity);
COPY_PROPERTY_TO_QSCRIPTVALUE(registrationPoint);
COPY_PROPERTY_TO_QSCRIPTVALUE(angularVelocity);
COPY_PROPERTY_TO_QSCRIPTVALUE(angularDamping);
COPY_PROPERTY_TO_QSCRIPTVALUE(visible);
COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR(color);
COPY_PROPERTY_TO_QSCRIPTVALUE(color);
COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(compoundShapeURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL);
@ -393,23 +401,24 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(simulatorID, getSimulatorIDAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(text);
COPY_PROPERTY_TO_QSCRIPTVALUE(lineHeight);
COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(textColor, getTextColor());
COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(backgroundColor, getBackgroundColor());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(textColor, getTextColor());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(backgroundColor, getBackgroundColor());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(shapeType, getShapeTypeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(maxParticles);
COPY_PROPERTY_TO_QSCRIPTVALUE(lifespan);
COPY_PROPERTY_TO_QSCRIPTVALUE(emitRate);
COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(emitDirection);
COPY_PROPERTY_TO_QSCRIPTVALUE(emitDirection);
COPY_PROPERTY_TO_QSCRIPTVALUE(emitStrength);
COPY_PROPERTY_TO_QSCRIPTVALUE(localGravity);
COPY_PROPERTY_TO_QSCRIPTVALUE(particleRadius);
COPY_PROPERTY_TO_QSCRIPTVALUE(marketplaceID);
COPY_PROPERTY_TO_QSCRIPTVALUE(name);
COPY_PROPERTY_TO_QSCRIPTVALUE(collisionSoundURL);
COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR(keyLightColor);
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightColor);
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightIntensity);
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightAmbientIntensity);
COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(keyLightDirection);
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightDirection);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(backgroundMode, getBackgroundModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(sourceUrl);
@ -459,61 +468,64 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
setType(typeScriptValue.toVariant().toString());
}
COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(position, setPosition);
COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(dimensions, setDimensions);
COPY_PROPERTY_FROM_QSCRIPTVALUE_QUAT(rotation, setRotation);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(density, setDensity);
COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(velocity, setVelocity);
COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(gravity, setGravity);
COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(acceleration, setAcceleration);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(damping, setDamping);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(lifetime, setLifetime);
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(script, setScript);
COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(registrationPoint, setRegistrationPoint);
COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(angularVelocity, setAngularVelocity);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(angularDamping, setAngularDamping);
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(visible, setVisible);
COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(color, setColor);
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(modelURL, setModelURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(compoundShapeURL, setCompoundShapeURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(animationURL, setAnimationURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(animationIsPlaying, setAnimationIsPlaying);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(animationFPS, setAnimationFPS);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(animationFrameIndex, setAnimationFrameIndex);
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(animationSettings, setAnimationSettings);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(glowLevel, setGlowLevel);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(localRenderAlpha, setLocalRenderAlpha);
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(ignoreForCollisions, setIgnoreForCollisions);
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(collisionsWillMove, setCollisionsWillMove);
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(isSpotlight, setIsSpotlight);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(intensity, setIntensity);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(exponent, setExponent);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(cutoff, setCutoff);
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(locked, setLocked);
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(textures, setTextures);
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(userData, setUserData);
COPY_PROPERTY_FROM_QSCRIPTVALUE_UUID(simulatorID, setSimulatorID);
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(text, setText);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(lineHeight, setLineHeight);
COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(textColor, setTextColor);
COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(backgroundColor, setBackgroundColor);
COPY_PROPERTY_FROM_QSCRIPTVALUE(position, glmVec3, setPosition);
COPY_PROPERTY_FROM_QSCRIPTVALUE(dimensions, glmVec3, setDimensions);
COPY_PROPERTY_FROM_QSCRIPTVALUE(rotation, glmQuat, setRotation);
COPY_PROPERTY_FROM_QSCRIPTVALUE(density, float, setDensity);
COPY_PROPERTY_FROM_QSCRIPTVALUE(velocity, glmVec3, setVelocity);
COPY_PROPERTY_FROM_QSCRIPTVALUE(gravity, glmVec3, setGravity);
COPY_PROPERTY_FROM_QSCRIPTVALUE(acceleration, glmVec3, setAcceleration);
COPY_PROPERTY_FROM_QSCRIPTVALUE(damping, float, setDamping);
COPY_PROPERTY_FROM_QSCRIPTVALUE(restitution, float, setRestitution);
COPY_PROPERTY_FROM_QSCRIPTVALUE(friction, float, setFriction);
COPY_PROPERTY_FROM_QSCRIPTVALUE(lifetime, float, setLifetime);
COPY_PROPERTY_FROM_QSCRIPTVALUE(script, QString, setScript);
COPY_PROPERTY_FROM_QSCRIPTVALUE(registrationPoint, glmVec3, setRegistrationPoint);
COPY_PROPERTY_FROM_QSCRIPTVALUE(angularVelocity, glmVec3, setAngularVelocity);
COPY_PROPERTY_FROM_QSCRIPTVALUE(angularDamping, float, setAngularDamping);
COPY_PROPERTY_FROM_QSCRIPTVALUE(visible, bool, setVisible);
COPY_PROPERTY_FROM_QSCRIPTVALUE(color, xColor, setColor);
COPY_PROPERTY_FROM_QSCRIPTVALUE(modelURL, QString, setModelURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE(compoundShapeURL, QString, setCompoundShapeURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE(animationURL, QString, setAnimationURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE(animationIsPlaying, bool, setAnimationIsPlaying);
COPY_PROPERTY_FROM_QSCRIPTVALUE(animationFPS, float, setAnimationFPS);
COPY_PROPERTY_FROM_QSCRIPTVALUE(animationFrameIndex, float, setAnimationFrameIndex);
COPY_PROPERTY_FROM_QSCRIPTVALUE(animationSettings, QString, setAnimationSettings);
COPY_PROPERTY_FROM_QSCRIPTVALUE(glowLevel, float, setGlowLevel);
COPY_PROPERTY_FROM_QSCRIPTVALUE(localRenderAlpha, float, setLocalRenderAlpha);
COPY_PROPERTY_FROM_QSCRIPTVALUE(ignoreForCollisions, bool, setIgnoreForCollisions);
COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionsWillMove, bool, setCollisionsWillMove);
COPY_PROPERTY_FROM_QSCRIPTVALUE(isSpotlight, bool, setIsSpotlight);
COPY_PROPERTY_FROM_QSCRIPTVALUE(intensity, float, setIntensity);
COPY_PROPERTY_FROM_QSCRIPTVALUE(exponent, float, setExponent);
COPY_PROPERTY_FROM_QSCRIPTVALUE(cutoff, float, setCutoff);
COPY_PROPERTY_FROM_QSCRIPTVALUE(locked, bool, setLocked);
COPY_PROPERTY_FROM_QSCRIPTVALUE(textures, QString, setTextures);
COPY_PROPERTY_FROM_QSCRIPTVALUE(userData, QString, setUserData);
//COPY_PROPERTY_FROM_QSCRIPTVALUE(simulatorID, QUuid, setSimulatorID); DO NOT accept this info from QScriptValue
COPY_PROPERTY_FROM_QSCRIPTVALUE(text, QString, setText);
COPY_PROPERTY_FROM_QSCRIPTVALUE(lineHeight, float, setLineHeight);
COPY_PROPERTY_FROM_QSCRIPTVALUE(textColor, xColor, setTextColor);
COPY_PROPERTY_FROM_QSCRIPTVALUE(backgroundColor, xColor, setBackgroundColor);
COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(shapeType, ShapeType);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(maxParticles, setMaxParticles);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(lifespan, setLifespan);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(emitRate, setEmitRate);
COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(emitDirection, setEmitDirection);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(emitStrength, setEmitStrength);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(localGravity, setLocalGravity);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(particleRadius, setParticleRadius);
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(marketplaceID, setMarketplaceID);
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(name, setName);
COPY_PROPERTY_FROM_QSCRIPTVALUE(maxParticles, float, setMaxParticles);
COPY_PROPERTY_FROM_QSCRIPTVALUE(lifespan, float, setLifespan);
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitRate, float, setEmitRate);
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitDirection, glmVec3, setEmitDirection);
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitStrength, float, setEmitStrength);
COPY_PROPERTY_FROM_QSCRIPTVALUE(localGravity, float, setLocalGravity);
COPY_PROPERTY_FROM_QSCRIPTVALUE(particleRadius, float, setParticleRadius);
COPY_PROPERTY_FROM_QSCRIPTVALUE(marketplaceID, QString, setMarketplaceID);
COPY_PROPERTY_FROM_QSCRIPTVALUE(name, QString, setName);
COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionSoundURL, QString, setCollisionSoundURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(keyLightColor, setKeyLightColor);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(keyLightIntensity, setKeyLightIntensity);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(keyLightAmbientIntensity, setKeyLightAmbientIntensity);
COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(keyLightDirection, setKeyLightDirection);
COPY_PROPERTY_FROM_QSCRIPTVALUE(keyLightColor, xColor, setKeyLightColor);
COPY_PROPERTY_FROM_QSCRIPTVALUE(keyLightIntensity, float, setKeyLightIntensity);
COPY_PROPERTY_FROM_QSCRIPTVALUE(keyLightAmbientIntensity, float, setKeyLightAmbientIntensity);
COPY_PROPERTY_FROM_QSCRIPTVALUE(keyLightDirection, glmVec3, setKeyLightDirection);
COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(backgroundMode, BackgroundMode);
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(sourceUrl, setSourceUrl);
COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl);
_stage.copyFromScriptValue(object, _defaultSettings);
_atmosphere.copyFromScriptValue(object, _defaultSettings);
@ -650,81 +662,83 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
// PROP_PAGED_PROPERTY,
// PROP_CUSTOM_PROPERTIES_INCLUDED,
APPEND_ENTITY_PROPERTY(PROP_POSITION, appendPosition, properties.getPosition());
APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, appendValue, properties.getDimensions()); // NOTE: PROP_RADIUS obsolete
APPEND_ENTITY_PROPERTY(PROP_ROTATION, appendValue, properties.getRotation());
APPEND_ENTITY_PROPERTY(PROP_DENSITY, appendValue, properties.getDensity());
APPEND_ENTITY_PROPERTY(PROP_VELOCITY, appendValue, properties.getVelocity());
APPEND_ENTITY_PROPERTY(PROP_GRAVITY, appendValue, properties.getGravity());
APPEND_ENTITY_PROPERTY(PROP_ACCELERATION, appendValue, properties.getAcceleration());
APPEND_ENTITY_PROPERTY(PROP_DAMPING, appendValue, properties.getDamping());
APPEND_ENTITY_PROPERTY(PROP_LIFETIME, appendValue, properties.getLifetime());
APPEND_ENTITY_PROPERTY(PROP_SCRIPT, appendValue, properties.getScript());
APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, properties.getColor());
APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, appendValue, properties.getRegistrationPoint());
APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, appendValue, properties.getAngularVelocity());
APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, appendValue, properties.getAngularDamping());
APPEND_ENTITY_PROPERTY(PROP_VISIBLE, appendValue, properties.getVisible());
APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, appendValue, properties.getIgnoreForCollisions());
APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, appendValue, properties.getCollisionsWillMove());
APPEND_ENTITY_PROPERTY(PROP_LOCKED, appendValue, properties.getLocked());
APPEND_ENTITY_PROPERTY(PROP_USER_DATA, appendValue, properties.getUserData());
APPEND_ENTITY_PROPERTY(PROP_SIMULATOR_ID, appendValue, properties.getSimulatorID());
APPEND_ENTITY_PROPERTY(PROP_POSITION, properties.getPosition());
APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, properties.getDimensions()); // NOTE: PROP_RADIUS obsolete
APPEND_ENTITY_PROPERTY(PROP_ROTATION, properties.getRotation());
APPEND_ENTITY_PROPERTY(PROP_DENSITY, properties.getDensity());
APPEND_ENTITY_PROPERTY(PROP_VELOCITY, properties.getVelocity());
APPEND_ENTITY_PROPERTY(PROP_GRAVITY, properties.getGravity());
APPEND_ENTITY_PROPERTY(PROP_ACCELERATION, properties.getAcceleration());
APPEND_ENTITY_PROPERTY(PROP_DAMPING, properties.getDamping());
APPEND_ENTITY_PROPERTY(PROP_RESTITUTION, properties.getRestitution());
APPEND_ENTITY_PROPERTY(PROP_FRICTION, properties.getFriction());
APPEND_ENTITY_PROPERTY(PROP_LIFETIME, properties.getLifetime());
APPEND_ENTITY_PROPERTY(PROP_SCRIPT, properties.getScript());
APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor());
APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, properties.getRegistrationPoint());
APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, properties.getAngularVelocity());
APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, properties.getAngularDamping());
APPEND_ENTITY_PROPERTY(PROP_VISIBLE, properties.getVisible());
APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, properties.getIgnoreForCollisions());
APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, properties.getCollisionsWillMove());
APPEND_ENTITY_PROPERTY(PROP_LOCKED, properties.getLocked());
APPEND_ENTITY_PROPERTY(PROP_USER_DATA, properties.getUserData());
APPEND_ENTITY_PROPERTY(PROP_SIMULATOR_ID, properties.getSimulatorID());
if (properties.getType() == EntityTypes::Web) {
APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, appendValue, properties.getSourceUrl());
APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, properties.getSourceUrl());
}
if (properties.getType() == EntityTypes::Text) {
APPEND_ENTITY_PROPERTY(PROP_TEXT, appendValue, properties.getText());
APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, appendValue, properties.getLineHeight());
APPEND_ENTITY_PROPERTY(PROP_TEXT_COLOR, appendColor, properties.getTextColor());
APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, appendColor, properties.getBackgroundColor());
APPEND_ENTITY_PROPERTY(PROP_TEXT, properties.getText());
APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, properties.getLineHeight());
APPEND_ENTITY_PROPERTY(PROP_TEXT_COLOR, properties.getTextColor());
APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, properties.getBackgroundColor());
}
if (properties.getType() == EntityTypes::Model) {
APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, properties.getModelURL());
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, properties.getCompoundShapeURL());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, appendValue, properties.getAnimationURL());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, properties.getAnimationFPS());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, properties.getAnimationFrameIndex());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, appendValue, properties.getAnimationIsPlaying());
APPEND_ENTITY_PROPERTY(PROP_TEXTURES, appendValue, properties.getTextures());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, appendValue, properties.getAnimationSettings());
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, appendValue, (uint32_t)(properties.getShapeType()));
APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, properties.getModelURL());
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, properties.getCompoundShapeURL());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, properties.getAnimationURL());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, properties.getAnimationFPS());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, properties.getAnimationFrameIndex());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, properties.getAnimationIsPlaying());
APPEND_ENTITY_PROPERTY(PROP_TEXTURES, properties.getTextures());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, properties.getAnimationSettings());
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)(properties.getShapeType()));
}
if (properties.getType() == EntityTypes::Light) {
APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, appendValue, properties.getIsSpotlight());
APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, properties.getColor());
APPEND_ENTITY_PROPERTY(PROP_INTENSITY, appendValue, properties.getIntensity());
APPEND_ENTITY_PROPERTY(PROP_EXPONENT, appendValue, properties.getExponent());
APPEND_ENTITY_PROPERTY(PROP_CUTOFF, appendValue, properties.getCutoff());
APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, properties.getIsSpotlight());
APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor());
APPEND_ENTITY_PROPERTY(PROP_INTENSITY, properties.getIntensity());
APPEND_ENTITY_PROPERTY(PROP_EXPONENT, properties.getExponent());
APPEND_ENTITY_PROPERTY(PROP_CUTOFF, properties.getCutoff());
}
if (properties.getType() == EntityTypes::ParticleEffect) {
APPEND_ENTITY_PROPERTY(PROP_MAX_PARTICLES, appendValue, properties.getMaxParticles());
APPEND_ENTITY_PROPERTY(PROP_LIFESPAN, appendValue, properties.getLifespan());
APPEND_ENTITY_PROPERTY(PROP_EMIT_RATE, appendValue, properties.getEmitRate());
APPEND_ENTITY_PROPERTY(PROP_EMIT_DIRECTION, appendValue, properties.getEmitDirection());
APPEND_ENTITY_PROPERTY(PROP_EMIT_STRENGTH, appendValue, properties.getEmitStrength());
APPEND_ENTITY_PROPERTY(PROP_LOCAL_GRAVITY, appendValue, properties.getLocalGravity());
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, appendValue, properties.getParticleRadius());
APPEND_ENTITY_PROPERTY(PROP_MAX_PARTICLES, properties.getMaxParticles());
APPEND_ENTITY_PROPERTY(PROP_LIFESPAN, properties.getLifespan());
APPEND_ENTITY_PROPERTY(PROP_EMIT_RATE, properties.getEmitRate());
APPEND_ENTITY_PROPERTY(PROP_EMIT_DIRECTION, properties.getEmitDirection());
APPEND_ENTITY_PROPERTY(PROP_EMIT_STRENGTH, properties.getEmitStrength());
APPEND_ENTITY_PROPERTY(PROP_LOCAL_GRAVITY, properties.getLocalGravity());
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, properties.getParticleRadius());
}
if (properties.getType() == EntityTypes::Zone) {
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, appendColor, properties.getKeyLightColor());
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, appendValue, properties.getKeyLightIntensity());
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_AMBIENT_INTENSITY, appendValue, properties.getKeyLightAmbientIntensity());
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, appendValue, properties.getKeyLightDirection());
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, properties.getKeyLightColor());
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, properties.getKeyLightIntensity());
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_AMBIENT_INTENSITY, properties.getKeyLightAmbientIntensity());
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, properties.getKeyLightDirection());
_staticStage.setProperties(properties);
_staticStage.appentToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState );
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, appendValue, (uint32_t)properties.getShapeType());
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, properties.getCompoundShapeURL());
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)properties.getShapeType());
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, properties.getCompoundShapeURL());
APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_MODE, appendValue, (uint32_t)properties.getBackgroundMode());
APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_MODE, (uint32_t)properties.getBackgroundMode());
_staticAtmosphere.setProperties(properties);
_staticAtmosphere.appentToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState );
@ -733,8 +747,9 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
_staticSkybox.appentToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState );
}
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, appendValue, properties.getMarketplaceID());
APPEND_ENTITY_PROPERTY(PROP_NAME, appendValue, properties.getName());
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID());
APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName());
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL());
}
if (propertyCount > 0) {
int endOfEntityItemData = packetData->getUncompressedByteOffset();
@ -911,15 +926,17 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_POSITION, glm::vec3, setPosition);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DIMENSIONS, glm::vec3, setDimensions); // NOTE: PROP_RADIUS obsolete
READ_ENTITY_PROPERTY_QUAT_TO_PROPERTIES(PROP_ROTATION, setRotation);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ROTATION, glm::quat, setRotation);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DENSITY, float, setDensity);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VELOCITY, glm::vec3, setVelocity);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_GRAVITY, glm::vec3, setGravity);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACCELERATION, glm::vec3, setAcceleration);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DAMPING, float, setDamping);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RESTITUTION, float, setRestitution);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FRICTION, float, setFriction);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LIFETIME, float, setLifetime);
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_SCRIPT,setScript);
READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_COLOR, setColor);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SCRIPT,QString, setScript);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, xColor, setColor);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_VELOCITY, glm::vec3, setAngularVelocity);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_DAMPING, float, setAngularDamping);
@ -927,35 +944,35 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IGNORE_FOR_COLLISIONS, bool, setIgnoreForCollisions);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISIONS_WILL_MOVE, bool, setCollisionsWillMove);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCKED, bool, setLocked);
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_USER_DATA, setUserData);
READ_ENTITY_PROPERTY_UUID_TO_PROPERTIES(PROP_SIMULATOR_ID, setSimulatorID);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USER_DATA, QString, setUserData);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SIMULATOR_ID, QUuid, setSimulatorID);
if (properties.getType() == EntityTypes::Web) {
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_SOURCE_URL, setSourceUrl);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SOURCE_URL, QString, setSourceUrl);
}
if (properties.getType() == EntityTypes::Text) {
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_TEXT, setText);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT, QString, setText);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_HEIGHT, float, setLineHeight);
READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_TEXT_COLOR, setTextColor);
READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_BACKGROUND_COLOR, setBackgroundColor);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT_COLOR, xColor, setTextColor);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BACKGROUND_COLOR, xColor, setBackgroundColor);
}
if (properties.getType() == EntityTypes::Model) {
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MODEL_URL, setModelURL);
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL);
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_ANIMATION_URL, setAnimationURL);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MODEL_URL, QString, setModelURL);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_URL, QString, setAnimationURL);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FPS, float, setAnimationFPS);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_PLAYING, bool, setAnimationIsPlaying);
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_TEXTURES, setTextures);
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_ANIMATION_SETTINGS, setAnimationSettings);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXTURES, QString, setTextures);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_SETTINGS, QString, setAnimationSettings);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType);
}
if (properties.getType() == EntityTypes::Light) {
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IS_SPOTLIGHT, bool, setIsSpotlight);
READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_COLOR, setColor);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, xColor, setColor);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_INTENSITY, float, setIntensity);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EXPONENT, float, setExponent);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CUTOFF, float, setCutoff);
@ -972,7 +989,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
}
if (properties.getType() == EntityTypes::Zone) {
READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_KEYLIGHT_COLOR, setKeyLightColor);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEYLIGHT_COLOR, xColor, setKeyLightColor);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEYLIGHT_INTENSITY, float, setKeyLightIntensity);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEYLIGHT_AMBIENT_INTENSITY, float, setKeyLightAmbientIntensity);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEYLIGHT_DIRECTION, glm::vec3, setKeyLightDirection);
@ -980,15 +997,16 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
properties.getStage().decodeFromEditPacket(propertyFlags, dataAt , processedBytes);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType);
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BACKGROUND_MODE, BackgroundMode, setBackgroundMode);
properties.getAtmosphere().decodeFromEditPacket(propertyFlags, dataAt , processedBytes);
properties.getSkybox().decodeFromEditPacket(propertyFlags, dataAt , processedBytes);
}
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MARKETPLACE_ID, setMarketplaceID);
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_NAME, setName);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
return valid;
}
@ -1030,10 +1048,13 @@ void EntityItemProperties::markAllChanged() {
_gravityChanged = true;
_accelerationChanged = true;
_dampingChanged = true;
_restitutionChanged = true;
_frictionChanged = true;
_lifetimeChanged = true;
_userDataChanged = true;
_simulatorIDChanged = true;
_scriptChanged = true;
_collisionSoundURLChanged = true;
_registrationPointChanged = true;
_angularVelocityChanged = true;
_angularDampingChanged = true;
@ -1130,3 +1151,5 @@ AABox EntityItemProperties::getAABox() const {
return AABox(rotatedExtentsRelativeToRegistrationPoint);
}

View file

@ -95,8 +95,11 @@ public:
DEFINE_PROPERTY_REF(PROP_GRAVITY, Gravity, gravity, glm::vec3);
DEFINE_PROPERTY_REF(PROP_ACCELERATION, Acceleration, acceleration, glm::vec3);
DEFINE_PROPERTY(PROP_DAMPING, Damping, damping, float);
DEFINE_PROPERTY(PROP_RESTITUTION, Restitution, restitution, float);
DEFINE_PROPERTY(PROP_FRICTION, Friction, friction, float);
DEFINE_PROPERTY(PROP_LIFETIME, Lifetime, lifetime, float);
DEFINE_PROPERTY_REF(PROP_SCRIPT, Script, script, QString);
DEFINE_PROPERTY_REF(PROP_COLLISION_SOUND_URL, CollisionSoundURL, collisionSoundURL, QString);
DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor);
DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString);
DEFINE_PROPERTY_REF(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString);
@ -242,8 +245,11 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Gravity, gravity, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Acceleration, acceleration, "in meters per second");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Damping, damping, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Restitution, restitution, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Friction, friction, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Lifetime, lifetime, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Script, script, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, CollisionSoundURL, collisionSoundURL, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Color, color, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ModelURL, modelURL, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, CompoundShapeURL, compoundShapeURL, "");

View file

@ -30,6 +30,7 @@ const float ENTITY_ITEM_DEFAULT_GLOW_LEVEL = 0.0f;
const bool ENTITY_ITEM_DEFAULT_VISIBLE = true;
const QString ENTITY_ITEM_DEFAULT_SCRIPT = QString("");
const QString ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL = 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
@ -52,6 +53,14 @@ const glm::vec3 ENTITY_ITEM_DEFAULT_ACCELERATION = 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 float ENTITY_ITEM_MIN_RESTITUTION = 0.0f;
const float ENTITY_ITEM_MAX_RESTITUTION = 0.99f;
const float ENTITY_ITEM_DEFAULT_RESTITUTION = 0.5f;
const float ENTITY_ITEM_MIN_FRICTION = 0.0f;
const float ENTITY_ITEM_MAX_FRICTION = 0.99f;
const float ENTITY_ITEM_DEFAULT_FRICTION = 0.5f;
const bool ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS = false;
const bool ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE = false;

View file

@ -12,10 +12,10 @@
#ifndef hifi_EntityItemPropertiesMacros_h
#define hifi_EntityItemPropertiesMacros_h
#define APPEND_ENTITY_PROPERTY(P,O,V) \
#define APPEND_ENTITY_PROPERTY(P,V) \
if (requestedProperties.getHasProperty(P)) { \
LevelDetails propertyLevel = packetData->startLevel(); \
successPropertyFits = packetData->O(V); \
successPropertyFits = packetData->appendValue(V); \
if (successPropertyFits) { \
propertyFlags |= P; \
propertiesDidntFit -= P; \
@ -29,82 +29,15 @@
propertiesDidntFit -= P; \
}
#define READ_ENTITY_PROPERTY(P,T,M) \
if (propertyFlags.getHasProperty(P)) { \
T fromBuffer; \
memcpy(&fromBuffer, dataAt, sizeof(fromBuffer)); \
dataAt += sizeof(fromBuffer); \
bytesRead += sizeof(fromBuffer); \
if (overwriteLocalData) { \
M = fromBuffer; \
} \
}
#define READ_ENTITY_PROPERTY_SETTER(P,T,M) \
if (propertyFlags.getHasProperty(P)) { \
T fromBuffer; \
memcpy(&fromBuffer, dataAt, sizeof(fromBuffer)); \
dataAt += sizeof(fromBuffer); \
bytesRead += sizeof(fromBuffer); \
if (overwriteLocalData) { \
M(fromBuffer); \
} \
}
#define READ_ENTITY_PROPERTY_QUAT(P,M) \
if (propertyFlags.getHasProperty(P)) { \
glm::quat fromBuffer; \
int bytes = unpackOrientationQuatFromBytes(dataAt, fromBuffer); \
dataAt += bytes; \
bytesRead += bytes; \
if (overwriteLocalData) { \
M = fromBuffer; \
} \
}
#define READ_ENTITY_PROPERTY_QUAT_SETTER(P,M) \
if (propertyFlags.getHasProperty(P)) { \
glm::quat fromBuffer; \
int bytes = unpackOrientationQuatFromBytes(dataAt, fromBuffer); \
dataAt += bytes; \
bytesRead += bytes; \
if (overwriteLocalData) { \
M(fromBuffer); \
} \
}
#define READ_ENTITY_PROPERTY_STRING(P,O) \
if (propertyFlags.getHasProperty(P)) { \
uint16_t length; \
memcpy(&length, dataAt, sizeof(length)); \
dataAt += sizeof(length); \
bytesRead += sizeof(length); \
QString value((const char*)dataAt); \
dataAt += length; \
bytesRead += length; \
if (overwriteLocalData) { \
O(value); \
} \
}
#define READ_ENTITY_PROPERTY_UUID(P,O) \
if (propertyFlags.getHasProperty(P)) { \
uint16_t length; \
memcpy(&length, dataAt, sizeof(length)); \
dataAt += sizeof(length); \
bytesRead += sizeof(length); \
QUuid value; \
if (length == 0) { \
value = QUuid(); \
} else { \
QByteArray ba((const char*)dataAt, length); \
value = QUuid::fromRfc4122(ba); \
dataAt += length; \
bytesRead += length; \
} \
if (overwriteLocalData) { \
O(value); \
} \
#define READ_ENTITY_PROPERTY(P,T,S) \
if (propertyFlags.getHasProperty(P)) { \
T fromBuffer; \
int bytes = OctreePacketData::uppackDataFromBytes(dataAt, fromBuffer); \
dataAt += bytes; \
bytesRead += bytes; \
if (overwriteLocalData) { \
S(fromBuffer); \
} \
}
#define DECODE_GROUP_PROPERTY_HAS_CHANGED(P,N) \
@ -112,82 +45,14 @@
set##N##Changed(true); \
}
#define READ_ENTITY_PROPERTY_COLOR(P,M) \
if (propertyFlags.getHasProperty(P)) { \
if (overwriteLocalData) { \
memcpy(M, dataAt, sizeof(M)); \
} \
dataAt += sizeof(rgbColor); \
bytesRead += sizeof(rgbColor); \
}
#define READ_ENTITY_PROPERTY_XCOLOR(P,M) \
if (propertyFlags.getHasProperty(P)) { \
if (overwriteLocalData) { \
M.red = dataAt[RED_INDEX]; \
M.green = dataAt[GREEN_INDEX]; \
M.blue = dataAt[BLUE_INDEX]; \
} \
dataAt += sizeof(rgbColor); \
bytesRead += sizeof(rgbColor); \
}
#define READ_ENTITY_PROPERTY_TO_PROPERTIES(P,T,O) \
if (propertyFlags.getHasProperty(P)) { \
T fromBuffer; \
memcpy(&fromBuffer, dataAt, sizeof(fromBuffer)); \
dataAt += sizeof(fromBuffer); \
processedBytes += sizeof(fromBuffer); \
properties.O(fromBuffer); \
}
#define READ_ENTITY_PROPERTY_QUAT_TO_PROPERTIES(P,O) \
if (propertyFlags.getHasProperty(P)) { \
glm::quat fromBuffer; \
int bytes = unpackOrientationQuatFromBytes(dataAt, fromBuffer); \
dataAt += bytes; \
processedBytes += bytes; \
properties.O(fromBuffer); \
}
#define READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(P,O) \
if (propertyFlags.getHasProperty(P)) { \
uint16_t length; \
memcpy(&length, dataAt, sizeof(length)); \
dataAt += sizeof(length); \
processedBytes += sizeof(length); \
QString value((const char*)dataAt); \
dataAt += length; \
processedBytes += length; \
properties.O(value); \
}
#define READ_ENTITY_PROPERTY_UUID_TO_PROPERTIES(P,O) \
if (propertyFlags.getHasProperty(P)) { \
uint16_t length; \
memcpy(&length, dataAt, sizeof(length)); \
dataAt += sizeof(length); \
processedBytes += sizeof(length); \
QUuid value; \
if (length == 0) { \
value = QUuid(); \
} else { \
QByteArray ba((const char*)dataAt, length); \
value = QUuid::fromRfc4122(ba); \
dataAt += length; \
processedBytes += length; \
} \
properties.O(value); \
}
#define READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(P,O) \
if (propertyFlags.getHasProperty(P)) { \
xColor color; \
memcpy(&color, dataAt, sizeof(color)); \
dataAt += sizeof(color); \
processedBytes += sizeof(color); \
properties.O(color); \
#define READ_ENTITY_PROPERTY_TO_PROPERTIES(P,T,O) \
if (propertyFlags.getHasProperty(P)) { \
T fromBuffer; \
int bytes = OctreePacketData::uppackDataFromBytes(dataAt, fromBuffer); \
dataAt += bytes; \
processedBytes += bytes; \
properties.O(fromBuffer); \
}
#define SET_ENTITY_PROPERTY_FROM_PROPERTIES(P,M) \
@ -221,63 +86,30 @@
changedProperties += P; \
}
inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::vec3& v) { return vec3toScriptValue(e, v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, float v) { return QScriptValue(v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, int v) { return QScriptValue(v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, quint32 v) { return QScriptValue(v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const QString& v) { return QScriptValue(v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const xColor& v) { return xColorToScriptValue(e, v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::quat& v) { return quatToScriptValue(e, v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const QScriptValue& v) { return v; }
#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_VEC3(G,g,P,p) \
if (!skipDefaults || defaultEntityProperties.get##G().get##P() != _##p) { \
#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(G,g,P,p) \
if (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P()) { \
QScriptValue groupProperties = properties.property(#g); \
if (!groupProperties.isValid()) { \
groupProperties = engine->newObject(); \
} \
QScriptValue V = vec3toScriptValue(engine, _##p); \
QScriptValue V = convertScriptValue(engine, get##P()); \
groupProperties.setProperty(#p, V); \
properties.setProperty(#g, groupProperties); \
}
#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(G,g,P,p) \
if (!skipDefaults || defaultEntityProperties.get##G().get##P() != _##p) { \
QScriptValue groupProperties = properties.property(#g); \
if (!groupProperties.isValid()) { \
groupProperties = engine->newObject(); \
} \
groupProperties.setProperty(#p, _##p); \
properties.setProperty(#g, groupProperties); \
}
#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_COLOR(G,g,P,p) \
if (!skipDefaults || defaultEntityProperties.get##G().get##P() != _##p) { \
QScriptValue groupProperties = properties.property(#g); \
if (!groupProperties.isValid()) { \
groupProperties = engine->newObject(); \
} \
QScriptValue colorValue = xColorToScriptValue(engine, _##p); \
groupProperties.setProperty(#p, colorValue); \
properties.setProperty(#g, groupProperties); \
}
#define COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(P) \
#define COPY_PROPERTY_TO_QSCRIPTVALUE(P) \
if (!skipDefaults || defaultEntityProperties._##P != _##P) { \
QScriptValue P = vec3toScriptValue(engine, _##P); \
properties.setProperty(#P, P); \
}
#define COPY_PROPERTY_TO_QSCRIPTVALUE_QUAT(P) \
if (!skipDefaults || defaultEntityProperties._##P != _##P) { \
QScriptValue P = quatToScriptValue(engine, _##P); \
properties.setProperty(#P, P); \
}
#define COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR(P) \
if (!skipDefaults || defaultEntityProperties._##P != _##P) { \
QScriptValue P = xColorToScriptValue(engine, _##P); \
properties.setProperty(#P, P); \
}
#define COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(P,G) \
if (!skipDefaults || defaultEntityProperties._##P != _##P) { \
QScriptValue P = xColorToScriptValue(engine, G); \
properties.setProperty(#P, P); \
QScriptValue V = convertScriptValue(engine, _##P); \
properties.setProperty(#P, V); \
}
#define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(P, G) \
@ -285,257 +117,114 @@
#define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(P, G) \
if (!skipDefaults || defaultEntityProperties._##P != _##P) { \
properties.setProperty(#P, G); \
}
#define COPY_PROPERTY_TO_QSCRIPTVALUE(P) \
if (!skipDefaults || defaultEntityProperties._##P != _##P) { \
properties.setProperty(#P, _##P); \
}
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(P, S) \
QScriptValue P = object.property(#P); \
if (P.isValid()) { \
float newValue = P.toVariant().toFloat(); \
if (_defaultSettings || newValue != _##P) { \
S(newValue); \
} \
}
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT_GETTER(P, S, G) \
QScriptValue P = object.property(#P); \
if (P.isValid()) { \
float newValue = P.toVariant().toFloat(); \
if (_defaultSettings || newValue != G()) { \
S(newValue); \
} \
}
#define COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(G, P, S) \
{ \
QScriptValue G = object.property(#G); \
if (G.isValid()) { \
QScriptValue P = G.property(#P); \
if (P.isValid()) { \
float newValue = P.toVariant().toFloat(); \
if (_defaultSettings || newValue != _##P) { \
S(newValue); \
} \
} \
} \
}
#define COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_UINT16(G, P, S) \
{ \
QScriptValue G = object.property(#G); \
if (G.isValid()) { \
QScriptValue P = G.property(#P); \
if (P.isValid()) { \
uint16_t newValue = P.toVariant().toInt(); \
if (_defaultSettings || newValue != _##P) { \
S(newValue); \
} \
} \
} \
}
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_INT(P, S) \
QScriptValue P = object.property(#P); \
if (P.isValid()) { \
int newValue = P.toVariant().toInt(); \
if (_defaultSettings || newValue != _##P) { \
S(newValue); \
} \
}
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_INT_GETTER(P, S, G) \
QScriptValue P = object.property(#P); \
if (P.isValid()) { \
int newValue = P.toVariant().toInt(); \
if (_defaultSettings || newValue != G()) { \
S(newValue); \
} \
}
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(P, S) \
QScriptValue P = object.property(#P); \
if (P.isValid()) { \
bool newValue = P.toVariant().toBool(); \
if (_defaultSettings || newValue != _##P) { \
S(newValue); \
} \
}
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL_GETTER(P, S, G) \
QScriptValue P = object.property(#P); \
if (P.isValid()) { \
bool newValue = P.toVariant().toBool(); \
if (_defaultSettings || newValue != G()) { \
S(newValue); \
} \
}
#define COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_BOOL(G, P, S) \
{ \
QScriptValue G = object.property(#G); \
if (G.isValid()) { \
QScriptValue P = G.property(#P); \
if (P.isValid()) { \
float newValue = P.toVariant().toBool(); \
if (_defaultSettings || newValue != _##P) { \
S(newValue); \
} \
} \
} \
}
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(P, S)\
QScriptValue P = object.property(#P); \
if (P.isValid()) { \
QString newValue = P.toVariant().toString().trimmed();\
if (_defaultSettings || newValue != _##P) { \
S(newValue); \
} \
}
#define COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_STRING(G, P, S)\
{ \
QScriptValue G = object.property(#G); \
if (G.isValid()) { \
QScriptValue P = G.property(#P); \
if (P.isValid()) { \
QString newValue = P.toVariant().toString().trimmed();\
if (_defaultSettings || newValue != _##P) { \
S(newValue); \
} \
} \
} \
}
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_UUID(P, S) \
QScriptValue P = object.property(#P); \
if (P.isValid()) { \
QUuid newValue = P.toVariant().toUuid(); \
if (_defaultSettings || newValue != _##P) { \
S(newValue); \
} \
}
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(P, S) \
QScriptValue P = object.property(#P); \
if (P.isValid()) { \
QScriptValue x = P.property("x"); \
QScriptValue y = P.property("y"); \
QScriptValue z = P.property("z"); \
if (x.isValid() && y.isValid() && z.isValid()) { \
glm::vec3 newValue; \
newValue.x = x.toVariant().toFloat(); \
newValue.y = y.toVariant().toFloat(); \
newValue.z = z.toVariant().toFloat(); \
bool isValid = !glm::isnan(newValue.x) && \
!glm::isnan(newValue.y) && \
!glm::isnan(newValue.z); \
if (isValid && \
(_defaultSettings || newValue != _##P)) { \
S(newValue); \
} \
} \
}
#define COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_VEC3(G, P, S) \
{ \
QScriptValue G = object.property(#G); \
if (G.isValid()) { \
QScriptValue P = G.property(#P); \
if (P.isValid()) { \
QScriptValue x = P.property("x"); \
QScriptValue y = P.property("y"); \
QScriptValue z = P.property("z"); \
if (x.isValid() && y.isValid() && z.isValid()) { \
glm::vec3 newValue; \
newValue.x = x.toVariant().toFloat(); \
newValue.y = y.toVariant().toFloat(); \
newValue.z = z.toVariant().toFloat(); \
bool isValid = !glm::isnan(newValue.x) && \
!glm::isnan(newValue.y) && \
!glm::isnan(newValue.z); \
if (isValid && \
(_defaultSettings || newValue != _##P)) { \
S(newValue); \
} \
} \
} \
} \
QScriptValue V = convertScriptValue(engine, G); \
properties.setProperty(#P, V); \
}
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_QUAT(P, S) \
QScriptValue P = object.property(#P); \
if (P.isValid()) { \
QScriptValue x = P.property("x"); \
QScriptValue y = P.property("y"); \
QScriptValue z = P.property("z"); \
QScriptValue w = P.property("w"); \
if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) { \
glm::quat newValue; \
newValue.x = x.toVariant().toFloat(); \
newValue.y = y.toVariant().toFloat(); \
newValue.z = z.toVariant().toFloat(); \
newValue.w = w.toVariant().toFloat(); \
bool isValid = !glm::isnan(newValue.x) && \
!glm::isnan(newValue.y) && \
!glm::isnan(newValue.z) && \
!glm::isnan(newValue.w); \
if (isValid && \
(_defaultSettings || newValue != _##P)) { \
S(newValue); \
} \
} \
typedef glm::vec3 glmVec3;
typedef glm::quat glmQuat;
inline float float_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toFloat(&isValid); }
inline uint16_t uint16_t_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
inline int int_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
inline bool bool_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toBool(); }
inline QString QString_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toString().trimmed(); }
inline QUuid QUuid_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); }
inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = false; /// assume it can't be converted
QScriptValue x = v.property("x");
QScriptValue y = v.property("y");
QScriptValue z = v.property("z");
if (x.isValid() && y.isValid() && z.isValid()) {
glm::vec3 newValue(0);
newValue.x = x.toVariant().toFloat();
newValue.y = y.toVariant().toFloat();
newValue.z = z.toVariant().toFloat();
isValid = !glm::isnan(newValue.x) &&
!glm::isnan(newValue.y) &&
!glm::isnan(newValue.z);
if (isValid) {
return newValue;
}
}
return glm::vec3(0);
}
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(P, S) \
QScriptValue P = object.property(#P); \
if (P.isValid()) { \
QScriptValue r = P.property("red"); \
QScriptValue g = P.property("green"); \
QScriptValue b = P.property("blue"); \
if (r.isValid() && g.isValid() && b.isValid()) {\
xColor newColor; \
newColor.red = r.toVariant().toInt(); \
newColor.green = g.toVariant().toInt(); \
newColor.blue = b.toVariant().toInt(); \
if (_defaultSettings || \
(newColor.red != _color.red || \
newColor.green != _color.green || \
newColor.blue != _color.blue)) { \
S(newColor); \
inline glmQuat glmQuat_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = false; /// assume it can't be converted
QScriptValue x = v.property("x");
QScriptValue y = v.property("y");
QScriptValue z = v.property("z");
QScriptValue w = v.property("w");
if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) {
glm::quat newValue;
newValue.x = x.toVariant().toFloat();
newValue.y = y.toVariant().toFloat();
newValue.z = z.toVariant().toFloat();
newValue.w = w.toVariant().toFloat();
isValid = !glm::isnan(newValue.x) &&
!glm::isnan(newValue.y) &&
!glm::isnan(newValue.z) &&
!glm::isnan(newValue.w);
if (isValid) {
return newValue;
}
}
return glm::quat();
}
inline xColor xColor_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
xColor newValue;
isValid = false; /// assume it can't be converted
QScriptValue r = v.property("red");
QScriptValue g = v.property("green");
QScriptValue b = v.property("blue");
if (r.isValid() && g.isValid() && b.isValid()) {
newValue.red = r.toVariant().toInt();
newValue.green = g.toVariant().toInt();
newValue.blue = b.toVariant().toInt();
isValid = true;
}
return newValue;
}
#define COPY_PROPERTY_FROM_QSCRIPTVALUE(P, T, S) \
{ \
QScriptValue V = object.property(#P); \
if (V.isValid()) { \
bool isValid = false; \
T newValue = T##_convertFromScriptValue(V, isValid); \
if (isValid && (_defaultSettings || newValue != _##P)) { \
S(newValue); \
} \
} \
}
#define COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_COLOR(G, P, S) \
{ \
QScriptValue G = object.property(#G); \
if (G.isValid()) { \
QScriptValue P = G.property(#P); \
if (P.isValid()) { \
QScriptValue r = P.property("red"); \
QScriptValue g = P.property("green"); \
QScriptValue b = P.property("blue"); \
if (r.isValid() && g.isValid() && b.isValid()) {\
xColor newColor; \
newColor.red = r.toVariant().toInt(); \
newColor.green = g.toVariant().toInt(); \
newColor.blue = b.toVariant().toInt(); \
if (_defaultSettings || \
(newColor.red != _color.red || \
newColor.green != _color.green || \
newColor.blue != _color.blue)) { \
S(newColor); \
} \
} \
} \
} \
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(P, T, S, G) \
{ \
QScriptValue V = object.property(#P); \
if (V.isValid()) { \
bool isValid = false; \
T newValue = T##_convertFromScriptValue(V, isValid); \
if (isValid && (_defaultSettings || newValue != G())) { \
S(newValue); \
} \
}\
}
#define COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(G, P, T, S) \
{ \
QScriptValue G = object.property(#G); \
if (G.isValid()) { \
QScriptValue V = G.property(#P); \
if (V.isValid()) { \
bool isValid = false; \
T newValue = T##_convertFromScriptValue(V, isValid); \
if (isValid && (_defaultSettings || newValue != _##P)) { \
S(newValue); \
} \
} \
} \
}
#define COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(P, S) \

View file

@ -75,7 +75,7 @@ enum EntityPropertyList {
// property used by Light entity
PROP_IS_SPOTLIGHT,
PROP_DIFFUSE_COLOR_UNUSED,
PROP_DIFFUSE_COLOR,
PROP_AMBIENT_COLOR_UNUSED,
PROP_SPECULAR_COLOR_UNUSED,
PROP_INTENSITY, // Previously PROP_CONSTANT_ATTENUATION
@ -106,6 +106,9 @@ enum EntityPropertyList {
PROP_ACCELERATION, // all entities
PROP_SIMULATOR_ID, // all entities
PROP_NAME, // all entities
PROP_COLLISION_SOUND_URL,
PROP_RESTITUTION,
PROP_FRICTION,
////////////////////////////////////////////////////////////////////////////////////////////////////
// ATTENTION: add new properties ABOVE this line
@ -131,7 +134,7 @@ enum EntityPropertyList {
PROP_KEYLIGHT_AMBIENT_INTENSITY = PROP_CUTOFF,
PROP_KEYLIGHT_DIRECTION = PROP_EXPONENT,
PROP_STAGE_SUN_MODEL_ENABLED = PROP_IS_SPOTLIGHT,
PROP_STAGE_LATITUDE = PROP_DIFFUSE_COLOR_UNUSED,
PROP_STAGE_LATITUDE = PROP_DIFFUSE_COLOR,
PROP_STAGE_LONGITUDE = PROP_AMBIENT_COLOR_UNUSED,
PROP_STAGE_ALTITUDE = PROP_SPECULAR_COLOR_UNUSED,
PROP_STAGE_DAY = PROP_LINEAR_ATTENUATION_UNUSED,
@ -162,11 +165,4 @@ typedef PropertyFlags<EntityPropertyList> EntityPropertyFlags;
extern EntityPropertyList PROP_LAST_ITEM;
enum BackgroundMode {
BACKGROUND_MODE_INHERIT,
BACKGROUND_MODE_ATMOSPHERE,
BACKGROUND_MODE_SKYBOX,
};
#endif // hifi_EntityPropertyFlags_h

View file

@ -61,13 +61,12 @@ void EntityScriptingInterface::setEntityTree(EntityTree* modelTree) {
}
}
void setSimId(EntityItemProperties& propertiesWithSimID, EntityItem* entity) {
void bidForSimulationOwnership(EntityItemProperties& properties) {
// We make a bid for simulation ownership by declaring our sessionID as simulation owner
// in the outgoing properties. The EntityServer may accept the bid or might not.
auto nodeList = DependencyManager::get<NodeList>();
const QUuid myNodeID = nodeList->getSessionUUID();
propertiesWithSimID.setSimulatorID(myNodeID);
entity->setSimulatorID(myNodeID);
properties.setSimulatorID(myNodeID);
}
@ -89,7 +88,7 @@ EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& pro
entity->setLastBroadcast(usecTimestampNow());
if (entity) {
// This Node is creating a new object. If it's in motion, set this Node as the simulator.
setSimId(propertiesWithSimID, entity);
bidForSimulationOwnership(propertiesWithSimID);
} else {
qCDebug(entities) << "script failed to add new Entity to local Octree";
success = false;
@ -163,29 +162,31 @@ EntityItemID EntityScriptingInterface::editEntity(EntityItemID entityID, const E
}
}
EntityItemProperties propertiesWithSimID = properties;
// If we have a local entity tree set, then also update it. We can do this even if we don't know
// the actual id, because we can edit out local entities just with creatorTokenID
if (_entityTree) {
_entityTree->lockForWrite();
_entityTree->updateEntity(entityID, propertiesWithSimID, canAdjustLocks());
_entityTree->updateEntity(entityID, properties);
_entityTree->unlock();
}
// if at this point, we know the id, send the update to the entity server
if (entityID.isKnownID) {
// make sure the properties has a type, so that the encode can know which properties to include
if (propertiesWithSimID.getType() == EntityTypes::Unknown) {
if (properties.getType() == EntityTypes::Unknown) {
EntityItem* entity = _entityTree->findEntityByEntityItemID(entityID);
if (entity) {
// we need to change the outgoing properties, so we make a copy, modify, and send.
EntityItemProperties modifiedProperties = properties;
entity->setLastBroadcast(usecTimestampNow());
propertiesWithSimID.setType(entity->getType());
setSimId(propertiesWithSimID, entity);
modifiedProperties.setType(entity->getType());
bidForSimulationOwnership(modifiedProperties);
queueEntityMessage(PacketTypeEntityAddOrEdit, entityID, modifiedProperties);
return entityID;
}
}
queueEntityMessage(PacketTypeEntityAddOrEdit, entityID, propertiesWithSimID);
queueEntityMessage(PacketTypeEntityAddOrEdit, entityID, properties);
}
return entityID;

View file

@ -37,7 +37,8 @@ const int DIRTY_SIMULATION_FLAGS =
EntityItem::DIRTY_SHAPE |
EntityItem::DIRTY_LIFETIME |
EntityItem::DIRTY_UPDATEABLE |
EntityItem::DIRTY_MATERIAL;
EntityItem::DIRTY_MATERIAL |
EntityItem::DIRTY_SIMULATOR_ID;
class EntitySimulation : public QObject {
Q_OBJECT

View file

@ -86,7 +86,7 @@ void EntityTree::postAddEntity(EntityItem* entity) {
emit addingEntity(entity->getEntityItemID());
}
bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties, bool allowLockChange) {
bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties, const SharedNodePointer& senderNode) {
EntityTreeElement* containingElement = getContainingElement(entityID);
if (!containingElement) {
qCDebug(entities) << "UNEXPECTED!!!! EntityTree::updateEntity() entityID doesn't exist!!! entityID=" << entityID;
@ -99,22 +99,34 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp
return false;
}
return updateEntityWithElement(existingEntity, properties, containingElement, allowLockChange);
return updateEntityWithElement(existingEntity, properties, containingElement, senderNode);
}
bool EntityTree::updateEntity(EntityItem* entity, const EntityItemProperties& properties, bool allowLockChange) {
bool EntityTree::updateEntity(EntityItem* entity, const EntityItemProperties& properties, const SharedNodePointer& senderNode) {
EntityTreeElement* containingElement = getContainingElement(entity->getEntityItemID());
if (!containingElement) {
qCDebug(entities) << "UNEXPECTED!!!! EntityTree::updateEntity() entity-->element lookup failed!!! entityID="
<< entity->getEntityItemID();
return false;
}
return updateEntityWithElement(entity, properties, containingElement, allowLockChange);
return updateEntityWithElement(entity, properties, containingElement, senderNode);
}
bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemProperties& origProperties,
EntityTreeElement* containingElement, bool allowLockChange) {
EntityTreeElement* containingElement, const SharedNodePointer& senderNode) {
EntityItemProperties properties = origProperties;
bool allowLockChange;
QUuid senderID;
if (senderNode.isNull()) {
auto nodeList = DependencyManager::get<NodeList>();
allowLockChange = nodeList->getThisNodeCanAdjustLocks();
senderID = nodeList->getSessionUUID();
} else {
allowLockChange = senderNode->getCanAdjustLocks();
senderID = senderNode->getUUID();
}
if (!allowLockChange && (entity->getLocked() != properties.getLocked())) {
qCDebug(entities) << "Refusing disallowed lock adjustment.";
return false;
@ -134,22 +146,41 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro
}
}
} else {
if (properties.simulatorIDChanged() &&
!entity->getSimulatorID().isNull() &&
properties.getSimulatorID() != entity->getSimulatorID()) {
// A Node is trying to take ownership of the simulation of this entity from another Node. Only allow this
// if ownership hasn't recently changed.
if (usecTimestampNow() - entity->getSimulatorIDChangedTime() < SIMULATOR_CHANGE_LOCKOUT_PERIOD) {
qCDebug(entities) << "simulator_change_lockout_period:"
<< entity->getSimulatorID() << "to" << properties.getSimulatorID();
if (getIsServer()) {
bool simulationBlocked = !entity->getSimulatorID().isNull();
if (properties.simulatorIDChanged()) {
QUuid submittedID = properties.getSimulatorID();
// a legit interface will only submit their own ID or NULL:
if (submittedID.isNull()) {
if (entity->getSimulatorID() == senderID) {
// We only allow the simulation owner to clear their own simulationID's.
simulationBlocked = false;
}
// else: We assume the sender really did believe it was the simulation owner when it sent
} else if (submittedID == senderID) {
// the sender is trying to take or continue ownership
if (entity->getSimulatorID().isNull() || entity->getSimulatorID() == senderID) {
simulationBlocked = false;
} else {
// the sender is trying to steal ownership from another simulator
// so we apply the ownership change filter
if (usecTimestampNow() - entity->getSimulatorIDChangedTime() > SIMULATOR_CHANGE_LOCKOUT_PERIOD) {
simulationBlocked = false;
}
}
} else {
// the entire update is suspect --> ignore it
return false;
}
}
if (simulationBlocked) {
// squash the physics-related changes.
properties.setSimulatorIDChanged(false);
properties.setPositionChanged(false);
properties.setRotationChanged(false);
} else {
qCDebug(entities) << "allowing simulatorID change";
}
}
// else client accepts what the server says
QString entityScriptBefore = entity->getScript();
uint32_t preFlags = entity->getDirtyFlags();
@ -664,7 +695,7 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char
qCDebug(entities) << "User [" << senderNode->getUUID() << "] editing entity. ID:" << entityItemID;
qCDebug(entities) << " properties:" << properties;
}
updateEntity(entityItemID, properties, senderNode->getCanAdjustLocks());
updateEntity(entityItemID, properties, senderNode);
existingEntity->markAsChangedOnServer();
} else {
qCDebug(entities) << "User attempted to edit an unknown entity. ID:" << entityItemID;

View file

@ -88,10 +88,10 @@ public:
EntityItem* addEntity(const EntityItemID& entityID, const EntityItemProperties& properties);
// use this method if you only know the entityID
bool updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties, bool allowLockChange);
bool updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties, const SharedNodePointer& senderNode = SharedNodePointer(nullptr));
// use this method if you have a pointer to the entity (avoid an extra entity lookup)
bool updateEntity(EntityItem* entity, const EntityItemProperties& properties, bool allowLockChange);
bool updateEntity(EntityItem* entity, const EntityItemProperties& properties, const SharedNodePointer& senderNode = SharedNodePointer(nullptr));
void deleteEntity(const EntityItemID& entityID, bool force = false, bool ignoreWarnings = false);
void deleteEntities(QSet<EntityItemID> entityIDs, bool force = false, bool ignoreWarnings = false);
@ -180,7 +180,8 @@ private:
void processRemovedEntities(const DeleteEntityOperator& theOperator);
bool updateEntityWithElement(EntityItem* entity, const EntityItemProperties& properties,
EntityTreeElement* containingElement, bool allowLockChange);
EntityTreeElement* containingElement,
const SharedNodePointer& senderNode = SharedNodePointer(nullptr));
static bool findNearPointOperation(OctreeElement* element, void* extraData);
static bool findInSphereOperation(OctreeElement* element, void* extraData);
static bool findInCubeOperation(OctreeElement* element, void* extraData);

View file

@ -124,37 +124,32 @@ int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
const unsigned char* dataAt = data;
if (args.bitstreamVersion < VERSION_ENTITIES_LIGHT_HAS_INTENSITY_AND_COLOR_PROPERTIES) {
rgbColor ignoredColor;
float ignoredAttenuation;
READ_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, bool, _isSpotlight);
READ_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, bool, setIsSpotlight);
// _diffuseColor has been renamed to _color
READ_ENTITY_PROPERTY_COLOR(PROP_DIFFUSE_COLOR_UNUSED, _color);
READ_ENTITY_PROPERTY(PROP_DIFFUSE_COLOR, rgbColor, setColor);
// Ambient and specular color are from an older format and are no longer supported.
// Their values will be ignored.
READ_ENTITY_PROPERTY_COLOR(PROP_AMBIENT_COLOR_UNUSED, ignoredColor);
READ_ENTITY_PROPERTY_COLOR(PROP_SPECULAR_COLOR_UNUSED, ignoredColor);
READ_ENTITY_PROPERTY(PROP_AMBIENT_COLOR_UNUSED, rgbColor, setIgnoredColor);
READ_ENTITY_PROPERTY(PROP_SPECULAR_COLOR_UNUSED, rgbColor, setIgnoredColor);
// _constantAttenuation has been renamed to _intensity
READ_ENTITY_PROPERTY(PROP_INTENSITY, float, _intensity);
READ_ENTITY_PROPERTY(PROP_INTENSITY, float, setIntensity);
// Linear and quadratic attenuation are from an older format and are no longer supported.
// Their values will be ignored.
READ_ENTITY_PROPERTY(PROP_LINEAR_ATTENUATION_UNUSED, float, ignoredAttenuation);
READ_ENTITY_PROPERTY(PROP_QUADRATIC_ATTENUATION_UNUSED, float, ignoredAttenuation);
READ_ENTITY_PROPERTY(PROP_LINEAR_ATTENUATION_UNUSED, float, setIgnoredAttenuation);
READ_ENTITY_PROPERTY(PROP_QUADRATIC_ATTENUATION_UNUSED, float, setIgnoredAttenuation);
READ_ENTITY_PROPERTY(PROP_EXPONENT, float, _exponent);
READ_ENTITY_PROPERTY(PROP_CUTOFF, float, _cutoff);
(void) ignoredAttenuation; // suppress compiler warning
READ_ENTITY_PROPERTY(PROP_EXPONENT, float, setExponent);
READ_ENTITY_PROPERTY(PROP_CUTOFF, float, setCutoff);
} else {
READ_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, bool, _isSpotlight);
READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color);
READ_ENTITY_PROPERTY(PROP_INTENSITY, float, _intensity);
READ_ENTITY_PROPERTY(PROP_EXPONENT, float, _exponent);
READ_ENTITY_PROPERTY(PROP_CUTOFF, float, _cutoff);
READ_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, bool, setIsSpotlight);
READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor);
READ_ENTITY_PROPERTY(PROP_INTENSITY, float, setIntensity);
READ_ENTITY_PROPERTY(PROP_EXPONENT, float, setExponent);
READ_ENTITY_PROPERTY(PROP_CUTOFF, float, setCutoff);
}
return bytesRead;
@ -181,9 +176,9 @@ void LightEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, appendValue, getIsSpotlight());
APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor());
APPEND_ENTITY_PROPERTY(PROP_INTENSITY, appendValue, getIntensity());
APPEND_ENTITY_PROPERTY(PROP_EXPONENT, appendValue, getExponent());
APPEND_ENTITY_PROPERTY(PROP_CUTOFF, appendValue, getCutoff());
APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, getIsSpotlight());
APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor());
APPEND_ENTITY_PROPERTY(PROP_INTENSITY, getIntensity());
APPEND_ENTITY_PROPERTY(PROP_EXPONENT, getExponent());
APPEND_ENTITY_PROPERTY(PROP_CUTOFF, getCutoff());
}

View file

@ -58,6 +58,9 @@ public:
bool getIsSpotlight() const { return _isSpotlight; }
void setIsSpotlight(bool value);
void setIgnoredColor(const rgbColor& value) { }
void setIgnoredAttenuation(float value) { }
float getIntensity() const { return _intensity; }
void setIntensity(float value) { _intensity = value; }

View file

@ -71,7 +71,7 @@ int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
int bytesRead = 0;
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color);
READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor);
return bytesRead;
}
@ -94,7 +94,7 @@ void LineEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor());
APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor());
}
void LineEntityItem::debugDump() const {

View file

@ -95,16 +95,16 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
int bytesRead = 0;
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color);
READ_ENTITY_PROPERTY_STRING(PROP_MODEL_URL, setModelURL);
READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor);
READ_ENTITY_PROPERTY(PROP_MODEL_URL, QString, setModelURL);
if (args.bitstreamVersion < VERSION_ENTITIES_HAS_COLLISION_MODEL) {
setCompoundShapeURL("");
} else if (args.bitstreamVersion == VERSION_ENTITIES_HAS_COLLISION_MODEL) {
READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL);
READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL);
} else {
READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL);
READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL);
}
READ_ENTITY_PROPERTY_STRING(PROP_ANIMATION_URL, setAnimationURL);
READ_ENTITY_PROPERTY(PROP_ANIMATION_URL, QString, setAnimationURL);
// Because we're using AnimationLoop which will reset the frame index if you change it's running state
// we want to read these values in the order they appear in the buffer, but call our setters in an
@ -112,9 +112,9 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
float animationFPS = getAnimationFPS();
float animationFrameIndex = getAnimationFrameIndex();
bool animationIsPlaying = getAnimationIsPlaying();
READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, animationFPS);
READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, animationFrameIndex);
READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, animationIsPlaying);
READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, setAnimationFPS);
READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex);
READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, setAnimationIsPlaying);
if (propertyFlags.getHasProperty(PROP_ANIMATION_PLAYING)) {
if (animationIsPlaying != getAnimationIsPlaying()) {
@ -128,9 +128,9 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
setAnimationFrameIndex(animationFrameIndex);
}
READ_ENTITY_PROPERTY_STRING(PROP_TEXTURES, setTextures);
READ_ENTITY_PROPERTY_STRING(PROP_ANIMATION_SETTINGS, setAnimationSettings);
READ_ENTITY_PROPERTY_SETTER(PROP_SHAPE_TYPE, ShapeType, updateShapeType);
READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures);
READ_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, QString, setAnimationSettings);
READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, updateShapeType);
return bytesRead;
}
@ -162,16 +162,16 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor());
APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, getModelURL());
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, getCompoundShapeURL());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, appendValue, getAnimationURL());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, getAnimationFPS());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, getAnimationFrameIndex());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, appendValue, getAnimationIsPlaying());
APPEND_ENTITY_PROPERTY(PROP_TEXTURES, appendValue, getTextures());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, appendValue, getAnimationSettings());
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, appendValue, (uint32_t)getShapeType());
APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor());
APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, getModelURL());
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, getCompoundShapeURL());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, getAnimationURL());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, getAnimationFPS());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, getAnimationFrameIndex());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, getAnimationIsPlaying());
APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, getAnimationSettings());
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType());
}

View file

@ -153,7 +153,7 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch
int bytesRead = 0;
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color);
READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor);
// Because we're using AnimationLoop which will reset the frame index if you change it's running state
// we want to read these values in the order they appear in the buffer, but call our setters in an
@ -161,9 +161,9 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch
float animationFPS = getAnimationFPS();
float animationFrameIndex = getAnimationFrameIndex();
bool animationIsPlaying = getAnimationIsPlaying();
READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, animationFPS);
READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, animationFrameIndex);
READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, animationIsPlaying);
READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, setAnimationFPS);
READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex);
READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, setAnimationIsPlaying);
if (propertyFlags.getHasProperty(PROP_ANIMATION_PLAYING)) {
if (animationIsPlaying != getAnimationIsPlaying()) {
@ -177,16 +177,16 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch
setAnimationFrameIndex(animationFrameIndex);
}
READ_ENTITY_PROPERTY_STRING(PROP_ANIMATION_SETTINGS, setAnimationSettings);
READ_ENTITY_PROPERTY_SETTER(PROP_SHAPE_TYPE, ShapeType, updateShapeType);
READ_ENTITY_PROPERTY(PROP_MAX_PARTICLES, quint32, _maxParticles);
READ_ENTITY_PROPERTY(PROP_LIFESPAN, float, _lifespan);
READ_ENTITY_PROPERTY(PROP_EMIT_RATE, float, _emitRate);
READ_ENTITY_PROPERTY_SETTER(PROP_EMIT_DIRECTION, glm::vec3, setEmitDirection);
READ_ENTITY_PROPERTY(PROP_EMIT_STRENGTH, float, _emitStrength);
READ_ENTITY_PROPERTY(PROP_LOCAL_GRAVITY, float, _localGravity);
READ_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float, _particleRadius);
READ_ENTITY_PROPERTY_STRING(PROP_TEXTURES, setTextures);
READ_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, QString, setAnimationSettings);
READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, updateShapeType);
READ_ENTITY_PROPERTY(PROP_MAX_PARTICLES, quint32, setMaxParticles);
READ_ENTITY_PROPERTY(PROP_LIFESPAN, float, setLifespan);
READ_ENTITY_PROPERTY(PROP_EMIT_RATE, float, setEmitRate);
READ_ENTITY_PROPERTY(PROP_EMIT_DIRECTION, glm::vec3, setEmitDirection);
READ_ENTITY_PROPERTY(PROP_EMIT_STRENGTH, float, setEmitStrength);
READ_ENTITY_PROPERTY(PROP_LOCAL_GRAVITY, float, setLocalGravity);
READ_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float, setParticleRadius);
READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures);
return bytesRead;
}
@ -223,20 +223,20 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData,
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, getAnimationFPS());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, getAnimationFrameIndex());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, appendValue, getAnimationIsPlaying());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, appendValue, getAnimationSettings());
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, appendValue, (uint32_t)getShapeType());
APPEND_ENTITY_PROPERTY(PROP_MAX_PARTICLES, appendValue, getMaxParticles());
APPEND_ENTITY_PROPERTY(PROP_LIFESPAN, appendValue, getLifespan());
APPEND_ENTITY_PROPERTY(PROP_EMIT_RATE, appendValue, getEmitRate());
APPEND_ENTITY_PROPERTY(PROP_EMIT_DIRECTION, appendValue, getEmitDirection());
APPEND_ENTITY_PROPERTY(PROP_EMIT_STRENGTH, appendValue, getEmitStrength());
APPEND_ENTITY_PROPERTY(PROP_LOCAL_GRAVITY, appendValue, getLocalGravity());
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, appendValue, getParticleRadius());
APPEND_ENTITY_PROPERTY(PROP_TEXTURES, appendValue, getTextures());
APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, getAnimationFPS());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, getAnimationFrameIndex());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, getAnimationIsPlaying());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, getAnimationSettings());
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType());
APPEND_ENTITY_PROPERTY(PROP_MAX_PARTICLES, getMaxParticles());
APPEND_ENTITY_PROPERTY(PROP_LIFESPAN, getLifespan());
APPEND_ENTITY_PROPERTY(PROP_EMIT_RATE, getEmitRate());
APPEND_ENTITY_PROPERTY(PROP_EMIT_DIRECTION, getEmitDirection());
APPEND_ENTITY_PROPERTY(PROP_EMIT_STRENGTH, getEmitStrength());
APPEND_ENTITY_PROPERTY(PROP_LOCAL_GRAVITY, getLocalGravity());
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, getParticleRadius());
APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures());
}
bool ParticleEffectEntityItem::isAnimatingSomething() const {

View file

@ -32,6 +32,7 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) {
SharedNodePointer ownerNode = nodeList->nodeWithUUID(entity->getSimulatorID());
if (ownerNode.isNull() || !ownerNode->isAlive()) {
qCDebug(entities) << "auto-removing simulation owner" << entity->getSimulatorID();
// TODO: zero velocities when we clear simulatorID?
entity->setSimulatorID(QUuid());
itemItr = _hasSimulationOwnerEntities.erase(itemItr);
} else {

View file

@ -21,13 +21,13 @@ SkyboxPropertyGroup::SkyboxPropertyGroup() {
}
void SkyboxPropertyGroup::copyToScriptValue(QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_COLOR(Skybox, skybox, Color, color);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Skybox, skybox, Color, color);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Skybox, skybox, URL, url);
}
void SkyboxPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) {
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_COLOR(skybox, color, setColor);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_STRING(skybox, url, setURL);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(skybox, color, xColor, setColor);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(skybox, url, QString, setURL);
}
void SkyboxPropertyGroup::debugDump() const {
@ -45,8 +45,8 @@ bool SkyboxPropertyGroup::appentToEditPacket(OctreePacketData* packetData,
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_SKYBOX_COLOR, appendColor, getColor());
APPEND_ENTITY_PROPERTY(PROP_SKYBOX_URL, appendValue, getURL());
APPEND_ENTITY_PROPERTY(PROP_SKYBOX_COLOR, getColor());
APPEND_ENTITY_PROPERTY(PROP_SKYBOX_URL, getURL());
return true;
}
@ -57,8 +57,8 @@ bool SkyboxPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlag
int bytesRead = 0;
bool overwriteLocalData = true;
READ_ENTITY_PROPERTY_XCOLOR(PROP_SKYBOX_COLOR, _color);
READ_ENTITY_PROPERTY_STRING(PROP_SKYBOX_URL, setURL);
READ_ENTITY_PROPERTY(PROP_SKYBOX_COLOR, xColor, setColor);
READ_ENTITY_PROPERTY(PROP_SKYBOX_URL, QString, setURL);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_SKYBOX_COLOR, Color);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_SKYBOX_URL, URL);
@ -115,8 +115,8 @@ void SkyboxPropertyGroup::appendSubclassData(OctreePacketData* packetData, Encod
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_SKYBOX_COLOR, appendColor, getColor());
APPEND_ENTITY_PROPERTY(PROP_SKYBOX_URL, appendValue, getURL());
APPEND_ENTITY_PROPERTY(PROP_SKYBOX_COLOR, getColor());
APPEND_ENTITY_PROPERTY(PROP_SKYBOX_URL, getURL());
}
int SkyboxPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
@ -126,8 +126,8 @@ int SkyboxPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* d
int bytesRead = 0;
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY_XCOLOR(PROP_SKYBOX_COLOR, _color);
READ_ENTITY_PROPERTY_STRING(PROP_SKYBOX_URL, setURL);
READ_ENTITY_PROPERTY(PROP_SKYBOX_COLOR, xColor, setColor);
READ_ENTITY_PROPERTY(PROP_SKYBOX_URL, QString, setURL);
return bytesRead;
}

View file

@ -67,7 +67,7 @@ int SphereEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data
int bytesRead = 0;
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color);
READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor);
return bytesRead;
}
@ -89,7 +89,7 @@ void SphereEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBi
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor());
APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor());
}
bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,

View file

@ -49,20 +49,20 @@ void StagePropertyGroup::copyToScriptValue(QScriptValue& properties, QScriptEngi
void StagePropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) {
// Backward compatibility support for the old way of doing stage properties
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL_GETTER(stageSunModelEnabled, setSunModelEnabled, getSunModelEnabled);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT_GETTER(stageLatitude, setLatitude, getLatitude);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT_GETTER(stageLongitude, setLongitude, getLongitude);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT_GETTER(stageAltitude, setAltitude, getAltitude);
COPY_PROPERTY_FROM_QSCRIPTVALUE_INT_GETTER(stageDay, setDay, getDay);
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT_GETTER(stageHour, setHour, getHour);
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(stageSunModelEnabled, bool, setSunModelEnabled, getSunModelEnabled);
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(stageLatitude, float, setLatitude, getLatitude);
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(stageLongitude, float, setLongitude, getLongitude);
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(stageAltitude, float, setAltitude, getAltitude);
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(stageDay, uint16_t, setDay, getDay);
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(stageHour, float, setHour, getHour);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_BOOL(stage, sunModelEnabled, setSunModelEnabled);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(stage, latitude, setLatitude);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(stage, longitude, setLongitude);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(stage, altitude, setAltitude);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_UINT16(stage, day, setDay);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(stage, hour, setHour);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_BOOL(stage, automaticHourDay, setAutomaticHourDay);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(stage, sunModelEnabled, bool, setSunModelEnabled);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(stage, latitude, float, setLatitude);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(stage, longitude, float, setLongitude);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(stage, altitude, float, setAltitude);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(stage, day, uint16_t, setDay);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(stage, hour, float, setHour);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(stage, automaticHourDay, bool, setAutomaticHourDay);
}
void StagePropertyGroup::debugDump() const {
@ -85,13 +85,13 @@ bool StagePropertyGroup::appentToEditPacket(OctreePacketData* packetData,
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_STAGE_SUN_MODEL_ENABLED, appendValue, getSunModelEnabled());
APPEND_ENTITY_PROPERTY(PROP_STAGE_LATITUDE, appendValue, getLatitude());
APPEND_ENTITY_PROPERTY(PROP_STAGE_LONGITUDE, appendValue, getLongitude());
APPEND_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, appendValue, getAltitude());
APPEND_ENTITY_PROPERTY(PROP_STAGE_DAY, appendValue, getDay());
APPEND_ENTITY_PROPERTY(PROP_STAGE_HOUR, appendValue, getHour());
APPEND_ENTITY_PROPERTY(PROP_STAGE_AUTOMATIC_HOURDAY, appendValue, getAutomaticHourDay());
APPEND_ENTITY_PROPERTY(PROP_STAGE_SUN_MODEL_ENABLED, getSunModelEnabled());
APPEND_ENTITY_PROPERTY(PROP_STAGE_LATITUDE, getLatitude());
APPEND_ENTITY_PROPERTY(PROP_STAGE_LONGITUDE, getLongitude());
APPEND_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, getAltitude());
APPEND_ENTITY_PROPERTY(PROP_STAGE_DAY, getDay());
APPEND_ENTITY_PROPERTY(PROP_STAGE_HOUR, getHour());
APPEND_ENTITY_PROPERTY(PROP_STAGE_AUTOMATIC_HOURDAY, getAutomaticHourDay());
return true;
}
@ -102,13 +102,13 @@ bool StagePropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags
int bytesRead = 0;
bool overwriteLocalData = true;
READ_ENTITY_PROPERTY(PROP_STAGE_SUN_MODEL_ENABLED, bool, _sunModelEnabled);
READ_ENTITY_PROPERTY(PROP_STAGE_LATITUDE, float, _latitude);
READ_ENTITY_PROPERTY(PROP_STAGE_LONGITUDE, float, _longitude);
READ_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, float, _altitude);
READ_ENTITY_PROPERTY(PROP_STAGE_DAY, quint16, _day);
READ_ENTITY_PROPERTY(PROP_STAGE_HOUR, float, _hour);
READ_ENTITY_PROPERTY(PROP_STAGE_AUTOMATIC_HOURDAY, bool, _automaticHourDay);
READ_ENTITY_PROPERTY(PROP_STAGE_SUN_MODEL_ENABLED, bool, setSunModelEnabled);
READ_ENTITY_PROPERTY(PROP_STAGE_LATITUDE, float, setLatitude);
READ_ENTITY_PROPERTY(PROP_STAGE_LONGITUDE, float, setLongitude);
READ_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, float, setAltitude);
READ_ENTITY_PROPERTY(PROP_STAGE_DAY, quint16, setDay);
READ_ENTITY_PROPERTY(PROP_STAGE_HOUR, float, setHour);
READ_ENTITY_PROPERTY(PROP_STAGE_AUTOMATIC_HOURDAY, bool, setAutomaticHourDay);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_STAGE_SUN_MODEL_ENABLED, SunModelEnabled);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_STAGE_LATITUDE, Latitude);
@ -195,13 +195,13 @@ void StagePropertyGroup::appendSubclassData(OctreePacketData* packetData, Encode
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_STAGE_SUN_MODEL_ENABLED, appendValue, getSunModelEnabled());
APPEND_ENTITY_PROPERTY(PROP_STAGE_LATITUDE, appendValue, getLatitude());
APPEND_ENTITY_PROPERTY(PROP_STAGE_LONGITUDE, appendValue, getLongitude());
APPEND_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, appendValue, getAltitude());
APPEND_ENTITY_PROPERTY(PROP_STAGE_DAY, appendValue, getDay());
APPEND_ENTITY_PROPERTY(PROP_STAGE_HOUR, appendValue, getHour());
APPEND_ENTITY_PROPERTY(PROP_STAGE_AUTOMATIC_HOURDAY, appendValue, getAutomaticHourDay());
APPEND_ENTITY_PROPERTY(PROP_STAGE_SUN_MODEL_ENABLED, getSunModelEnabled());
APPEND_ENTITY_PROPERTY(PROP_STAGE_LATITUDE, getLatitude());
APPEND_ENTITY_PROPERTY(PROP_STAGE_LONGITUDE, getLongitude());
APPEND_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, getAltitude());
APPEND_ENTITY_PROPERTY(PROP_STAGE_DAY, getDay());
APPEND_ENTITY_PROPERTY(PROP_STAGE_HOUR, getHour());
APPEND_ENTITY_PROPERTY(PROP_STAGE_AUTOMATIC_HOURDAY, getAutomaticHourDay());
}
int StagePropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
@ -211,13 +211,13 @@ int StagePropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* da
int bytesRead = 0;
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY(PROP_STAGE_SUN_MODEL_ENABLED, bool, _sunModelEnabled);
READ_ENTITY_PROPERTY(PROP_STAGE_LATITUDE, float, _latitude);
READ_ENTITY_PROPERTY(PROP_STAGE_LONGITUDE, float, _longitude);
READ_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, float, _altitude);
READ_ENTITY_PROPERTY(PROP_STAGE_DAY, quint16, _day);
READ_ENTITY_PROPERTY(PROP_STAGE_HOUR, float, _hour);
READ_ENTITY_PROPERTY(PROP_STAGE_AUTOMATIC_HOURDAY, bool, _automaticHourDay);
READ_ENTITY_PROPERTY(PROP_STAGE_SUN_MODEL_ENABLED, bool, setSunModelEnabled);
READ_ENTITY_PROPERTY(PROP_STAGE_LATITUDE, float, setLatitude);
READ_ENTITY_PROPERTY(PROP_STAGE_LONGITUDE, float, setLongitude);
READ_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, float, setAltitude);
READ_ENTITY_PROPERTY(PROP_STAGE_DAY, quint16, setDay);
READ_ENTITY_PROPERTY(PROP_STAGE_HOUR, float, setHour);
READ_ENTITY_PROPERTY(PROP_STAGE_AUTOMATIC_HOURDAY, bool, setAutomaticHourDay);
return bytesRead;
}

View file

@ -88,10 +88,10 @@ int TextEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
int bytesRead = 0;
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY_STRING(PROP_TEXT, setText);
READ_ENTITY_PROPERTY(PROP_LINE_HEIGHT, float, _lineHeight);
READ_ENTITY_PROPERTY_COLOR(PROP_TEXT_COLOR, _textColor);
READ_ENTITY_PROPERTY_COLOR(PROP_BACKGROUND_COLOR, _backgroundColor);
READ_ENTITY_PROPERTY(PROP_TEXT, QString, setText);
READ_ENTITY_PROPERTY(PROP_LINE_HEIGHT, float, setLineHeight);
READ_ENTITY_PROPERTY(PROP_TEXT_COLOR, rgbColor, setTextColor);
READ_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, rgbColor, setBackgroundColor);
return bytesRead;
}
@ -117,10 +117,10 @@ void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_TEXT, appendValue, getText());
APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, appendValue, getLineHeight());
APPEND_ENTITY_PROPERTY(PROP_TEXT_COLOR, appendColor, getTextColor());
APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, appendColor, getBackgroundColor());
APPEND_ENTITY_PROPERTY(PROP_TEXT, getText());
APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, getLineHeight());
APPEND_ENTITY_PROPERTY(PROP_TEXT_COLOR, getTextColor());
APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, getBackgroundColor());
}

View file

@ -75,7 +75,7 @@ int WebEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, i
int bytesRead = 0;
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY_STRING(PROP_SOURCE_URL, setSourceUrl);
READ_ENTITY_PROPERTY(PROP_SOURCE_URL, QString, setSourceUrl);
return bytesRead;
}
@ -97,7 +97,7 @@ void WebEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitst
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, appendValue, _sourceUrl);
APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, _sourceUrl);
}

View file

@ -135,10 +135,10 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
int bytesRead = 0;
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY_COLOR(PROP_KEYLIGHT_COLOR, _keyLightColor);
READ_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, float, _keyLightIntensity);
READ_ENTITY_PROPERTY(PROP_KEYLIGHT_AMBIENT_INTENSITY, float, _keyLightAmbientIntensity);
READ_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, glm::vec3, _keyLightDirection);
READ_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, rgbColor, setKeyLightColor);
READ_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, float, setKeyLightIntensity);
READ_ENTITY_PROPERTY(PROP_KEYLIGHT_AMBIENT_INTENSITY, float, setKeyLightAmbientIntensity);
READ_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, glm::vec3, setKeyLightDirection);
int bytesFromStage = _stageProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData);
@ -146,9 +146,9 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
bytesRead += bytesFromStage;
dataAt += bytesFromStage;
READ_ENTITY_PROPERTY_SETTER(PROP_SHAPE_TYPE, ShapeType, updateShapeType);
READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL);
READ_ENTITY_PROPERTY_SETTER(PROP_BACKGROUND_MODE, BackgroundMode, setBackgroundMode);
READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, updateShapeType);
READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL);
READ_ENTITY_PROPERTY(PROP_BACKGROUND_MODE, BackgroundMode, setBackgroundMode);
int bytesFromAtmosphere = _atmosphereProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData);
@ -193,18 +193,18 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, appendColor, _keyLightColor);
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, appendValue, getKeyLightIntensity());
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_AMBIENT_INTENSITY, appendValue, getKeyLightAmbientIntensity());
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, appendValue, getKeyLightDirection());
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, _keyLightColor);
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, getKeyLightIntensity());
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_AMBIENT_INTENSITY, getKeyLightAmbientIntensity());
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, getKeyLightDirection());
_stageProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState);
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, appendValue, (uint32_t)getShapeType());
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, getCompoundShapeURL());
APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_MODE, appendValue, (uint32_t)getBackgroundMode()); // could this be a uint16??
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType());
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, getCompoundShapeURL());
APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_MODE, (uint32_t)getBackgroundMode()); // could this be a uint16??
_atmosphereProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState);

View file

@ -51,6 +51,12 @@ public:
_keyLightColor[BLUE_INDEX] = value.blue;
}
void setKeyLightColor(const rgbColor& value) {
_keyLightColor[RED_INDEX] = value[RED_INDEX];
_keyLightColor[GREEN_INDEX] = value[GREEN_INDEX];
_keyLightColor[BLUE_INDEX] = value[BLUE_INDEX];
}
glm::vec3 getKeyLightColorVec3() const {
const quint8 MAX_COLOR = 255;
glm::vec3 color = { (float)_keyLightColor[RED_INDEX] / (float)MAX_COLOR,

View file

@ -28,6 +28,8 @@
#include <NumericalConstants.h>
#include <OctalCode.h>
#include <Shape.h>
#include <gpu/Format.h>
#include <LogHandler.h>
#include "FBXReader.h"
#include "ModelFormatLogging.h"
@ -1276,6 +1278,153 @@ FBXLight extractLight(const FBXNode& object) {
return light;
}
#if USE_MODEL_MESH
void buildModelMesh(ExtractedMesh& extracted) {
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("buildModelMesh failed -- .*");
if (extracted.mesh.vertices.size() == 0) {
extracted.mesh._mesh = model::Mesh();
qCDebug(modelformat) << "buildModelMesh failed -- no vertices";
return;
}
FBXMesh& fbxMesh = extracted.mesh;
model::Mesh mesh;
// Grab the vertices in a buffer
gpu::BufferPointer vb(new gpu::Buffer());
vb->setData(extracted.mesh.vertices.size() * sizeof(glm::vec3),
(const gpu::Byte*) extracted.mesh.vertices.data());
gpu::BufferView vbv(vb, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
mesh.setVertexBuffer(vbv);
// evaluate all attribute channels sizes
int normalsSize = fbxMesh.normals.size() * sizeof(glm::vec3);
int tangentsSize = fbxMesh.tangents.size() * sizeof(glm::vec3);
int colorsSize = fbxMesh.colors.size() * sizeof(glm::vec3);
int texCoordsSize = fbxMesh.texCoords.size() * sizeof(glm::vec2);
int texCoords1Size = fbxMesh.texCoords1.size() * sizeof(glm::vec2);
int clusterIndicesSize = fbxMesh.clusterIndices.size() * sizeof(glm::vec4);
int clusterWeightsSize = fbxMesh.clusterWeights.size() * sizeof(glm::vec4);
int normalsOffset = 0;
int tangentsOffset = normalsOffset + normalsSize;
int colorsOffset = tangentsOffset + tangentsSize;
int texCoordsOffset = colorsOffset + colorsSize;
int texCoords1Offset = texCoordsOffset + texCoordsSize;
int clusterIndicesOffset = texCoords1Offset + texCoords1Size;
int clusterWeightsOffset = clusterIndicesOffset + clusterIndicesSize;
int totalAttributeSize = clusterWeightsOffset + clusterWeightsSize;
// Copy all attribute data in a single attribute buffer
gpu::BufferPointer attribBuffer(new gpu::Buffer());
attribBuffer->resize(totalAttributeSize);
attribBuffer->setSubData(normalsOffset, normalsSize, (gpu::Byte*) fbxMesh.normals.constData());
attribBuffer->setSubData(tangentsOffset, tangentsSize, (gpu::Byte*) fbxMesh.tangents.constData());
attribBuffer->setSubData(colorsOffset, colorsSize, (gpu::Byte*) fbxMesh.colors.constData());
attribBuffer->setSubData(texCoordsOffset, texCoordsSize, (gpu::Byte*) fbxMesh.texCoords.constData());
attribBuffer->setSubData(texCoords1Offset, texCoords1Size, (gpu::Byte*) fbxMesh.texCoords1.constData());
attribBuffer->setSubData(clusterIndicesOffset, clusterIndicesSize, (gpu::Byte*) fbxMesh.clusterIndices.constData());
attribBuffer->setSubData(clusterWeightsOffset, clusterWeightsSize, (gpu::Byte*) fbxMesh.clusterWeights.constData());
if (normalsSize) {
mesh.addAttribute(gpu::Stream::NORMAL,
model::BufferView(attribBuffer, normalsOffset, normalsSize,
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)));
}
if (tangentsSize) {
mesh.addAttribute(gpu::Stream::TANGENT,
model::BufferView(attribBuffer, tangentsOffset, tangentsSize,
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)));
}
if (colorsSize) {
mesh.addAttribute(gpu::Stream::COLOR,
model::BufferView(attribBuffer, colorsOffset, colorsSize,
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB)));
}
if (texCoordsSize) {
mesh.addAttribute(gpu::Stream::TEXCOORD,
model::BufferView( attribBuffer, texCoordsOffset, texCoordsSize,
gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV)));
}
if (texCoords1Size) {
mesh.addAttribute(gpu::Stream::TEXCOORD1,
model::BufferView(attribBuffer, texCoords1Offset, texCoords1Size,
gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV)));
}
if (clusterIndicesSize) {
mesh.addAttribute(gpu::Stream::SKIN_CLUSTER_INDEX,
model::BufferView(attribBuffer, clusterIndicesOffset, clusterIndicesSize,
gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW)));
}
if (clusterWeightsSize) {
mesh.addAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT,
model::BufferView(attribBuffer, clusterWeightsOffset, clusterWeightsSize,
gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW)));
}
unsigned int totalIndices = 0;
foreach(const FBXMeshPart& part, extracted.mesh.parts) {
totalIndices += (part.quadIndices.size() + part.triangleIndices.size());
}
if (! totalIndices) {
extracted.mesh._mesh = model::Mesh();
qCDebug(modelformat) << "buildModelMesh failed -- no indices";
return;
}
gpu::BufferPointer ib(new gpu::Buffer());
ib->resize(totalIndices * sizeof(int));
int indexNum = 0;
int offset = 0;
std::vector< model::Mesh::Part > parts;
foreach(const FBXMeshPart& part, extracted.mesh.parts) {
model::Mesh::Part quadPart(indexNum, part.quadIndices.size(), 0, model::Mesh::QUADS);
if (quadPart._numIndices) {
parts.push_back(quadPart);
ib->setSubData(offset, part.quadIndices.size() * sizeof(int),
(gpu::Byte*) part.quadIndices.constData());
offset += part.quadIndices.size() * sizeof(int);
indexNum += part.quadIndices.size();
}
model::Mesh::Part triPart(indexNum, part.triangleIndices.size(), 0, model::Mesh::TRIANGLES);
if (triPart._numIndices) {
ib->setSubData(offset, part.triangleIndices.size() * sizeof(int),
(gpu::Byte*) part.triangleIndices.constData());
offset += part.triangleIndices.size() * sizeof(int);
indexNum += part.triangleIndices.size();
}
}
gpu::BufferView ibv(ib, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::XYZ));
mesh.setIndexBuffer(ibv);
if (parts.size()) {
gpu::BufferPointer pb(new gpu::Buffer());
pb->setData(parts.size() * sizeof(model::Mesh::Part), (const gpu::Byte*) parts.data());
gpu::BufferView pbv(pb, gpu::Element(gpu::VEC4, gpu::UINT32, gpu::XYZW));
mesh.setPartBuffer(pbv);
} else {
extracted.mesh._mesh = model::Mesh();
qCDebug(modelformat) << "buildModelMesh failed -- no parts";
return;
}
// model::Box box =
mesh.evalPartBound(0);
extracted.mesh._mesh = mesh;
}
#endif // USE_MODEL_MESH
FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, bool loadLightmaps, float lightmapLevel) {
QHash<QString, ExtractedMesh> meshes;
QHash<QString, QString> modelIDsToNames;
@ -2431,6 +2580,10 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping,
}
}
extracted.mesh.isEye = (maxJointIndex == geometry.leftEyeJointIndex || maxJointIndex == geometry.rightEyeJointIndex);
# if USE_MODEL_MESH
buildModelMesh(extracted);
# endif
geometry.meshes.append(extracted.mesh);
int meshIndex = geometry.meshes.size() - 1;

View file

@ -12,6 +12,8 @@
#ifndef hifi_FBXReader_h
#define hifi_FBXReader_h
#define USE_MODEL_MESH 1
#include <QMetaType>
#include <QUrl>
#include <QVarLengthArray>
@ -154,6 +156,9 @@ public:
bool hasEmissiveTexture() const;
unsigned int meshIndex; // the order the meshes appeared in the object file
# if USE_MODEL_MESH
model::Mesh _mesh;
# endif
};
/// A single animation frame extracted from an FBX document.

View file

@ -10,6 +10,7 @@
//
#include "GPULogging.h"
#include "GLBackendShared.h"
#include <glm/gtc/type_ptr.hpp>
GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
{
@ -521,3 +522,29 @@ void GLBackend::do_glColor4f(Batch& batch, uint32 paramOffset) {
(void) CHECK_GL_ERROR();
}
void GLBackend::loadMatrix(GLenum target, const glm::mat4 & m) {
glMatrixMode(target);
glLoadMatrixf(glm::value_ptr(m));
}
void GLBackend::fetchMatrix(GLenum target, glm::mat4 & m) {
switch (target) {
case GL_MODELVIEW_MATRIX:
case GL_PROJECTION_MATRIX:
break;
// Lazy cheating
case GL_MODELVIEW:
target = GL_MODELVIEW_MATRIX;
break;
case GL_PROJECTION:
target = GL_PROJECTION_MATRIX;
break;
default:
Q_ASSERT_X(false, "GLBackend::fetchMatrix", "Bad matrix target");
}
glGetFloatv(target, glm::value_ptr(m));
}

View file

@ -79,6 +79,9 @@ public:
static GLShader* syncGPUObject(const Shader& shader);
static GLuint getShaderID(const ShaderPointer& shader);
static void loadMatrix(GLenum target, const glm::mat4 & m);
static void fetchMatrix(GLenum target, glm::mat4 & m);
class GLState : public GPUObject {
public:
class Command {

View file

@ -57,7 +57,7 @@ const Texture::PixelsPointer Texture::Storage::getMipFace(uint16 level, uint8 fa
void Texture::Storage::notifyMipFaceGPULoaded(uint16 level, uint8 face) const {
PixelsPointer mipFace = getMipFace(level, face);
if (mipFace) {
if (mipFace && (_type != TEX_CUBE)) {
mipFace->_isGPULoaded = true;
mipFace->_sysmem.resize(0);
}

View file

@ -127,7 +127,7 @@ public:
CUBE_FACE_LEFT_NEG_X,
CUBE_FACE_TOP_POS_Y,
CUBE_FACE_BOTTOM_NEG_Y,
CUBE_FACE_BACK_POS_X,
CUBE_FACE_BACK_POS_Z,
CUBE_FACE_FRONT_NEG_Z,
NUM_CUBE_FACES, // Not a valid vace index

View file

@ -99,3 +99,6 @@ void Light::setShowContour(float show) {
}
editSchema()._control.w = show;
}

View file

@ -180,6 +180,7 @@ public:
}
}
};
typedef std::shared_ptr< SphericalHarmonics > SHPointer;
class Light {
public:

View file

@ -39,6 +39,9 @@ void Skybox::setColor(const Color& color) {
}
void Skybox::setCubemap(const gpu::TexturePointer& cubemap) {
if (_isSHValid && (cubemap != _cubemap)) {
_isSHValid = false;
}
_cubemap = cubemap;
}
@ -49,6 +52,9 @@ void Skybox::clearCubemap() {
void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Skybox& skybox) {
if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) {
skybox.getIrradianceSH();
static gpu::PipelinePointer thePipeline;
static gpu::BufferPointer theBuffer;
static gpu::Stream::FormatPointer theFormat;
@ -113,3 +119,223 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(skybox.getColor(),1.0f), 0.f, 0);
}
}
glm::vec3 sRGBToLinear(glm::vec3& color) {
const float GAMMA_CORRECTION = 2.2f;
return glm::pow(color, glm::vec3(GAMMA_CORRECTION));
}
glm::vec3 linearTosRGB(glm::vec3& color) {
const float GAMMA_CORRECTION_INV = 1.0f / 2.2f;
return glm::pow(color, glm::vec3(GAMMA_CORRECTION_INV));
}
// Originial code for the Spherical Harmonics taken from "Sun and Black Cat- Igor Dykhta (igor dykhta email) © 2007-2014 "
void sphericalHarmonicsAdd(float * result, int order, const float * inputA, const float * inputB) {
const int numCoeff = order * order;
for(int i=0; i < numCoeff; i++) {
result[i] = inputA[i] + inputB[i];
}
}
void sphericalHarmonicsScale(float * result, int order, const float * input, float scale) {
const int numCoeff = order * order;
for(int i=0; i < numCoeff; i++) {
result[i] = input[i] * scale;
}
}
void sphericalHarmonicsEvaluateDirection(float * result, int order, const glm::vec3 & dir) {
// calculate coefficients for first 3 bands of spherical harmonics
double P_0_0 = 0.282094791773878140;
double P_1_0 = 0.488602511902919920 * dir.z;
double P_1_1 = -0.488602511902919920;
double P_2_0 = 0.946174695757560080 * dir.z * dir.z - 0.315391565252520050;
double P_2_1 = -1.092548430592079200 * dir.z;
double P_2_2 = 0.546274215296039590;
result[0] = P_0_0;
result[1] = P_1_1 * dir.y;
result[2] = P_1_0;
result[3] = P_1_1 * dir.x;
result[4] = P_2_2 * (dir.x * dir.y + dir.y * dir.x);
result[5] = P_2_1 * dir.y;
result[6] = P_2_0;
result[7] = P_2_1 * dir.x;
result[8] = P_2_2 * (dir.x * dir.x - dir.y * dir.y);
}
void sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<glm::vec3> & output, const uint order) {
const uint sqOrder = order*order;
// allocate memory for calculations
output.resize(sqOrder);
std::vector<float> resultR(sqOrder);
std::vector<float> resultG(sqOrder);
std::vector<float> resultB(sqOrder);
int width, height;
// initialize values
float fWt = 0.0f;
for(uint i=0; i < sqOrder; i++) {
output[i] = glm::vec3(0.0f);
resultR[i] = 0.0f;
resultG[i] = 0;
resultB[i] = 0;
}
std::vector<float> shBuff(sqOrder);
std::vector<float> shBuffB(sqOrder);
// get width and height
width = height = cubeTexture.getWidth();
if(width != height) {
return;
}
const float UCHAR_TO_FLOAT = 1.0f / float(std::numeric_limits<unsigned char>::max());
// for each face of cube texture
for(int face=0; face < gpu::Texture::NUM_CUBE_FACES; face++) {
auto numComponents = cubeTexture.accessStoredMipFace(0,face)->_format.getDimensionCount();
auto data = cubeTexture.accessStoredMipFace(0,face)->_sysmem.readData();
if (data == nullptr) {
continue;
}
// step between two texels for range [0, 1]
float invWidth = 1.0f / float(width);
// initial negative bound for range [-1, 1]
float negativeBound = -1.0f + invWidth;
// step between two texels for range [-1, 1]
float invWidthBy2 = 2.0f / float(width);
for(int y=0; y < width; y++) {
// texture coordinate V in range [-1 to 1]
const float fV = negativeBound + float(y) * invWidthBy2;
for(int x=0; x < width; x++) {
// texture coordinate U in range [-1 to 1]
const float fU = negativeBound + float(x) * invWidthBy2;
// determine direction from center of cube texture to current texel
glm::vec3 dir;
switch(face) {
case gpu::Texture::CUBE_FACE_RIGHT_POS_X: {
dir.x = 1.0f;
dir.y = 1.0f - (invWidthBy2 * float(y) + invWidth);
dir.z = 1.0f - (invWidthBy2 * float(x) + invWidth);
dir = -dir;
break;
}
case gpu::Texture::CUBE_FACE_LEFT_NEG_X: {
dir.x = -1.0f;
dir.y = 1.0f - (invWidthBy2 * float(y) + invWidth);
dir.z = -1.0f + (invWidthBy2 * float(x) + invWidth);
dir = -dir;
break;
}
case gpu::Texture::CUBE_FACE_TOP_POS_Y: {
dir.x = - 1.0f + (invWidthBy2 * float(x) + invWidth);
dir.y = 1.0f;
dir.z = - 1.0f + (invWidthBy2 * float(y) + invWidth);
dir = -dir;
break;
}
case gpu::Texture::CUBE_FACE_BOTTOM_NEG_Y: {
dir.x = - 1.0f + (invWidthBy2 * float(x) + invWidth);
dir.y = - 1.0f;
dir.z = 1.0f - (invWidthBy2 * float(y) + invWidth);
dir = -dir;
break;
}
case gpu::Texture::CUBE_FACE_BACK_POS_Z: {
dir.x = - 1.0f + (invWidthBy2 * float(x) + invWidth);
dir.y = 1.0f - (invWidthBy2 * float(y) + invWidth);
dir.z = 1.0f;
break;
}
case gpu::Texture::CUBE_FACE_FRONT_NEG_Z: {
dir.x = 1.0f - (invWidthBy2 * float(x) + invWidth);
dir.y = 1.0f - (invWidthBy2 * float(y) + invWidth);
dir.z = - 1.0f;
break;
}
default:
return;
}
// normalize direction
dir = glm::normalize(dir);
// scale factor depending on distance from center of the face
const float fDiffSolid = 4.0f / ((1.0f + fU*fU + fV*fV) *
sqrtf(1.0f + fU*fU + fV*fV));
fWt += fDiffSolid;
// calculate coefficients of spherical harmonics for current direction
sphericalHarmonicsEvaluateDirection(shBuff.data(), order, dir);
// index of texel in texture
uint pixOffsetIndex = (x + y * width) * numComponents;
// get color from texture and map to range [0, 1]
glm::vec3 clr(float(data[pixOffsetIndex]) * UCHAR_TO_FLOAT,
float(data[pixOffsetIndex+1]) * UCHAR_TO_FLOAT,
float(data[pixOffsetIndex+2]) * UCHAR_TO_FLOAT);
// Gamma correct
clr = sRGBToLinear(clr);
// scale color and add to previously accumulated coefficients
sphericalHarmonicsScale(shBuffB.data(), order,
shBuff.data(), clr.r * fDiffSolid);
sphericalHarmonicsAdd(resultR.data(), order,
resultR.data(), shBuffB.data());
sphericalHarmonicsScale(shBuffB.data(), order,
shBuff.data(), clr.g * fDiffSolid);
sphericalHarmonicsAdd(resultG.data(), order,
resultG.data(), shBuffB.data());
sphericalHarmonicsScale(shBuffB.data(), order,
shBuff.data(), clr.b * fDiffSolid);
sphericalHarmonicsAdd(resultB.data(), order,
resultB.data(), shBuffB.data());
}
}
}
// final scale for coefficients
const float fNormProj = (4.0f * glm::pi<float>()) / fWt;
sphericalHarmonicsScale(resultR.data(), order, resultR.data(), fNormProj);
sphericalHarmonicsScale(resultG.data(), order, resultG.data(), fNormProj);
sphericalHarmonicsScale(resultB.data(), order, resultB.data(), fNormProj);
// save result
for(uint i=0; i < sqOrder; i++) {
// gamma Correct
// output[i] = linearTosRGB(glm::vec3(resultR[i], resultG[i], resultB[i]));
output[i] = glm::vec3(resultR[i], resultG[i], resultB[i]);
}
}
const SphericalHarmonics& Skybox::getIrradianceSH() const {
if (!_isSHValid) {
if (_cubemap && _cubemap->isDefined()) {
std::vector< glm::vec3 > coefs;
sphericalHarmonicsFromTexture(*_cubemap, coefs, 3);
_irradianceSH.L00 = coefs[0];
_irradianceSH.L1m1 = coefs[1];
_irradianceSH.L10 = coefs[2];
_irradianceSH.L11 = coefs[3];
_irradianceSH.L2m2 = coefs[4];
_irradianceSH.L2m1 = coefs[5];
_irradianceSH.L20 = coefs[6];
_irradianceSH.L21 = coefs[7];
_irradianceSH.L22 = coefs[8];
_isSHValid = true;
}
}
return _irradianceSH;
}

View file

@ -13,6 +13,8 @@
#include "gpu/Texture.h"
#include "Light.h"
class ViewFrustum;
//class Transform;
namespace gpu { class Batch; }
@ -34,11 +36,16 @@ public:
const gpu::TexturePointer& getCubemap() const { return _cubemap; }
void clearCubemap();
const SphericalHarmonics& getIrradianceSH() const;
static void render(gpu::Batch& batch, const ViewFrustum& frustum, const Skybox& skybox);
protected:
gpu::TexturePointer _cubemap;
mutable SphericalHarmonics _irradianceSH;
mutable bool _isSHValid = false;
Color _color{1.0f, 1.0f, 1.0f};
};
typedef std::shared_ptr< Skybox > SkyboxPointer;

View file

@ -20,5 +20,6 @@ varying vec3 color;
void main(void) {
vec3 coord = normalize(normal);
vec4 texel = textureCube(cubeMap, coord);
gl_FragData[0] = vec4(texel.xyz * color, 0.0);
vec3 pixel = pow(texel.xyz * color, vec3(1.0/2.2)); // manual Gamma correction
gl_FragData[0] = vec4(pixel, 0.0);
}

View file

@ -71,14 +71,14 @@ public:
EarthSunModel() { valid(); }
protected:
double _scale = 1000.0; //Km
float _scale = 1000.0f; //Km
double _earthRadius = 6360.0;
Quat _surfaceOrientation;
double _longitude = 0.0;
double _latitude = 0.0;
double _altitude = 0.01;
float _longitude = 0.0f;
float _latitude = 0.0f;
float _altitude = 0.01f;
mutable Vec3d _surfacePos;
mutable Mat4d _worldToSurfaceMat;
mutable Mat4d _surfaceToWorldMat;
@ -93,8 +93,8 @@ protected:
mutable Mat4d _worldToEyeMat;
mutable Mat4d _eyeToWorldMat;
double _sunLongitude = 0.0;
double _sunLatitude = 0.0;
float _sunLongitude = 0.0f;
float _sunLatitude = 0.0f;
mutable Vec3d _sunDir;
mutable Vec3d _surfaceSunDir;
void updateSun() const;

View file

@ -72,7 +72,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
return 1;
case PacketTypeEntityAddOrEdit:
case PacketTypeEntityData:
return VERSION_ENTITIES_HAVE_LINE_TYPE;
return VERSION_ENTITIES_HAVE_FRICTION;
case PacketTypeEntityErase:
return 2;
case PacketTypeAudioStreamStats:

View file

@ -176,5 +176,7 @@ const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_HAVE_SKYBOX = 21;
const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_STAGE_HAS_AUTOMATIC_HOURDAY = 22;
const PacketVersion VERSION_ENTITIES_PARTICLE_ENTITIES_HAVE_TEXTURES = 23;
const PacketVersion VERSION_ENTITIES_HAVE_LINE_TYPE = 24;
const PacketVersion VERSION_ENTITIES_HAVE_COLLISION_SOUND_URL = 25;
const PacketVersion VERSION_ENTITIES_HAVE_FRICTION = 26;
#endif // hifi_PacketHeaders_h

View file

@ -281,15 +281,15 @@ bool OctreePacketData::appendBitMask(unsigned char bitmask) {
return success;
}
bool OctreePacketData::appendColor(const nodeColor& color) {
bool OctreePacketData::appendValue(const nodeColor& color) {
return appendColor(color[RED_INDEX], color[GREEN_INDEX], color[BLUE_INDEX]);
}
bool OctreePacketData::appendColor(const xColor& color) {
bool OctreePacketData::appendValue(const xColor& color) {
return appendColor(color.red, color.green, color.blue);
}
bool OctreePacketData::appendColor(const rgbColor& color) {
bool OctreePacketData::appendValue(const rgbColor& color) {
return appendColor(color[RED_INDEX], color[GREEN_INDEX], color[BLUE_INDEX]);
}
@ -544,3 +544,32 @@ void OctreePacketData::debugContent() {
}
printf("\n");
}
int OctreePacketData::uppackDataFromBytes(const unsigned char* dataBytes, QString& result) {
uint16_t length;
memcpy(&length, dataBytes, sizeof(length));
dataBytes += sizeof(length);
QString value((const char*)dataBytes);
result = value;
return sizeof(length) + length;
}
int OctreePacketData::uppackDataFromBytes(const unsigned char* dataBytes, QUuid& result) {
uint16_t length;
memcpy(&length, dataBytes, sizeof(length));
dataBytes += sizeof(length);
if (length == 0) {
result = QUuid();
} else {
QByteArray ba((const char*)dataBytes, length);
result = QUuid::fromRfc4122(ba);
}
return sizeof(length) + length;
}
int OctreePacketData::uppackDataFromBytes(const unsigned char* dataBytes, xColor& result) {
result.red = dataBytes[RED_INDEX];
result.green = dataBytes[GREEN_INDEX];
result.blue = dataBytes[BLUE_INDEX];
return sizeof(rgbColor);
}

View file

@ -22,9 +22,15 @@
#ifndef hifi_OctreePacketData_h
#define hifi_OctreePacketData_h
#include <QByteArray>
#include <QString>
#include <QUuid>
#include <LimitedNodeList.h> // for MAX_PACKET_SIZE
#include <PacketHeaders.h> // for MAX_PACKET_HEADER_BYTES
#include <SharedUtil.h>
#include <ShapeInfo.h>
#include <BackgroundMode.h>
#include "OctreeConstants.h"
#include "OctreeElement.h"
@ -127,18 +133,18 @@ public:
/// Might fail if the new bytes would cause packet to be less compressed, or if offset and length was out of range.
bool updatePriorBytes(int offset, const unsigned char* replacementBytes, int length);
/// appends a color to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendColor(const nodeColor& color);
/// appends a color to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendColor(const xColor& color);
/// appends a color to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendColor(const rgbColor& color);
/// appends a color to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendColor(colorPart red, colorPart green, colorPart blue);
/// appends a color to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendValue(const nodeColor& color);
/// appends a color to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendValue(const xColor& color);
/// appends a color to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendValue(const rgbColor& color);
/// appends a unsigned 8 bit int to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendValue(uint8_t value);
@ -219,6 +225,21 @@ public:
static quint64 getTotalBytesOfOctalCodes() { return _totalBytesOfOctalCodes; } /// total bytes for octal codes
static quint64 getTotalBytesOfBitMasks() { return _totalBytesOfBitMasks; } /// total bytes of bitmasks
static quint64 getTotalBytesOfColor() { return _totalBytesOfColor; } /// total bytes of color
static int uppackDataFromBytes(const unsigned char* dataBytes, float& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int uppackDataFromBytes(const unsigned char* dataBytes, glm::vec3& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int uppackDataFromBytes(const unsigned char* dataBytes, bool& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int uppackDataFromBytes(const unsigned char* dataBytes, quint64& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int uppackDataFromBytes(const unsigned char* dataBytes, uint32_t& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int uppackDataFromBytes(const unsigned char* dataBytes, uint16_t& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int uppackDataFromBytes(const unsigned char* dataBytes, uint8_t& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int uppackDataFromBytes(const unsigned char* dataBytes, rgbColor& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int uppackDataFromBytes(const unsigned char* dataBytes, glm::quat& result) { int bytes = unpackOrientationQuatFromBytes(dataBytes, result); return bytes; }
static int uppackDataFromBytes(const unsigned char* dataBytes, ShapeType& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int uppackDataFromBytes(const unsigned char* dataBytes, BackgroundMode& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int uppackDataFromBytes(const unsigned char* dataBytes, QString& result);
static int uppackDataFromBytes(const unsigned char* dataBytes, QUuid& result);
static int uppackDataFromBytes(const unsigned char* dataBytes, xColor& result);
private:
/// appends raw bytes, might fail if byte would cause packet to be too large

View file

@ -25,7 +25,7 @@ static const quint8 STEPS_TO_DECIDE_BALLISTIC = 4;
EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItem* entity) :
ObjectMotionState(shape),
_entity(entity),
_sentMoving(false),
_sentActive(false),
_numNonMovingUpdates(0),
_lastStep(0),
_serverPosition(0.0f),
@ -35,8 +35,9 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItem* entity
_serverGravity(0.0f),
_serverAcceleration(0.0f),
_accelerationNearlyGravityCount(0),
_shouldClaimSimulationOwnership(false),
_movingStepsWithoutSimulationOwner(0)
_candidateForOwnership(false),
_loopsSinceOwnershipBid(0),
_loopsWithoutOwner(0)
{
_type = MOTION_STATE_TYPE_ENTITY;
assert(entity != nullptr);
@ -66,6 +67,28 @@ void EntityMotionState::updateServerPhysicsVariables(uint32_t flags) {
void EntityMotionState::handleEasyChanges(uint32_t flags) {
updateServerPhysicsVariables(flags);
ObjectMotionState::handleEasyChanges(flags);
if (flags & EntityItem::DIRTY_SIMULATOR_ID) {
_loopsWithoutOwner = 0;
_candidateForOwnership = 0;
if (_entity->getSimulatorID().isNull()
&& !_entity->isMoving()
&& _body->isActive()) {
// remove the ACTIVATION flag because this object is coming to rest
// according to a remote simulation and we don't want to wake it up again
flags &= ~EntityItem::DIRTY_PHYSICS_ACTIVATION;
_body->setActivationState(WANTS_DEACTIVATION);
} else {
auto nodeList = DependencyManager::get<NodeList>();
const QUuid& sessionID = nodeList->getSessionUUID();
if (_entity->getSimulatorID() != sessionID) {
_loopsSinceOwnershipBid = 0;
}
}
}
if ((flags & EntityItem::DIRTY_PHYSICS_ACTIVATION) && !_body->isActive()) {
_body->activate();
}
}
@ -95,15 +118,6 @@ bool EntityMotionState::isMoving() const {
return _entity && _entity->isMoving();
}
bool EntityMotionState::isMovingVsServer() const {
auto alignmentDot = glm::abs(glm::dot(_serverRotation, _entity->getRotation()));
if (glm::distance(_serverPosition, _entity->getPosition()) > IGNORE_POSITION_DELTA ||
alignmentDot < IGNORE_ALIGNMENT_DOT) {
return true;
}
return false;
}
// This callback is invoked by the physics simulation in two cases:
// (1) when the RigidBody is first added to the world
// (irregardless of MotionType: STATIC, DYNAMIC, or KINEMATIC)
@ -143,19 +157,16 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
_entity->setLastSimulated(usecTimestampNow());
// if (_entity->getSimulatorID().isNull() && isMoving()) {
if (_entity->getSimulatorID().isNull() && isMovingVsServer()) {
// if object is moving and has no owner, attempt to claim simulation ownership.
_movingStepsWithoutSimulationOwner++;
if (_entity->getSimulatorID().isNull()) {
_loopsWithoutOwner++;
const uint32_t OWNERSHIP_BID_DELAY = 50;
if (_loopsWithoutOwner > OWNERSHIP_BID_DELAY) {
//qDebug() << "Warning -- claiming something I saw moving." << getName();
_candidateForOwnership = true;
}
} else {
_movingStepsWithoutSimulationOwner = 0;
}
uint32_t ownershipClaimDelay = 50; // TODO -- how to pick this? based on meters from our characterController?
if (_movingStepsWithoutSimulationOwner > ownershipClaimDelay) {
//qDebug() << "Warning -- claiming something I saw moving." << getName();
setShouldClaimSimulationOwnership(true);
_loopsWithoutOwner = 0;
}
#ifdef WANT_DEBUG
@ -177,8 +188,11 @@ void EntityMotionState::computeObjectShapeInfo(ShapeInfo& shapeInfo) {
// we alwasy resend packets for objects that have stopped moving up to some max limit.
const int MAX_NUM_NON_MOVING_UPDATES = 5;
bool EntityMotionState::doesNotNeedToSendUpdate() const {
return !_body || (_body->isActive() && _numNonMovingUpdates > MAX_NUM_NON_MOVING_UPDATES);
bool EntityMotionState::isCandidateForOwnership(const QUuid& sessionID) const {
if (!_body || !_entity) {
return false;
}
return _candidateForOwnership || sessionID == _entity->getSimulatorID();
}
bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
@ -191,6 +205,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
_serverVelocity = bulletToGLM(_body->getLinearVelocity());
_serverAngularVelocity = bulletToGLM(_body->getAngularVelocity());
_lastStep = simulationStep;
_sentActive = false;
return false;
}
@ -202,21 +217,26 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
int numSteps = simulationStep - _lastStep;
float dt = (float)(numSteps) * PHYSICS_ENGINE_FIXED_SUBSTEP;
_lastStep = simulationStep;
bool isActive = _body->isActive();
const float INACTIVE_UPDATE_PERIOD = 0.5f;
if (!_sentActive) {
// we resend the inactive update every INACTIVE_UPDATE_PERIOD
// until it is removed from the outgoing updates
// (which happens when we don't own the simulation and it isn't touching our simulation)
return (dt > INACTIVE_UPDATE_PERIOD);
}
bool isActive = _body->isActive();
if (!isActive) {
if (_sentMoving) {
// this object just went inactive so send an update immediately
return true;
} else {
const float NON_MOVING_UPDATE_PERIOD = 1.0f;
if (dt > NON_MOVING_UPDATE_PERIOD && _numNonMovingUpdates < MAX_NUM_NON_MOVING_UPDATES) {
// RELIABLE_SEND_HACK: since we're not yet using a reliable method for non-moving update packets we repeat these
// at a faster rate than the MAX period above, and only send a limited number of them.
return true;
}
}
// object has gone inactive but our last send was moving --> send non-moving update immediately
return true;
}
_lastStep = simulationStep;
if (glm::length2(_serverVelocity) > 0.0f) {
_serverVelocity += _serverAcceleration * dt;
_serverVelocity *= powf(1.0f - _body->getLinearDamping(), dt);
_serverPosition += dt * _serverVelocity;
}
// Else we measure the error between current and extrapolated transform (according to expected behavior
@ -224,15 +244,10 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
// NOTE: math is done in the simulation-frame, which is NOT necessarily the same as the world-frame
// due to _worldOffset.
// TODO: compensate for _worldOffset offset here
// compute position error
if (glm::length2(_serverVelocity) > 0.0f) {
_serverVelocity += _serverAcceleration * dt;
_serverVelocity *= powf(1.0f - _body->getLinearDamping(), dt);
_serverPosition += dt * _serverVelocity;
}
// TODO: compensate for simulation offset here
btTransform worldTrans = _body->getWorldTransform();
glm::vec3 position = bulletToGLM(worldTrans.getOrigin());
@ -285,42 +300,50 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
return (fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT);
}
bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) {
if (!_entity || !remoteSimulationOutOfSync(simulationFrame)) {
bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep, const QUuid& sessionID) {
// NOTE: we expect _entity and _body to be valid in this context, since shouldSendUpdate() is only called
// after doesNotNeedToSendUpdate() returns false and that call should return 'true' if _entity or _body are NULL.
assert(_entity);
assert(_body);
if (!remoteSimulationOutOfSync(simulationStep)) {
_candidateForOwnership = false;
return false;
}
if (getShouldClaimSimulationOwnership()) {
if (_entity->getSimulatorID() == sessionID) {
// we own the simulation
_candidateForOwnership = false;
return true;
}
auto nodeList = DependencyManager::get<NodeList>();
const QUuid& myNodeID = nodeList->getSessionUUID();
const QUuid& simulatorID = _entity->getSimulatorID();
if (simulatorID != myNodeID) {
// some other Node owns the simulating of this, so don't broadcast the results of local simulation.
return false;
const uint32_t FRAMES_BETWEEN_OWNERSHIP_CLAIMS = 30;
if (_candidateForOwnership) {
_candidateForOwnership = false;
++_loopsSinceOwnershipBid;
if (_loopsSinceOwnershipBid > FRAMES_BETWEEN_OWNERSHIP_CLAIMS) {
// we don't own the simulation, but it's time to bid for it
_loopsSinceOwnershipBid = 0;
return true;
}
}
return true;
_candidateForOwnership = false;
return false;
}
void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_t step) {
if (!_entity || !_entity->isKnownID()) {
return; // never update entities that are unknown
}
void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const QUuid& sessionID, uint32_t step) {
assert(_entity);
assert(_entity->isKnownID());
bool active = _body->isActive();
if (!active) {
if (_sentMoving) {
// make sure all derivatives are zero
glm::vec3 zero(0.0f);
_entity->setVelocity(zero);
_entity->setAngularVelocity(zero);
_entity->setAcceleration(zero);
}
// make sure all derivatives are zero
glm::vec3 zero(0.0f);
_entity->setVelocity(zero);
_entity->setAngularVelocity(zero);
_entity->setAcceleration(zero);
_sentActive = false;
} else {
float gravityLength = glm::length(_entity->getGravity());
float accVsGravity = glm::abs(glm::length(_measuredAcceleration) - gravityLength);
@ -343,6 +366,21 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
} else {
_entity->setAcceleration(glm::vec3(0.0f));
}
const float DYNAMIC_LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec
const float DYNAMIC_ANGULAR_VELOCITY_THRESHOLD = 0.087266f; // ~5 deg/sec
bool movingSlowly = glm::length2(_entity->getVelocity()) < (DYNAMIC_LINEAR_VELOCITY_THRESHOLD * DYNAMIC_LINEAR_VELOCITY_THRESHOLD)
&& glm::length2(_entity->getAngularVelocity()) < (DYNAMIC_ANGULAR_VELOCITY_THRESHOLD * DYNAMIC_ANGULAR_VELOCITY_THRESHOLD)
&& _entity->getAcceleration() == glm::vec3(0.0f);
if (movingSlowly) {
// velocities might not be zero, but we'll fake them as such, which will hopefully help convince
// other simulating observers to deactivate their own copies
glm::vec3 zero(0.0f);
_entity->setVelocity(zero);
_entity->setAngularVelocity(zero);
}
_sentActive = true;
}
// remember properties for local server prediction
@ -352,59 +390,41 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
_serverAcceleration = _entity->getAcceleration();
_serverAngularVelocity = _entity->getAngularVelocity();
_sentMoving = _serverVelocity != glm::vec3(0.0f) || _serverAngularVelocity != glm::vec3(0.0f);
EntityItemProperties properties = _entity->getProperties();
// explicitly set the properties that changed
// explicitly set the properties that changed so that they will be packed
properties.setPosition(_serverPosition);
properties.setRotation(_serverRotation);
properties.setVelocity(_serverVelocity);
properties.setAcceleration(_serverAcceleration);
properties.setAngularVelocity(_serverAngularVelocity);
// RELIABLE_SEND_HACK: count number of updates for entities at rest
// so we can stop sending them after some limit.
if (_sentMoving) {
_numNonMovingUpdates = 0;
// we only update lastEdited when we're sending new physics data
quint64 lastSimulated = _entity->getLastSimulated();
_entity->setLastEdited(lastSimulated);
properties.setLastEdited(lastSimulated);
#ifdef WANT_DEBUG
quint64 now = usecTimestampNow();
qCDebug(physics) << "EntityMotionState::sendUpdate()";
qCDebug(physics) << " EntityItemId:" << _entity->getEntityItemID()
<< "---------------------------------------------";
qCDebug(physics) << " lastSimulated:" << debugTime(lastSimulated, now);
#endif //def WANT_DEBUG
if (sessionID == _entity->getSimulatorID()) {
// we think we own the simulation
if (!active) {
// we own the simulation but the entity has stopped, so we tell the server that we're clearing simulatorID
// but we remember that we do still own it... and rely on the server to tell us that we don't
properties.setSimulatorID(QUuid());
} else {
// explicitly set the property's simulatorID so that it is flagged as changed and will be packed
properties.setSimulatorID(sessionID);
}
} else {
_numNonMovingUpdates++;
}
if (_numNonMovingUpdates <= 1) {
// we only update lastEdited when we're sending new physics data
quint64 lastSimulated = _entity->getLastSimulated();
_entity->setLastEdited(lastSimulated);
properties.setLastEdited(lastSimulated);
#ifdef WANT_DEBUG
quint64 now = usecTimestampNow();
qCDebug(physics) << "EntityMotionState::sendUpdate()";
qCDebug(physics) << " EntityItemId:" << _entity->getEntityItemID()
<< "---------------------------------------------";
qCDebug(physics) << " lastSimulated:" << debugTime(lastSimulated, now);
#endif //def WANT_DEBUG
} else {
properties.setLastEdited(_entity->getLastEdited());
}
auto nodeList = DependencyManager::get<NodeList>();
QUuid myNodeID = nodeList->getSessionUUID();
QUuid simulatorID = _entity->getSimulatorID();
if (getShouldClaimSimulationOwnership()) {
// we think we should own it, so we tell the server that we do,
// but we don't remember that we own it...
// instead we expect the sever to tell us later whose ownership it has accepted
properties.setSimulatorID(myNodeID);
setShouldClaimSimulationOwnership(false);
} else if (simulatorID == myNodeID
&& !_sentMoving
&& _numNonMovingUpdates == MAX_NUM_NON_MOVING_UPDATES) {
// we own it, the entity has stopped, and we're sending the last non-moving update
// --> give up ownership
_entity->setSimulatorID(QUuid());
properties.setSimulatorID(QUuid());
// we don't own the simulation for this entity yet, but we're sending a bid for it
properties.setSimulatorID(sessionID);
}
if (EntityItem::getSendPhysicsUpdates()) {
@ -453,7 +473,7 @@ QUuid EntityMotionState::getSimulatorID() const {
// virtual
void EntityMotionState::bump() {
setShouldClaimSimulationOwnership(true);
_candidateForOwnership = true;
}
void EntityMotionState::resetMeasuredBodyAcceleration() {

View file

@ -36,7 +36,6 @@ public:
virtual MotionType computeObjectMotionType() const;
virtual bool isMoving() const;
virtual bool isMovingVsServer() const;
// this relays incoming position/rotation to the RigidBody
virtual void getWorldTransform(btTransform& worldTrans) const;
@ -46,13 +45,10 @@ public:
virtual void computeObjectShapeInfo(ShapeInfo& shapeInfo);
bool doesNotNeedToSendUpdate() const;
bool isCandidateForOwnership(const QUuid& sessionID) const;
bool remoteSimulationOutOfSync(uint32_t simulationStep);
bool shouldSendUpdate(uint32_t simulationFrame);
void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t step);
void setShouldClaimSimulationOwnership(bool value) { _shouldClaimSimulationOwnership = value; }
bool getShouldClaimSimulationOwnership() { return _shouldClaimSimulationOwnership; }
bool shouldSendUpdate(uint32_t simulationStep, const QUuid& sessionID);
void sendUpdate(OctreeEditPacketSender* packetSender, const QUuid& sessionID, uint32_t step);
virtual uint32_t getAndClearIncomingDirtyFlags() const;
@ -92,7 +88,7 @@ protected:
EntityItem* _entity;
bool _sentMoving; // true if last update was moving
bool _sentActive; // true if body was active when we sent last update
int _numNonMovingUpdates; // RELIABLE_SEND_HACK for "not so reliable" resends of packets for non-moving objects
// these are for the prediction of the remote server's simple extrapolation
@ -109,8 +105,9 @@ protected:
glm::vec3 _measuredAcceleration;
quint8 _accelerationNearlyGravityCount;
bool _shouldClaimSimulationOwnership;
quint32 _movingStepsWithoutSimulationOwner;
bool _candidateForOwnership;
uint32_t _loopsSinceOwnershipBid;
uint32_t _loopsWithoutOwner;
};
#endif // hifi_EntityMotionState_h

View file

@ -146,10 +146,6 @@ void ObjectMotionState::handleEasyChanges(uint32_t flags) {
_body->setMassProps(mass, inertia);
_body->updateInertiaTensor();
}
if (flags & EntityItem::DIRTY_PHYSICS_ACTIVATION) {
_body->activate();
}
}
void ObjectMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine) {

View file

@ -36,11 +36,11 @@ enum MotionStateType {
// and re-added to the physics engine and "easy" which just updates the body properties.
const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_MOTION_TYPE | EntityItem::DIRTY_SHAPE);
const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES |
EntityItem::DIRTY_MASS | EntityItem::DIRTY_COLLISION_GROUP |
EntityItem::DIRTY_MATERIAL | EntityItem::DIRTY_PHYSICS_ACTIVATION);
EntityItem::DIRTY_MASS | EntityItem::DIRTY_COLLISION_GROUP);
// These are the set of incoming flags that the PhysicsEngine needs to hear about:
const uint32_t DIRTY_PHYSICS_FLAGS = HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS;
const uint32_t DIRTY_PHYSICS_FLAGS = HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS |
EntityItem::DIRTY_MATERIAL | (uint32_t)EntityItem::DIRTY_PHYSICS_ACTIVATION;
// These are the outgoing flags that the PhysicsEngine can affect:
const uint32_t OUTGOING_DIRTY_PHYSICS_FLAGS = EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES;

View file

@ -188,7 +188,7 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToChange() {
return _tempVector;
}
void PhysicalEntitySimulation::handleOutgoingChanges(VectorOfMotionStates& motionStates) {
void PhysicalEntitySimulation::handleOutgoingChanges(VectorOfMotionStates& motionStates, const QUuid& sessionID) {
// walk the motionStates looking for those that correspond to entities
for (auto stateItr : motionStates) {
ObjectMotionState* state = &(*stateItr);
@ -196,24 +196,32 @@ void PhysicalEntitySimulation::handleOutgoingChanges(VectorOfMotionStates& motio
EntityMotionState* entityState = static_cast<EntityMotionState*>(state);
EntityItem* entity = entityState->getEntity();
if (entity) {
_outgoingChanges.insert(entityState);
if (entity->isKnownID() && entityState->isCandidateForOwnership(sessionID)) {
_outgoingChanges.insert(entityState);
}
_entitiesToSort.insert(entityState->getEntity());
}
}
}
// send outgoing packets
uint32_t numSubsteps = _physicsEngine->getNumSubsteps();
if (_lastStepSendPackets != numSubsteps) {
_lastStepSendPackets = numSubsteps;
if (sessionID.isNull()) {
// usually don't get here, but if so --> nothing to do
_outgoingChanges.clear();
return;
}
// send outgoing packets
QSet<EntityMotionState*>::iterator stateItr = _outgoingChanges.begin();
while (stateItr != _outgoingChanges.end()) {
EntityMotionState* state = *stateItr;
if (state->doesNotNeedToSendUpdate()) {
if (!state->isCandidateForOwnership(sessionID)) {
stateItr = _outgoingChanges.erase(stateItr);
} else if (state->shouldSendUpdate(numSubsteps)) {
state->sendUpdate(_entityPacketSender, numSubsteps);
} else if (state->shouldSendUpdate(numSubsteps, sessionID)) {
state->sendUpdate(_entityPacketSender, sessionID, numSubsteps);
++stateItr;
} else {
++stateItr;

View file

@ -48,7 +48,7 @@ public:
VectorOfMotionStates& getObjectsToAdd();
VectorOfMotionStates& getObjectsToChange();
void handleOutgoingChanges(VectorOfMotionStates& motionStates);
void handleOutgoingChanges(VectorOfMotionStates& motionStates, const QUuid& sessionID);
void handleCollisionEvents(CollisionEvents& collisionEvents);
private:

View file

@ -53,6 +53,7 @@ public:
void init();
void setSessionUUID(const QUuid& sessionID) { _sessionID = sessionID; }
const QUuid& getSessionID() const { return _sessionID; }
void addObject(ObjectMotionState* motionState);
void removeObject(ObjectMotionState* motionState);

View file

@ -15,36 +15,48 @@
#include "BulletUtil.h"
// find the average point on a convex shape
glm::vec3 findCenter(const QVector<glm::vec3>& points) {
glm::vec3 result = glm::vec3(0);
for (int i = 0; i < points.size(); i++) {
result += points[i];
btConvexHullShape* ShapeInfoUtil::createConvexHull(const QVector<glm::vec3>& points) {
assert(points.size() > 0);
btConvexHullShape* hull = new btConvexHullShape();
glm::vec3 center = points[0];
glm::vec3 maxCorner = center;
glm::vec3 minCorner = center;
for (int i = 1; i < points.size(); i++) {
center += points[i];
maxCorner = glm::max(maxCorner, points[i]);
minCorner = glm::min(minCorner, points[i]);
}
return result * (1.0f / points.size());
}
center /= (float)(points.size());
float margin = hull->getMargin();
// bullet puts "margins" around all the collision shapes. This can cause shapes will hulls
// to float a bit above what they are sitting on, etc. One option is to call:
//
// compound->setMargin(0.01);
//
// to reduce the size of the margin, but this has some consequences for the
// performance and stability of the simulation. Instead, we clench in all the points of
// the hull by the margin. These clenched points + bullets margin will but the actual
// collision hull fairly close to the visual edge of the object.
QVector<glm::vec3> shrinkByMargin(const QVector<glm::vec3>& points, const glm::vec3 center, float margin) {
QVector<glm::vec3> result(points.size());
for (int i = 0; i < points.size(); i++) {
glm::vec3 pVec = points[ i ] - center;
glm::vec3 pVecNorm = glm::normalize(pVec);
result[ i ] = center + pVec - (pVecNorm * margin);
// Bullet puts "margins" around all the collision shapes. This can cause objects that use ConvexHull shapes
// to have visible gaps between them and the surface they touch. One option is to reduce the size of the margin
// but this can reduce the performance and stability of the simulation (e.g. the GJK algorithm will fail to provide
// nearest contact points and narrow-phase collisions will fall into more expensive code paths). Alternatively
// one can shift the geometry of the shape to make the margin surface approximately close to the visible surface.
// This is the strategy we try, but if the object is too small then we start to reduce the margin down to some minimum.
const float MIN_MARGIN = 0.01f;
glm::vec3 diagonal = maxCorner - minCorner;
float minDimension = glm::min(diagonal[0], diagonal[1]);
minDimension = glm::min(minDimension, diagonal[2]);
margin = glm::min(glm::max(0.5f * minDimension, MIN_MARGIN), margin);
hull->setMargin(margin);
// add the points, correcting for margin
glm::vec3 relativeScale = (diagonal - glm::vec3(2.0f * margin)) / diagonal;
glm::vec3 correctedPoint;
for (int i = 0; i < points.size(); ++i) {
correctedPoint = (points[i] - center) * relativeScale + center;
hull->addPoint(btVector3(correctedPoint[0], correctedPoint[1], correctedPoint[2]), false);
}
return result;
hull->recalcLocalAabb();
return hull;
}
btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) {
btCollisionShape* shape = NULL;
switch(info.getType()) {
@ -68,30 +80,14 @@ btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) {
const QVector<QVector<glm::vec3>>& points = info.getPoints();
uint32_t numSubShapes = info.getNumSubShapes();
if (numSubShapes == 1) {
auto hull = new btConvexHullShape();
const QVector<QVector<glm::vec3>>& points = info.getPoints();
glm::vec3 center = findCenter(points[0]);
QVector<glm::vec3> shrunken = shrinkByMargin(points[0], center, hull->getMargin());
foreach (glm::vec3 point, shrunken) {
btVector3 btPoint(point[0], point[1], point[2]);
hull->addPoint(btPoint, false);
}
hull->recalcLocalAabb();
shape = hull;
shape = createConvexHull(info.getPoints()[0]);
} else {
assert(numSubShapes > 1);
auto compound = new btCompoundShape();
btTransform trans;
trans.setIdentity();
foreach (QVector<glm::vec3> hullPoints, points) {
auto hull = new btConvexHullShape();
glm::vec3 center = findCenter(points[0]);
QVector<glm::vec3> shrunken = shrinkByMargin(hullPoints, center, hull->getMargin());
foreach (glm::vec3 point, shrunken) {
btVector3 btPoint(point[0], point[1], point[2]);
hull->addPoint(btPoint, false);
}
hull->recalcLocalAabb();
btConvexHullShape* hull = createConvexHull(hullPoints);
compound->addChildShape (trans, hull);
}
shape = compound;

View file

@ -22,6 +22,8 @@
// TODO: rename this to ShapeFactory
namespace ShapeInfoUtil {
btConvexHullShape* createConvexHull(const QVector<glm::vec3>& points);
btCollisionShape* createShapeFromInfo(const ShapeInfo& info);
};

View file

@ -111,8 +111,8 @@ vec3 evalSkyboxGlobalColor(float shadowAttenuation, vec3 position, vec3 normal,
vec4 fragEyeVector = invViewMat * vec4(-position, 0.0);
vec3 fragEyeDir = normalize(fragEyeVector.xyz);
vec3 color = diffuse.rgb * evalSkyboxLight(fragNormal, 0.75).xyz * getLightAmbientIntensity(light);
vec3 color = diffuse.rgb * evalSphericalLight(ambientSphere, fragNormal).xyz * getLightAmbientIntensity(light);
vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss);
color += vec3(diffuse + shading.rgb) * shading.w * shadowAttenuation * getLightColor(light) * getLightIntensity(light);

View file

@ -291,7 +291,12 @@ void DeferredLightingEffect::render() {
auto globalLight = _allocatedLights[_globalLights.front()];
if (locations->ambientSphere >= 0) {
auto sh = globalLight->getAmbientSphere();
model::SphericalHarmonics sh;
if (useSkyboxCubemap) {
sh = _skybox->getIrradianceSH();
} else {
sh = globalLight->getAmbientSphere();
}
for (int i =0; i <model::SphericalHarmonics::NUM_COEFFICIENTS; i++) {
program->setUniformValue(locations->ambientSphere + i, *(((QVector4D*) &sh) + i));
}

View file

@ -142,22 +142,12 @@ gpu::FramebufferPointer GlowEffect::render() {
gpu::FramebufferPointer destFBO = textureCache->getSecondaryFramebuffer();
if (!_enabled || _isEmpty) {
// copy the primary to the screen
if (QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(destFBO));
glBindFramebuffer(GL_READ_FRAMEBUFFER, primaryFBO);
glBlitFramebuffer(0, 0, framebufferSize.width(), framebufferSize.height(),
0, 0, framebufferSize.width(), framebufferSize.height(),
GL_COLOR_BUFFER_BIT, GL_NEAREST);
} else {
glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(destFBO));
glViewport(0, 0, framebufferSize.width(), framebufferSize.height());
glEnable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
renderFullscreenQuad();
glDisable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(destFBO));
glBindFramebuffer(GL_READ_FRAMEBUFFER, primaryFBO);
glBlitFramebuffer(
0, 0, framebufferSize.width(), framebufferSize.height(),
0, 0, framebufferSize.width(), framebufferSize.height(),
GL_COLOR_BUFFER_BIT, GL_NEAREST);
} else {
// diffuse into the secondary/tertiary (alternating between frames)
auto oldDiffusedFBO =

View file

@ -1 +0,0 @@
#include "MatrixStack.h"

View file

@ -0,0 +1,43 @@
//
// OffscreenGlCanvas.cpp
// interface/src/renderer
//
// Created by Bradley Austin Davis on 2014/04/09.
// 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 "OffscreenGlContext.h"
OffscreenGlContext::OffscreenGlContext() {
}
void OffscreenGlContext::create(QOpenGLContext * sharedContext) {
QSurfaceFormat format;
format.setDepthBufferSize(16);
format.setStencilBufferSize(8);
format.setMajorVersion(4);
format.setMinorVersion(1);
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile);
_context.setFormat(format);
if (nullptr != sharedContext) {
_context.setShareContext(sharedContext);
}
_context.create();
_offscreenSurface.setFormat(_context.format());
_offscreenSurface.create();
}
bool OffscreenGlContext::makeCurrent() {
return _context.makeCurrent(&_offscreenSurface);
}
void OffscreenGlContext::doneCurrent() {
_context.doneCurrent();
}

View file

@ -0,0 +1,33 @@
//
// OffscreenGlCanvas.h
// interface/src/renderer
//
// Created by Bradley Austin Davis on 2014/04/09.
// 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
//
#pragma once
#ifndef hifi_OffscreenGlContext_h
#define hifi_OffscreenGlContext_h
#include <QOpenGLContext>
#include <QOffscreenSurface>
class OffscreenGlContext : public QObject {
public:
OffscreenGlContext();
void create(QOpenGLContext * sharedContext = nullptr);
bool makeCurrent();
void doneCurrent();
QOpenGLContext * getContext() {
return &_context;
}
protected:
QOpenGLContext _context;
QOffscreenSurface _offscreenSurface;
};
#endif // hifi_OffscreenGlCanvas_h

View file

@ -374,3 +374,6 @@ void OffscreenQmlSurface::setProxyWindow(QWindow* window) {
_renderControl->_renderWindow = window;
}
QQuickWindow* OffscreenQmlSurface::getWindow() {
return _quickWindow;
}

View file

@ -71,6 +71,7 @@ public:
void setBaseUrl(const QUrl& baseUrl);
QQuickItem* getRootItem();
QQuickWindow* getWindow();
virtual bool eventFilter(QObject* originalDestination, QEvent* event);

View file

@ -12,6 +12,8 @@
#ifndef hifi_RenderUtil_h
#define hifi_RenderUtil_h
#include <MatrixStack.h>
/// Renders a quad from (-1, -1, 0) to (1, 1, 0) with texture coordinates from (sMin, tMin) to (sMax, tMax).
void renderFullscreenQuad(float sMin = 0.0f, float sMax = 1.0f, float tMin = 0.0f, float tMax = 1.0f);

View file

@ -548,18 +548,23 @@ float TextRenderer::draw(float x, float y, const QString & str,
float scale = (_pointSize / DEFAULT_POINT_SIZE) * 0.25f;
glm::vec2 result;
MatrixStack::withGlMatrices([&] {
MatrixStack::withPushAll([&] {
MatrixStack & mv = MatrixStack::modelview();
// scale the modelview into font units
// FIXME migrate the constant scale factor into the geometry of the
// fonts so we don't have to flip the Y axis here and don't have to
// scale at all.
mv.translate(glm::vec2(x, y)).scale(glm::vec3(scale, -scale, scale));
// The font does all the OpenGL work
if (_font) {
result = _font->drawString(x, y, str, actualColor, _effectType, bounds / scale);
}
});
MatrixStack & pr = MatrixStack::projection();
gpu::GLBackend::fetchMatrix(GL_MODELVIEW_MATRIX, mv.top());
gpu::GLBackend::fetchMatrix(GL_PROJECTION_MATRIX, pr.top());
// scale the modelview into font units
// FIXME migrate the constant scale factor into the geometry of the
// fonts so we don't have to flip the Y axis here and don't have to
// scale at all.
mv.translate(glm::vec2(x, y)).scale(glm::vec3(scale, -scale, scale));
// The font does all the OpenGL work
if (_font) {
result = _font->drawString(x, y, str, actualColor, _effectType, bounds / scale);
}
});
return result.x;
}

View file

@ -514,7 +514,8 @@ void NetworkTexture::setImage(const QImage& image, bool translucent, const QColo
if ((_width > 0) && (_height > 0)) {
bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
// bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
bool isLinearRGB = !(_type == CUBE_TEXTURE); //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
@ -602,6 +603,45 @@ void NetworkTexture::setImage(const QImage& image, bool translucent, const QColo
faces.push_back(image.copy(QRect(3 * faceWidth, faceWidth, faceWidth, faceWidth)).mirrored(true, false));
// Front = -Z
faces.push_back(image.copy(QRect(1 * faceWidth, faceWidth, faceWidth, faceWidth)).mirrored(true, false));
} else if ((_height / 4) == (_width / 3)) {
int faceWidth = _height / 4;
// Here is the expected layout for the faces in an image with the 4/3 aspect ratio:
//
// <-------WIDTH-------->
// ^ +------+------+------+
// | | | | |
// | | | +Y | |
// | | | | |
// H +------+------+------+
// E | | | |
// I | -X | -Z | +X |
// G | | | |
// H +------+------+------+
// T | | | |
// | | | -Y | |
// | | | | |
// | +------+------+------+
// | | | | |
// | | | +Z! | | <+Z is upside down!
// | | | | |
// V +------+------+------+
//
// FaceWidth = width / 3 = height / 4
// Right = +X
faces.push_back(image.copy(QRect(2 * faceWidth, faceWidth, faceWidth, faceWidth)).mirrored(true, false));
// Left = -X
faces.push_back(image.copy(QRect(0 * faceWidth, faceWidth, faceWidth, faceWidth)).mirrored(true, false));
// Top = +Y
faces.push_back(image.copy(QRect(1 * faceWidth, 0, faceWidth, faceWidth)).mirrored(false, true));
// Bottom = -Y
faces.push_back(image.copy(QRect(1 * faceWidth, 2 * faceWidth, faceWidth, faceWidth)).mirrored(false, true));
// Back = +Z
faces.push_back(image.copy(QRect(1 * faceWidth, 3 * faceWidth, faceWidth, faceWidth)).mirrored(false, true));
// Front = -Z
faces.push_back(image.copy(QRect(1 * faceWidth, faceWidth, faceWidth, faceWidth)).mirrored(true, false));
}
if (faces.size() == gpu::Texture::NUM_FACES_PER_TYPE[gpu::Texture::TEX_CUBE]) {

View file

@ -24,7 +24,7 @@ MenuItemProperties::MenuItemProperties() :
afterItem(""),
isCheckable(false),
isChecked(false),
isSeparator(false)
isSeparator(false)
{
};

View file

@ -0,0 +1,22 @@
//
// BackgroundMode.h
// libraries/physcis/src
//
// 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_BackgroundMode_h
#define hifi_BackgroundMode_h
enum BackgroundMode {
BACKGROUND_MODE_INHERIT,
BACKGROUND_MODE_ATMOSPHERE,
BACKGROUND_MODE_SKYBOX,
};
#endif // hifi_BackgroundMode_h

View file

@ -0,0 +1,9 @@
//
// Created by Bradley Austin Davis
// 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
//
#include "MatrixStack.h"

View file

@ -1,21 +1,10 @@
/************************************************************************************
Authors : Bradley Austin Davis <bdavis@saintandreas.org>
Copyright : Copyright Brad Davis. All Rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
************************************************************************************/
//
// Created by Bradley Austin Davis
// 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
//
#pragma once
#include <glm/glm.hpp>
@ -26,10 +15,6 @@
#include <glm/gtc/matrix_transform.hpp>
#include <stack>
#include <gpu/GPUConfig.h>
class MatrixStack : public std::stack<glm::mat4> {
public:
@ -183,22 +168,5 @@ public:
stack2.withPush(f);
});
}
template <typename Function>
static void withGlMatrices(Function f) {
// Push the current stack, and then copy the values out of OpenGL
withPushAll([&] {
// Fetch the current matrices out of GL stack
// FIXME, eliminate the usage of deprecated GL
MatrixStack & mv = MatrixStack::modelview();
MatrixStack & pr = MatrixStack::projection();
glm::mat4 & mvm = mv.top();
glGetFloatv(GL_MODELVIEW_MATRIX, &(mvm[0][0]));
glm::mat4 & prm = pr.top();
glGetFloatv(GL_PROJECTION_MATRIX, &(prm[0][0]));
f();
});
}
};

View file

@ -103,7 +103,7 @@ void EntityTests::entityTreeTests(bool verbose) {
properties.setPosition(newPosition);
tree.updateEntity(entityID, properties, true);
tree.updateEntity(entityID, properties);
float targetRadius = oneMeter * 2.0f;
const EntityItem* foundEntityByRadius = tree.findClosestEntity(positionNearOrigin, targetRadius);
@ -143,7 +143,7 @@ void EntityTests::entityTreeTests(bool verbose) {
properties.setPosition(newPosition);
tree.updateEntity(entityID, properties, true);
tree.updateEntity(entityID, properties);
float targetRadius = oneMeter * 2.0f;
const EntityItem* foundEntityByRadius = tree.findClosestEntity(positionAtCenter, targetRadius);