mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:24:00 +02:00
Merge branch 'offscreen' into m_and_m
This commit is contained in:
commit
c0d562ed55
43 changed files with 1027 additions and 333 deletions
|
@ -28,6 +28,7 @@ Script.include([
|
|||
"libraries/gridTool.js",
|
||||
"libraries/entityList.js",
|
||||
"libraries/lightOverlayManager.js",
|
||||
"libraries/zoneOverlayManager.js",
|
||||
]);
|
||||
|
||||
var selectionDisplay = SelectionDisplay;
|
||||
|
@ -35,6 +36,7 @@ var selectionManager = SelectionManager;
|
|||
var entityPropertyDialogBox = EntityPropertyDialogBox;
|
||||
|
||||
var lightOverlayManager = new LightOverlayManager();
|
||||
var zoneOverlayManager = new ZoneOverlayManager();
|
||||
|
||||
var cameraManager = new CameraManager();
|
||||
|
||||
|
@ -47,6 +49,7 @@ var entityListTool = EntityListTool();
|
|||
selectionManager.addEventListener(function() {
|
||||
selectionDisplay.updateHandles();
|
||||
lightOverlayManager.updatePositions();
|
||||
zoneOverlayManager.updatePositions();
|
||||
});
|
||||
|
||||
var windowDimensions = Controller.getViewportDimensions();
|
||||
|
@ -77,11 +80,13 @@ var DEFAULT_LIGHT_DIMENSIONS = Vec3.multiply(20, DEFAULT_DIMENSIONS);
|
|||
var MENU_AUTO_FOCUS_ON_SELECT = "Auto Focus on Select";
|
||||
var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus";
|
||||
var MENU_SHOW_LIGHTS_IN_EDIT_MODE = "Show Lights in Edit Mode";
|
||||
var MENU_SHOW_ZONES_IN_EDIT_MODE = "Show Zones in Edit Mode";
|
||||
|
||||
var SETTING_INSPECT_TOOL_ENABLED = "inspectToolEnabled";
|
||||
var SETTING_AUTO_FOCUS_ON_SELECT = "autoFocusOnSelect";
|
||||
var SETTING_EASE_ON_FOCUS = "cameraEaseOnFocus";
|
||||
var SETTING_SHOW_LIGHTS_IN_EDIT_MODE = "showLightsInEditMode";
|
||||
var SETTING_SHOW_ZONES_IN_EDIT_MODE = "showZonesInEditMode";
|
||||
|
||||
var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to edit on this domain."
|
||||
var INSUFFICIENT_PERMISSIONS_IMPORT_ERROR_MSG = "You do not have the necessary permissions to place items on this domain."
|
||||
|
@ -135,6 +140,7 @@ var toolBar = (function () {
|
|||
newSphereButton,
|
||||
newLightButton,
|
||||
newTextButton,
|
||||
newZoneButton,
|
||||
browseMarketplaceButton;
|
||||
|
||||
function initialize() {
|
||||
|
@ -201,6 +207,14 @@ var toolBar = (function () {
|
|||
alpha: 0.9,
|
||||
visible: false
|
||||
});
|
||||
newZoneButton = toolBar.addTool({
|
||||
imageURL: toolIconUrl + "zonecube3.svg",
|
||||
subImage: { x: 0, y: Tool.IMAGE_WIDTH + 208, width: 256, height: 256 },
|
||||
width: toolWidth,
|
||||
height: toolHeight,
|
||||
alpha: 0.9,
|
||||
visible: false
|
||||
});
|
||||
|
||||
that.setActive(false);
|
||||
}
|
||||
|
@ -232,6 +246,7 @@ var toolBar = (function () {
|
|||
}
|
||||
toolBar.selectTool(activeButton, isActive);
|
||||
lightOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_IN_EDIT_MODE));
|
||||
zoneOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE));
|
||||
};
|
||||
|
||||
// Sets visibility of tool buttons, excluding the power button
|
||||
|
@ -241,6 +256,7 @@ var toolBar = (function () {
|
|||
toolBar.showTool(newSphereButton, doShow);
|
||||
toolBar.showTool(newLightButton, doShow);
|
||||
toolBar.showTool(newTextButton, doShow);
|
||||
toolBar.showTool(newZoneButton, doShow);
|
||||
};
|
||||
|
||||
var RESIZE_INTERVAL = 50;
|
||||
|
@ -412,6 +428,21 @@ var toolBar = (function () {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (newZoneButton === toolBar.clicked(clickedOverlay)) {
|
||||
var position = getPositionToCreateEntity();
|
||||
|
||||
if (position.x > 0 && position.y > 0 && position.z > 0) {
|
||||
placingEntityID = Entities.addEntity({
|
||||
type: "Zone",
|
||||
position: grid.snapToSurface(grid.snapToGrid(position, false, DEFAULT_DIMENSIONS), DEFAULT_DIMENSIONS),
|
||||
dimensions: { x: 10, y: 10, z: 10 },
|
||||
});
|
||||
} else {
|
||||
print("Can't create box: Text would be out of bounds.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
@ -486,12 +517,22 @@ function rayPlaneIntersection(pickRay, point, normal) {
|
|||
}
|
||||
|
||||
function findClickedEntity(event) {
|
||||
var pickZones = event.isControl;
|
||||
|
||||
if (pickZones) {
|
||||
Entities.setZonesArePickable(true);
|
||||
}
|
||||
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
|
||||
var entityResult = Entities.findRayIntersection(pickRay, true); // want precision picking
|
||||
var lightResult = lightOverlayManager.findRayIntersection(pickRay);
|
||||
lightResult.accurate = true;
|
||||
|
||||
if (pickZones) {
|
||||
Entities.setZonesArePickable(false);
|
||||
}
|
||||
|
||||
var result;
|
||||
|
||||
if (!entityResult.intersects && !lightResult.intersects) {
|
||||
|
@ -776,6 +817,8 @@ function setupModelMenus() {
|
|||
isCheckable: true, isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" });
|
||||
Menu.addMenuItem({ menuName: "View", menuItemName: MENU_SHOW_LIGHTS_IN_EDIT_MODE, afterItem: MENU_EASE_ON_FOCUS,
|
||||
isCheckable: true, isChecked: Settings.getValue(SETTING_SHOW_LIGHTS_IN_EDIT_MODE) == "true" });
|
||||
Menu.addMenuItem({ menuName: "View", menuItemName: MENU_SHOW_ZONES_IN_EDIT_MODE, afterItem: MENU_SHOW_LIGHTS_IN_EDIT_MODE,
|
||||
isCheckable: true, isChecked: Settings.getValue(SETTING_SHOW_ZONES_IN_EDIT_MODE) == "true" });
|
||||
|
||||
Entities.setLightsArePickable(false);
|
||||
}
|
||||
|
@ -804,12 +847,14 @@ function cleanupModelMenus() {
|
|||
Menu.removeMenuItem("View", MENU_AUTO_FOCUS_ON_SELECT);
|
||||
Menu.removeMenuItem("View", MENU_EASE_ON_FOCUS);
|
||||
Menu.removeMenuItem("View", MENU_SHOW_LIGHTS_IN_EDIT_MODE);
|
||||
Menu.removeMenuItem("View", MENU_SHOW_ZONES_IN_EDIT_MODE);
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(function() {
|
||||
Settings.setValue(SETTING_AUTO_FOCUS_ON_SELECT, Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT));
|
||||
Settings.setValue(SETTING_EASE_ON_FOCUS, Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
|
||||
Settings.setValue(SETTING_SHOW_LIGHTS_IN_EDIT_MODE, Menu.isOptionChecked(MENU_SHOW_LIGHTS_IN_EDIT_MODE));
|
||||
Settings.setValue(SETTING_SHOW_ZONES_IN_EDIT_MODE, Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE));
|
||||
|
||||
progressDialog.cleanup();
|
||||
toolBar.cleanup();
|
||||
|
@ -942,6 +987,8 @@ function handeMenuEvent(menuItem) {
|
|||
selectAllEtitiesInCurrentSelectionBox(true);
|
||||
} else if (menuItem == MENU_SHOW_LIGHTS_IN_EDIT_MODE) {
|
||||
lightOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_IN_EDIT_MODE));
|
||||
} else if (menuItem == MENU_SHOW_ZONES_IN_EDIT_MODE) {
|
||||
zoneOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE));
|
||||
}
|
||||
tooltip.show(false);
|
||||
}
|
||||
|
|
23
examples/example/entities/fullDomainZoneEntityExample.js
Normal file
23
examples/example/entities/fullDomainZoneEntityExample.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// fullDomainZoneEntityExample.js
|
||||
// examples
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 4/16/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that demonstrates creating a Zone which is as large as the entire domain
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Entities.addEntity({
|
||||
type: "Zone",
|
||||
position: { x: -10000, y: -10000, z: -10000 },
|
||||
dimensions: { x: 30000, y: 30000, z: 30000 },
|
||||
keyLightColor: { red: 255, green: 255, blue: 0 },
|
||||
keyLightDirection: { x: 0, y: -1.0, z: 0 },
|
||||
keyLightIntensity: 1.0,
|
||||
keyLightAmbientIntensity: 0.5
|
||||
});
|
||||
|
|
@ -22,7 +22,8 @@ var zoneEntityA = Entities.addEntity({
|
|||
dimensions: { x: 10, y: 10, z: 10 },
|
||||
keyLightColor: { red: 255, green: 0, blue: 0 },
|
||||
stageSunModelEnabled: false,
|
||||
keyLightDirection: { x: 0, y: -1.0, z: 0 }
|
||||
keyLightDirection: { x: 0, y: -1.0, z: 0 },
|
||||
shapeType: "sphere"
|
||||
});
|
||||
|
||||
print("zoneEntityA:" + zoneEntityA);
|
||||
|
@ -51,7 +52,9 @@ var zoneEntityC = Entities.addEntity({
|
|||
keyLightColor: { red: 0, green: 0, blue: 255 },
|
||||
keyLightIntensity: 0.75,
|
||||
keyLightDirection: { x: 0, y: 0, z: -1 },
|
||||
stageSunModelEnabled: false
|
||||
stageSunModelEnabled: false,
|
||||
shapeType: "compound",
|
||||
compoundShapeURL: "http://headache.hungry.com/~seth/hifi/cube.fbx"
|
||||
});
|
||||
|
||||
print("zoneEntityC:" + zoneEntityC);
|
||||
|
|
|
@ -39,126 +39,130 @@ hitSounds.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "Collisions-ballhitsandc
|
|||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||
var screenSize = Controller.getViewportDimensions();
|
||||
var reticle = Overlays.addOverlay("image", {
|
||||
x: screenSize.x / 2 - 16,
|
||||
y: screenSize.y / 2 - 16,
|
||||
width: 32,
|
||||
height: 32,
|
||||
imageURL: HIFI_PUBLIC_BUCKET + "images/billiardsReticle.png",
|
||||
color: { red: 255, green: 255, blue: 255},
|
||||
alpha: 1
|
||||
});
|
||||
x: screenSize.x / 2 - 16,
|
||||
y: screenSize.y / 2 - 16,
|
||||
width: 32,
|
||||
height: 32,
|
||||
imageURL: HIFI_PUBLIC_BUCKET + "images/billiardsReticle.png",
|
||||
color: { red: 255, green: 255, blue: 255},
|
||||
alpha: 1
|
||||
});
|
||||
|
||||
function makeTable(pos) {
|
||||
// Top
|
||||
tableParts.push(Entities.addEntity(
|
||||
// Top
|
||||
tableParts.push(Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: pos,
|
||||
dimensions: { x: LENGTH * SCALE, y: HEIGHT, z: WIDTH * SCALE },
|
||||
color: { red: 0, green: 255, blue: 0 } }));
|
||||
// Long Bumpers
|
||||
tableParts.push(Entities.addEntity(
|
||||
position: pos,
|
||||
dimensions: { x: LENGTH * SCALE, y: HEIGHT, z: WIDTH * SCALE },
|
||||
color: { red: 0, green: 255, blue: 0 } }));
|
||||
// Long Bumpers
|
||||
tableParts.push(Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: { x: pos.x - LENGTH / 2.0,
|
||||
y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0),
|
||||
z: pos.z - (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE },
|
||||
dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE },
|
||||
color: { red: 237, green: 201, blue: 175 } }));
|
||||
tableParts.push(Entities.addEntity(
|
||||
position: { x: pos.x - LENGTH / 2.0,
|
||||
y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0),
|
||||
z: pos.z - (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE },
|
||||
dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE },
|
||||
color: { red: 237, green: 201, blue: 175 } }));
|
||||
tableParts.push(Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: { x: pos.x + LENGTH / 2.0,
|
||||
y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0),
|
||||
z: pos.z - (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE },
|
||||
dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE },
|
||||
color: { red: 237, green: 201, blue: 175 } }));
|
||||
position: { x: pos.x + LENGTH / 2.0,
|
||||
y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0),
|
||||
z: pos.z - (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE },
|
||||
dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE },
|
||||
color: { red: 237, green: 201, blue: 175 } }));
|
||||
|
||||
tableParts.push(Entities.addEntity(
|
||||
tableParts.push(Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: { x: pos.x - LENGTH / 2.0,
|
||||
y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0),
|
||||
z: pos.z + (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE },
|
||||
dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE },
|
||||
color: { red: 237, green: 201, blue: 175 } }));
|
||||
tableParts.push(Entities.addEntity(
|
||||
position: { x: pos.x - LENGTH / 2.0,
|
||||
y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0),
|
||||
z: pos.z + (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE },
|
||||
dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE },
|
||||
color: { red: 237, green: 201, blue: 175 } }));
|
||||
tableParts.push(Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: { x: pos.x + LENGTH / 2.0,
|
||||
y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0),
|
||||
z: pos.z + (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE },
|
||||
dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE },
|
||||
color: { red: 237, green: 201, blue: 175 } }));
|
||||
// End bumpers
|
||||
tableParts.push(Entities.addEntity(
|
||||
position: { x: pos.x + LENGTH / 2.0,
|
||||
y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0),
|
||||
z: pos.z + (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE },
|
||||
dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE },
|
||||
color: { red: 237, green: 201, blue: 175 } }));
|
||||
// End bumpers
|
||||
tableParts.push(Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: { x: pos.x + (LENGTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE,
|
||||
y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0),
|
||||
z: pos.z },
|
||||
dimensions: { z: (WIDTH - 2.0 * HOLE_SIZE) * SCALE, y: BUMPER_HEIGHT, x: BUMPER_WIDTH * SCALE },
|
||||
color: { red: 237, green: 201, blue: 175 } }));
|
||||
position: { x: pos.x + (LENGTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE,
|
||||
y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0),
|
||||
z: pos.z },
|
||||
dimensions: { z: (WIDTH - 2.0 * HOLE_SIZE) * SCALE, y: BUMPER_HEIGHT, x: BUMPER_WIDTH * SCALE },
|
||||
color: { red: 237, green: 201, blue: 175 } }));
|
||||
|
||||
tableParts.push(Entities.addEntity(
|
||||
tableParts.push(Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: { x: pos.x - (LENGTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE,
|
||||
y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0),
|
||||
z: pos.z },
|
||||
dimensions: { z: (WIDTH - 2.0 * HOLE_SIZE) * SCALE, y: BUMPER_HEIGHT, x: BUMPER_WIDTH * SCALE },
|
||||
color: { red: 237, green: 201, blue: 175 } }));
|
||||
position: { x: pos.x - (LENGTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE,
|
||||
y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0),
|
||||
z: pos.z },
|
||||
dimensions: { z: (WIDTH - 2.0 * HOLE_SIZE) * SCALE, y: BUMPER_HEIGHT, x: BUMPER_WIDTH * SCALE },
|
||||
color: { red: 237, green: 201, blue: 175 } }));
|
||||
|
||||
}
|
||||
|
||||
function makeBalls(pos) {
|
||||
// Object balls
|
||||
// Object balls
|
||||
var whichBall = [ 1, 14, 15, 4, 8, 7, 12, 9, 3, 13, 10, 5, 6, 11, 2 ];
|
||||
var ballNumber = 0;
|
||||
var ballPosition = { x: pos.x + (LENGTH / 4.0) * SCALE, y: pos.y + HEIGHT / 2.0 + DROP_HEIGHT, z: pos.z };
|
||||
for (var row = 1; row <= 5; row++) {
|
||||
ballPosition.z = pos.z - ((row - 1.0) / 2.0 * (BALL_SIZE + BALL_GAP) * SCALE);
|
||||
for (var spot = 0; spot < row; spot++) {
|
||||
balls.push(Entities.addEntity(
|
||||
var ballPosition = { x: pos.x + (LENGTH / 4.0) * SCALE, y: pos.y + HEIGHT / 2.0 + DROP_HEIGHT, z: pos.z };
|
||||
for (var row = 1; row <= 5; row++) {
|
||||
ballPosition.z = pos.z - ((row - 1.0) / 2.0 * (BALL_SIZE + BALL_GAP) * SCALE);
|
||||
for (var spot = 0; spot < row; spot++) {
|
||||
balls.push(Entities.addEntity(
|
||||
{ type: "Model",
|
||||
modelURL: "https://s3.amazonaws.com/hifi-public/models/props/Pool/ball_" + whichBall[ballNumber].toString() + ".fbx",
|
||||
position: ballPosition,
|
||||
dimensions: { x: BALL_SIZE * SCALE, y: BALL_SIZE * SCALE, z: BALL_SIZE * SCALE },
|
||||
rotation: Quat.fromPitchYawRollDegrees((Math.random() - 0.5) * 20, (Math.random() - 0.5) * 20, (Math.random() - 0.5) * 20),
|
||||
color: { red: 255, green: 255, blue: 255 },
|
||||
gravity: { x: 0, y: GRAVITY, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
damping: 0.50,
|
||||
shapeType: "sphere",
|
||||
collisionsWillMove: true }));
|
||||
ballPosition.z += (BALL_SIZE + BALL_GAP) * SCALE;
|
||||
modelURL: "https://s3.amazonaws.com/hifi-public/models/props/Pool/ball_" +
|
||||
whichBall[ballNumber].toString() + ".fbx",
|
||||
position: ballPosition,
|
||||
dimensions: { x: BALL_SIZE * SCALE, y: BALL_SIZE * SCALE, z: BALL_SIZE * SCALE },
|
||||
rotation: Quat.fromPitchYawRollDegrees((Math.random() - 0.5) * 20,
|
||||
(Math.random() - 0.5) * 20,
|
||||
(Math.random() - 0.5) * 20),
|
||||
color: { red: 255, green: 255, blue: 255 },
|
||||
gravity: { x: 0, y: GRAVITY, z: 0 },
|
||||
velocity: {x: 0, y: -0.2, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
damping: 0.50,
|
||||
shapeType: "sphere",
|
||||
collisionsWillMove: true }));
|
||||
ballPosition.z += (BALL_SIZE + BALL_GAP) * SCALE;
|
||||
ballNumber++;
|
||||
}
|
||||
ballPosition.x += (BALL_GAP + Math.sqrt(3.0) / 2.0 * BALL_SIZE) * SCALE;
|
||||
}
|
||||
ballPosition.x += (BALL_GAP + Math.sqrt(3.0) / 2.0 * BALL_SIZE) * SCALE;
|
||||
}
|
||||
|
||||
// Cue Ball
|
||||
cuePosition = { x: pos.x - (LENGTH / 4.0) * SCALE, y: pos.y + HEIGHT / 2.0 + DROP_HEIGHT, z: pos.z };
|
||||
cueBall = Entities.addEntity(
|
||||
{ type: "Model",
|
||||
modelURL: "https://s3.amazonaws.com/hifi-public/models/props/Pool/cue_ball.fbx",
|
||||
position: cuePosition,
|
||||
dimensions: { x: BALL_SIZE * SCALE, y: BALL_SIZE * SCALE, z: BALL_SIZE * SCALE },
|
||||
color: { red: 255, green: 255, blue: 255 },
|
||||
gravity: { x: 0, y: GRAVITY, z: 0 },
|
||||
angularVelocity: { x: 0, y: 0, z: 0 },
|
||||
velocity: {x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
damping: 0.50,
|
||||
shapeType: "sphere",
|
||||
collisionsWillMove: true });
|
||||
|
||||
{ type: "Model",
|
||||
modelURL: "https://s3.amazonaws.com/hifi-public/models/props/Pool/cue_ball.fbx",
|
||||
position: cuePosition,
|
||||
dimensions: { x: BALL_SIZE * SCALE, y: BALL_SIZE * SCALE, z: BALL_SIZE * SCALE },
|
||||
color: { red: 255, green: 255, blue: 255 },
|
||||
gravity: { x: 0, y: GRAVITY, z: 0 },
|
||||
angularVelocity: { x: 0, y: 0, z: 0 },
|
||||
velocity: {x: 0, y: -0.2, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
damping: 0.50,
|
||||
shapeType: "sphere",
|
||||
collisionsWillMove: true });
|
||||
|
||||
}
|
||||
|
||||
function isObjectBall(id) {
|
||||
for (var i; i < balls.length; i++) {
|
||||
if (balls[i].id == id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
for (var i; i < balls.length; i++) {
|
||||
if (balls[i].id == id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function shootCue(velocity) {
|
||||
var DISTANCE_FROM_CAMERA = BALL_SIZE * 5.0 * SCALE;
|
||||
var DISTANCE_FROM_CAMERA = BALL_SIZE * 5.0 * SCALE;
|
||||
var camera = Camera.getPosition();
|
||||
var forwardVector = Quat.getFront(Camera.getOrientation());
|
||||
var cuePosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_FROM_CAMERA));
|
||||
|
@ -180,14 +184,14 @@ function shootCue(velocity) {
|
|||
density: 8000,
|
||||
ignoreCollisions: false,
|
||||
collisionsWillMove: true
|
||||
});
|
||||
});
|
||||
print("Shot, velocity = " + velocity);
|
||||
}
|
||||
|
||||
function keyReleaseEvent(event) {
|
||||
if ((startStroke > 0) && event.text == "SPACE") {
|
||||
var endTime = new Date().getTime();
|
||||
var delta = endTime - startStroke;
|
||||
if ((startStroke > 0) && event.text == "SPACE") {
|
||||
var endTime = new Date().getTime();
|
||||
var delta = endTime - startStroke;
|
||||
shootCue(delta / 100.0);
|
||||
startStroke = 0;
|
||||
}
|
||||
|
@ -201,49 +205,49 @@ function keyPressEvent(event) {
|
|||
}
|
||||
|
||||
function cleanup() {
|
||||
for (var i = 0; i < tableParts.length; i++) {
|
||||
if (!tableParts[i].isKnownID) {
|
||||
tableParts[i] = Entities.identifyEntity(tableParts[i]);
|
||||
}
|
||||
Entities.deleteEntity(tableParts[i]);
|
||||
for (var i = 0; i < tableParts.length; i++) {
|
||||
if (!tableParts[i].isKnownID) {
|
||||
tableParts[i] = Entities.identifyEntity(tableParts[i]);
|
||||
}
|
||||
for (var i = 0; i < balls.length; i++) {
|
||||
if (!balls[i].isKnownID) {
|
||||
balls[i] = Entities.identifyEntity(balls[i]);
|
||||
}
|
||||
Entities.deleteEntity(balls[i]);
|
||||
Entities.deleteEntity(tableParts[i]);
|
||||
}
|
||||
for (var i = 0; i < balls.length; i++) {
|
||||
if (!balls[i].isKnownID) {
|
||||
balls[i] = Entities.identifyEntity(balls[i]);
|
||||
}
|
||||
Overlays.deleteOverlay(reticle);
|
||||
Entities.deleteEntity(cueBall);
|
||||
Entities.deleteEntity(balls[i]);
|
||||
}
|
||||
Overlays.deleteOverlay(reticle);
|
||||
Entities.deleteEntity(cueBall);
|
||||
}
|
||||
|
||||
function update(deltaTime) {
|
||||
if (!cueBall.isKnownID) {
|
||||
cueBall = Entities.identifyEntity(cueBall);
|
||||
} else {
|
||||
// Check if cue ball has fallen off table, re-drop if so
|
||||
var cueProperties = Entities.getEntityProperties(cueBall);
|
||||
if (cueProperties.position.y < tableCenter.y) {
|
||||
// Replace the cueball
|
||||
Entities.editEntity(cueBall, { position: cuePosition } );
|
||||
if (!cueBall.isKnownID) {
|
||||
cueBall = Entities.identifyEntity(cueBall);
|
||||
} else {
|
||||
// Check if cue ball has fallen off table, re-drop if so
|
||||
var cueProperties = Entities.getEntityProperties(cueBall);
|
||||
if (cueProperties.position.y < tableCenter.y) {
|
||||
// Replace the cueball
|
||||
Entities.editEntity(cueBall, { position: cuePosition } );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function entityCollisionWithEntity(entity1, entity2, collision) {
|
||||
/*
|
||||
NOT WORKING YET
|
||||
if ((entity1.id == cueBall.id) || (entity2.id == cueBall.id)) {
|
||||
print("Cue ball collision!");
|
||||
//audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||
//Audio.playSound(hitSounds[0], { position: Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())) });
|
||||
}
|
||||
/*
|
||||
NOT WORKING YET
|
||||
if ((entity1.id == cueBall.id) || (entity2.id == cueBall.id)) {
|
||||
print("Cue ball collision!");
|
||||
//audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||
//Audio.playSound(hitSounds[0], { position: Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())) });
|
||||
}
|
||||
|
||||
else if (isObjectBall(entity1.id) || isObjectBall(entity2.id)) {
|
||||
print("Object ball collision");
|
||||
} */
|
||||
else if (isObjectBall(entity1.id) || isObjectBall(entity2.id)) {
|
||||
print("Object ball collision");
|
||||
} */
|
||||
}
|
||||
|
||||
tableCenter = Vec3.sum(MyAvatar.position, Vec3.multiply(4.0, Quat.getFront(Camera.getOrientation())));
|
||||
|
|
|
@ -162,7 +162,7 @@
|
|||
|
||||
var elModelSections = document.querySelectorAll(".model-section");
|
||||
var elModelURL = document.getElementById("property-model-url");
|
||||
var elCollisionModelURL = document.getElementById("property-collision-model-url");
|
||||
var elCompoundShapeURL = document.getElementById("property-compound-shape-url");
|
||||
var elModelAnimationURL = document.getElementById("property-model-animation-url");
|
||||
var elModelAnimationPlaying = document.getElementById("property-model-animation-playing");
|
||||
var elModelAnimationFPS = document.getElementById("property-model-animation-fps");
|
||||
|
@ -182,6 +182,23 @@
|
|||
var elTextBackgroundColorGreen = document.getElementById("property-text-background-color-green");
|
||||
var elTextBackgroundColorBlue = document.getElementById("property-text-background-color-blue");
|
||||
|
||||
var elZoneSections = document.querySelectorAll(".zone-section");
|
||||
var elZoneStageSunModelEnabled = document.getElementById("property-zone-stage-sun-model-enabled");
|
||||
var elZoneKeyLightColorRed = document.getElementById("property-zone-key-light-color-red");
|
||||
var elZoneKeyLightColorGreen = document.getElementById("property-zone-key-light-color-green");
|
||||
var elZoneKeyLightColorBlue = document.getElementById("property-zone-key-light-color-blue");
|
||||
var elZoneKeyLightIntensity = document.getElementById("property-zone-key-intensity");
|
||||
var elZoneKeyLightAmbientIntensity = document.getElementById("property-zone-key-ambient-intensity");
|
||||
var elZoneKeyLightDirectionX = document.getElementById("property-zone-key-light-direction-x");
|
||||
var elZoneKeyLightDirectionY = document.getElementById("property-zone-key-light-direction-y");
|
||||
var elZoneKeyLightDirectionZ = document.getElementById("property-zone-key-light-direction-z");
|
||||
|
||||
var elZoneStageLatitude = document.getElementById("property-zone-stage-latitude");
|
||||
var elZoneStageLongitude = document.getElementById("property-zone-stage-longitude");
|
||||
var elZoneStageAltitude = document.getElementById("property-zone-stage-altitude");
|
||||
var elZoneStageDay = document.getElementById("property-zone-stage-day");
|
||||
var elZoneStageHour = document.getElementById("property-zone-stage-hour");
|
||||
|
||||
if (window.EventBridge !== undefined) {
|
||||
EventBridge.scriptEventReceived.connect(function(data) {
|
||||
data = JSON.parse(data);
|
||||
|
@ -306,7 +323,7 @@
|
|||
}
|
||||
|
||||
elModelURL.value = properties.modelURL;
|
||||
elCollisionModelURL.value = properties.collisionModelURL;
|
||||
elCompoundShapeURL.value = properties.compoundShapeURL;
|
||||
elModelAnimationURL.value = properties.animationURL;
|
||||
elModelAnimationPlaying.checked = properties.animationIsPlaying;
|
||||
elModelAnimationFPS.value = properties.animationFPS;
|
||||
|
@ -356,6 +373,32 @@
|
|||
elLightCutoff.value = properties.cutoff;
|
||||
}
|
||||
|
||||
if (properties.type != "Zone") {
|
||||
for (var i = 0; i < elZoneSections.length; i++) {
|
||||
elZoneSections[i].style.display = 'none';
|
||||
}
|
||||
} else {
|
||||
for (var i = 0; i < elZoneSections.length; i++) {
|
||||
elZoneSections[i].style.display = 'block';
|
||||
}
|
||||
|
||||
elZoneStageSunModelEnabled.checked = properties.stageSunModelEnabled;
|
||||
elZoneKeyLightColorRed.value = properties.keyLightColor.red;
|
||||
elZoneKeyLightColorGreen.value = properties.keyLightColor.green;
|
||||
elZoneKeyLightColorBlue.value = properties.keyLightColor.blue;
|
||||
elZoneKeyLightIntensity.value = properties.keyLightIntensity.toFixed(2);
|
||||
elZoneKeyLightAmbientIntensity.value = properties.keyLightAmbientIntensity.toFixed(2);
|
||||
elZoneKeyLightDirectionX.value = properties.keyLightDirection.x.toFixed(2);
|
||||
elZoneKeyLightDirectionY.value = properties.keyLightDirection.y.toFixed(2);
|
||||
elZoneKeyLightDirectionZ.value = properties.keyLightDirection.z.toFixed(2);
|
||||
|
||||
elZoneStageLatitude.value = properties.stageLatitude.toFixed(2);
|
||||
elZoneStageLongitude.value = properties.stageLongitude.toFixed(2);
|
||||
elZoneStageAltitude.value = properties.stageAltitude.toFixed(2);
|
||||
elZoneStageDay.value = properties.stageDay;
|
||||
elZoneStageHour.value = properties.stageHour;
|
||||
}
|
||||
|
||||
if (selected) {
|
||||
activeElement.focus();
|
||||
activeElement.select();
|
||||
|
@ -444,7 +487,7 @@
|
|||
elLightCutoff.addEventListener('change', createEmitNumberPropertyUpdateFunction('cutoff'));
|
||||
|
||||
elModelURL.addEventListener('change', createEmitTextPropertyUpdateFunction('modelURL'));
|
||||
elCollisionModelURL.addEventListener('change', createEmitTextPropertyUpdateFunction('collisionModelURL'));
|
||||
elCompoundShapeURL.addEventListener('change', createEmitTextPropertyUpdateFunction('compoundShapeURL'));
|
||||
elModelAnimationURL.addEventListener('change', createEmitTextPropertyUpdateFunction('animationURL'));
|
||||
elModelAnimationPlaying.addEventListener('change', createEmitCheckedPropertyUpdateFunction('animationIsPlaying'));
|
||||
elModelAnimationFPS.addEventListener('change', createEmitNumberPropertyUpdateFunction('animationFPS'));
|
||||
|
@ -468,6 +511,26 @@
|
|||
elTextBackgroundColorGreen.addEventListener('change', textBackgroundColorChangeFunction);
|
||||
elTextBackgroundColorBlue.addEventListener('change', textBackgroundColorChangeFunction);
|
||||
|
||||
elZoneStageSunModelEnabled.addEventListener('change', createEmitCheckedPropertyUpdateFunction('stageSunModelEnabled'));
|
||||
var zoneKeyLightColorChangeFunction = createEmitColorPropertyUpdateFunction(
|
||||
'keyLightColor', elZoneKeyLightColorRed, elZoneKeyLightColorGreen, elZoneKeyLightColorBlue);
|
||||
elZoneKeyLightColorRed.addEventListener('change', zoneKeyLightColorChangeFunction);
|
||||
elZoneKeyLightColorGreen.addEventListener('change', zoneKeyLightColorChangeFunction);
|
||||
elZoneKeyLightColorBlue.addEventListener('change', zoneKeyLightColorChangeFunction);
|
||||
elZoneKeyLightIntensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('keyLightIntensity'));
|
||||
elZoneKeyLightAmbientIntensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('keyLightAmbientIntensity'));
|
||||
var zoneKeyLightDirectionChangeFunction = createEmitVec3PropertyUpdateFunction(
|
||||
'keyLightDirection', elZoneKeyLightDirectionX, elZoneKeyLightDirectionY, elZoneKeyLightDirectionZ);
|
||||
elZoneKeyLightDirectionX.addEventListener('change', zoneKeyLightDirectionChangeFunction);
|
||||
elZoneKeyLightDirectionY.addEventListener('change', zoneKeyLightDirectionChangeFunction);
|
||||
elZoneKeyLightDirectionZ.addEventListener('change', zoneKeyLightDirectionChangeFunction);
|
||||
|
||||
elZoneStageLatitude.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageLatitude'));
|
||||
elZoneStageLongitude.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageLongitude'));
|
||||
elZoneStageAltitude.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageAltitude'));
|
||||
elZoneStageDay.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageDay'));
|
||||
elZoneStageHour.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageHour'));
|
||||
|
||||
elMoveSelectionToGrid.addEventListener("click", function() {
|
||||
EventBridge.emitWebEvent(JSON.stringify({
|
||||
type: "action",
|
||||
|
@ -712,9 +775,9 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="model-section property">
|
||||
<div class="label">Collision Model URL</div>
|
||||
<div class="label">Compound Shape URL</div>
|
||||
<div class="value">
|
||||
<input type="text" id="property-collision-model-url" class="url"></input>
|
||||
<input type="text" id="property-compound-shape-url" class="url"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="model-section property">
|
||||
|
@ -833,6 +896,73 @@
|
|||
<input class="coord" type='number' id="property-light-cutoff"></input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="zone-section property">
|
||||
<span class="label">Stage Sun Model Enabled</span>
|
||||
<span class="value">
|
||||
<input type='checkbox' id="property-zone-stage-sun-model-enabled">
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="zone-section property">
|
||||
<div class="label">Key Light Color</div>
|
||||
<div class="value">
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-zone-key-light-color-red" min="0" max="255" step="1"></input></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-zone-key-light-color-green" min="0" max="255" step="1"></input></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-zone-key-light-color-blue" min="0" max="255" step="1"></input></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="zone-section property">
|
||||
<div class="label">Key Light Intensity</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-key-intensity" min="0" max="10" step="0.1"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="zone-section property">
|
||||
<div class="label">Key Light Ambient Intensity</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-key-ambient-intensity" min="0" max="10" step="0.1"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="zone-section property">
|
||||
<div class="label">Key Light Direction</div>
|
||||
<div class="value">
|
||||
<div class="input-area">Pitch <input class="coord" type='number' id="property-zone-key-light-direction-x"></input></div>
|
||||
<div class="input-area">Yaw <input class="coord" type='number' id="property-zone-key-light-direction-y"></input></div>
|
||||
<div class="input-area">Roll <input class="coord" type='number' id="property-zone-key-light-direction-z"></input></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="zone-section property">
|
||||
<div class="label">Stage Latitude</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-stage-latitude" min="-90" max="90" step="1"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="zone-section property">
|
||||
<div class="label">Stage Longitude</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-stage-longitude" min="-180" max="180" step="1"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="zone-section property">
|
||||
<div class="label">Stage Altitude</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-stage-altitude" step="1"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="zone-section property">
|
||||
<div class="label">Stage Day</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-stage-day" min="0" max="365" step="1"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="zone-section property">
|
||||
<div class="label">Stage Hour</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-stage-hour" min="0" max="24" step="0.5"></input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -53,7 +53,7 @@ function Tooltip() {
|
|||
text += "ID: " + properties.id + "\n"
|
||||
if (properties.type == "Model") {
|
||||
text += "Model URL: " + properties.modelURL + "\n"
|
||||
text += "Collision Model URL: " + properties.collisionModelURL + "\n"
|
||||
text += "Compound Shape URL: " + properties.compoundShapeURL + "\n"
|
||||
text += "Animation URL: " + properties.animationURL + "\n"
|
||||
text += "Animation is playing: " + properties.animationIsPlaying + "\n"
|
||||
if (properties.sittingPoints && properties.sittingPoints.length > 0) {
|
||||
|
|
|
@ -52,7 +52,7 @@ EntityPropertyDialogBox = (function () {
|
|||
if (properties.type == "Model") {
|
||||
array.push({ label: "Model URL:", value: properties.modelURL });
|
||||
index++;
|
||||
array.push({ label: "Collision Model URL:", value: properties.collisionModelURL });
|
||||
array.push({ label: "Compound Shape URL:", value: properties.compoundShapeURL });
|
||||
index++;
|
||||
array.push({ label: "Animation URL:", value: properties.animationURL });
|
||||
index++;
|
||||
|
@ -284,7 +284,7 @@ EntityPropertyDialogBox = (function () {
|
|||
properties.locked = array[index++].value;
|
||||
if (properties.type == "Model") {
|
||||
properties.modelURL = array[index++].value;
|
||||
properties.collisionModelURL = array[index++].value;
|
||||
properties.compoundShapeURL = array[index++].value;
|
||||
properties.animationURL = array[index++].value;
|
||||
|
||||
var newAnimationIsPlaying = array[index++].value;
|
||||
|
|
|
@ -122,7 +122,7 @@ LightOverlayManager = function() {
|
|||
Entities.clearingEntities.connect(clearEntities);
|
||||
|
||||
// Add existing entities
|
||||
var ids = Entities.findEntities(MyAvatar.position, 100);
|
||||
var ids = Entities.findEntities(MyAvatar.position, 64000);
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
addEntity(ids[i]);
|
||||
}
|
||||
|
|
145
examples/libraries/zoneOverlayManager.js
Normal file
145
examples/libraries/zoneOverlayManager.js
Normal file
|
@ -0,0 +1,145 @@
|
|||
ZoneOverlayManager = function(isEntityFunc, entityAddedFunc, entityRemovedFunc, entityMovedFunc) {
|
||||
var self = this;
|
||||
|
||||
var visible = false;
|
||||
|
||||
// List of all created overlays
|
||||
var allOverlays = [];
|
||||
|
||||
// List of overlays not currently being used
|
||||
var unusedOverlays = [];
|
||||
|
||||
// Map from EntityItemID.id to overlay id
|
||||
var entityOverlays = {};
|
||||
|
||||
// Map from EntityItemID.id to EntityItemID object
|
||||
var entityIDs = {};
|
||||
|
||||
this.updatePositions = function(ids) {
|
||||
for (var id in entityIDs) {
|
||||
var entityID = entityIDs[id];
|
||||
var properties = Entities.getEntityProperties(entityID);
|
||||
Overlays.editOverlay(entityOverlays[entityID.id].solid, {
|
||||
position: properties.position,
|
||||
rotation: properties.rotation,
|
||||
dimensions: properties.dimensions,
|
||||
});
|
||||
Overlays.editOverlay(entityOverlays[entityID.id].outline, {
|
||||
position: properties.position,
|
||||
rotation: properties.rotation,
|
||||
dimensions: properties.dimensions,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.setVisible = function(isVisible) {
|
||||
if (visible != isVisible) {
|
||||
visible = isVisible;
|
||||
for (var id in entityOverlays) {
|
||||
Overlays.editOverlay(entityOverlays[id].solid, { visible: visible });
|
||||
Overlays.editOverlay(entityOverlays[id].outline, { visible: visible });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Allocate or get an unused overlay
|
||||
function getOverlay() {
|
||||
if (unusedOverlays.length == 0) {
|
||||
var overlay = Overlays.addOverlay("cube", {
|
||||
});
|
||||
allOverlays.push(overlay);
|
||||
} else {
|
||||
var overlay = unusedOverlays.pop();
|
||||
};
|
||||
return overlay;
|
||||
}
|
||||
|
||||
function releaseOverlay(overlay) {
|
||||
unusedOverlays.push(overlay);
|
||||
Overlays.editOverlay(overlay, { visible: false });
|
||||
}
|
||||
|
||||
function addEntity(entityID) {
|
||||
var properties = Entities.getEntityProperties(entityID);
|
||||
if (properties.type == "Zone" && !(entityID.id in entityOverlays)) {
|
||||
var overlaySolid = getOverlay();
|
||||
var overlayOutline = getOverlay();
|
||||
|
||||
entityOverlays[entityID.id] = {
|
||||
solid: overlaySolid,
|
||||
outline: overlayOutline,
|
||||
}
|
||||
entityIDs[entityID.id] = entityID;
|
||||
|
||||
var color = {
|
||||
red: Math.round(Math.random() * 255),
|
||||
green: Math.round(Math.random() * 255),
|
||||
blue: Math.round(Math.random() * 255)
|
||||
};
|
||||
Overlays.editOverlay(overlaySolid, {
|
||||
position: properties.position,
|
||||
rotation: properties.rotation,
|
||||
dimensions: properties.dimensions,
|
||||
visible: visible,
|
||||
solid: true,
|
||||
alpha: 0.1,
|
||||
color: color,
|
||||
ignoreRayIntersection: true,
|
||||
});
|
||||
Overlays.editOverlay(overlayOutline, {
|
||||
position: properties.position,
|
||||
rotation: properties.rotation,
|
||||
dimensions: properties.dimensions,
|
||||
visible: visible,
|
||||
solid: false,
|
||||
dashed: false,
|
||||
lineWidth: 2.0,
|
||||
alpha: 1.0,
|
||||
color: color,
|
||||
ignoreRayIntersection: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function deleteEntity(entityID) {
|
||||
if (entityID.id in entityOverlays) {
|
||||
releaseOverlay(entityOverlays[entityID.id].outline);
|
||||
releaseOverlay(entityOverlays[entityID.id].solid);
|
||||
delete entityOverlays[entityID.id];
|
||||
}
|
||||
}
|
||||
|
||||
function changeEntityID(oldEntityID, newEntityID) {
|
||||
entityOverlays[newEntityID.id] = entityOverlays[oldEntityID.id];
|
||||
entityIDs[newEntityID.id] = newEntityID;
|
||||
|
||||
delete entityOverlays[oldEntityID.id];
|
||||
delete entityIDs[oldEntityID.id];
|
||||
}
|
||||
|
||||
function clearEntities() {
|
||||
for (var id in entityOverlays) {
|
||||
releaseOverlay(entityOverlays[id].outline);
|
||||
releaseOverlay(entityOverlays[id].solid);
|
||||
}
|
||||
entityOverlays = {};
|
||||
entityIDs = {};
|
||||
}
|
||||
|
||||
Entities.addingEntity.connect(addEntity);
|
||||
Entities.changingEntityID.connect(changeEntityID);
|
||||
Entities.deletingEntity.connect(deleteEntity);
|
||||
Entities.clearingEntities.connect(clearEntities);
|
||||
|
||||
// Add existing entities
|
||||
var ids = Entities.findEntities(MyAvatar.position, 64000);
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
addEntity(ids[i]);
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(function() {
|
||||
for (var i = 0; i < allOverlays.length; i++) {
|
||||
Overlays.deleteOverlay(allOverlays[i]);
|
||||
}
|
||||
});
|
||||
};
|
|
@ -77,7 +77,7 @@ void Cube3DOverlay::render(RenderArgs* args) {
|
|||
if (_drawOnHUD) {
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha));
|
||||
} else {
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidCube(1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha));
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha));
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
|
@ -89,7 +89,7 @@ void Cube3DOverlay::render(RenderArgs* args) {
|
|||
if (_drawOnHUD) {
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, cubeColor);
|
||||
} else {
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidCube(1.0f, cubeColor);
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, cubeColor);
|
||||
}
|
||||
glPopMatrix();
|
||||
} else {
|
||||
|
|
|
@ -34,8 +34,8 @@
|
|||
#include "RenderableParticleEffectEntityItem.h"
|
||||
#include "RenderableSphereEntityItem.h"
|
||||
#include "RenderableTextEntityItem.h"
|
||||
#include "RenderableZoneEntityItem.h"
|
||||
#include "EntitiesRendererLogging.h"
|
||||
#include "ZoneEntityItem.h"
|
||||
|
||||
EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterface* viewState,
|
||||
AbstractScriptingServicesInterface* scriptingServices) :
|
||||
|
@ -57,6 +57,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
|
|||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Light, RenderableLightEntityItem::factory)
|
||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Text, RenderableTextEntityItem::factory)
|
||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(ParticleEffect, RenderableParticleEffectEntityItem::factory)
|
||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Zone, RenderableZoneEntityItem::factory)
|
||||
|
||||
_currentHoverOverEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID
|
||||
_currentClickingOnEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID
|
||||
|
@ -496,7 +497,7 @@ const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(const Entit
|
|||
|
||||
if (entityItem->getType() == EntityTypes::Model) {
|
||||
const RenderableModelEntityItem* constModelEntityItem = dynamic_cast<const RenderableModelEntityItem*>(entityItem);
|
||||
if (constModelEntityItem->hasCollisionModel()) {
|
||||
if (constModelEntityItem->hasCompoundShapeURL()) {
|
||||
RenderableModelEntityItem* modelEntityItem = const_cast<RenderableModelEntityItem*>(constModelEntityItem);
|
||||
Model* model = modelEntityItem->getModel(this);
|
||||
if (model) {
|
||||
|
|
|
@ -224,10 +224,10 @@ Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) {
|
|||
// if we have a previously allocated model, but its URL doesn't match
|
||||
// then we need to let our renderer update our model for us.
|
||||
if (_model && QUrl(getModelURL()) != _model->getURL()) {
|
||||
result = _model = _myRenderer->updateModel(_model, getModelURL(), getCollisionModelURL());
|
||||
result = _model = _myRenderer->updateModel(_model, getModelURL(), getCompoundShapeURL());
|
||||
_needsInitialSimulation = true;
|
||||
} else if (!_model) { // if we don't yet have a model, then we want our renderer to allocate one
|
||||
result = _model = _myRenderer->allocateModel(getModelURL(), getCollisionModelURL());
|
||||
result = _model = _myRenderer->allocateModel(getModelURL(), getCompoundShapeURL());
|
||||
_needsInitialSimulation = true;
|
||||
} else { // we already have the model we want...
|
||||
result = _model;
|
||||
|
@ -267,8 +267,8 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori
|
|||
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, extraInfo, precisionPicking);
|
||||
}
|
||||
|
||||
void RenderableModelEntityItem::setCollisionModelURL(const QString& url) {
|
||||
ModelEntityItem::setCollisionModelURL(url);
|
||||
void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) {
|
||||
ModelEntityItem::setCompoundShapeURL(url);
|
||||
if (_model) {
|
||||
_model->setCollisionModelURL(QUrl(url));
|
||||
}
|
||||
|
@ -410,8 +410,17 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
|||
}
|
||||
|
||||
glm::vec3 collisionModelDimensions = box.getDimensions();
|
||||
info.setParams(type, collisionModelDimensions, _collisionModelURL);
|
||||
info.setParams(type, collisionModelDimensions, _compoundShapeURL);
|
||||
info.setConvexHulls(_points);
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderableModelEntityItem::contains(const glm::vec3& point) const {
|
||||
if (EntityItem::contains(point) && _model && _model->getCollisionGeometry()) {
|
||||
const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry();
|
||||
const FBXGeometry& collisionGeometry = collisionNetworkGeometry->getFBXGeometry();
|
||||
return collisionGeometry.convexHullContains(worldToEntity(point));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -52,10 +52,12 @@ public:
|
|||
|
||||
bool needsToCallUpdate() const;
|
||||
|
||||
virtual void setCollisionModelURL(const QString& url);
|
||||
virtual void setCompoundShapeURL(const QString& url);
|
||||
|
||||
bool isReadyToComputeShape();
|
||||
void computeShapeInfo(ShapeInfo& info);
|
||||
|
||||
virtual bool contains(const glm::vec3& point) const;
|
||||
|
||||
private:
|
||||
void remapTextures();
|
||||
|
|
57
libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
Normal file
57
libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
//
|
||||
// RenderableZoneEntityItem.cpp
|
||||
//
|
||||
//
|
||||
// Created by Clement on 4/22/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "RenderableZoneEntityItem.h"
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <GeometryCache.h>
|
||||
|
||||
EntityItem* RenderableZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
return new RenderableZoneEntityItem(entityID, properties);
|
||||
}
|
||||
|
||||
bool RenderableZoneEntityItem::setProperties(const EntityItemProperties& properties) {
|
||||
QString oldShapeURL = getCompoundShapeURL();
|
||||
bool somethingChanged = ZoneEntityItem::setProperties(properties);
|
||||
if (somethingChanged && oldShapeURL != getCompoundShapeURL()) {
|
||||
_compoundShapeModel = DependencyManager::get<GeometryCache>()->getGeometry(getCompoundShapeURL(), QUrl(), true);
|
||||
}
|
||||
return somethingChanged;
|
||||
}
|
||||
|
||||
int RenderableZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||
ReadBitstreamToTreeParams& args,
|
||||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData) {
|
||||
QString oldShapeURL = getCompoundShapeURL();
|
||||
int bytesRead = ZoneEntityItem::readEntitySubclassDataFromBuffer(data, bytesLeftToRead,
|
||||
args, propertyFlags, overwriteLocalData);
|
||||
if (oldShapeURL != getCompoundShapeURL()) {
|
||||
_compoundShapeModel = DependencyManager::get<GeometryCache>()->getGeometry(getCompoundShapeURL(), QUrl(), true);
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
bool RenderableZoneEntityItem::contains(const glm::vec3& point) const {
|
||||
if (getShapeType() != SHAPE_TYPE_COMPOUND) {
|
||||
return EntityItem::contains(point);
|
||||
}
|
||||
if (!_compoundShapeModel && hasCompoundShapeURL()) {
|
||||
const_cast<RenderableZoneEntityItem*>(this)->_compoundShapeModel = DependencyManager::get<GeometryCache>()->getGeometry(getCompoundShapeURL(), QUrl(), true);
|
||||
}
|
||||
|
||||
if (EntityItem::contains(point) && _compoundShapeModel && _compoundShapeModel->isLoaded()) {
|
||||
const FBXGeometry& geometry = _compoundShapeModel->getFBXGeometry();
|
||||
glm::vec3 meshDimensions = geometry.getUnscaledMeshExtents().maximum - geometry.getUnscaledMeshExtents().minimum;
|
||||
return geometry.convexHullContains(worldToEntity(point) * meshDimensions);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
39
libraries/entities-renderer/src/RenderableZoneEntityItem.h
Normal file
39
libraries/entities-renderer/src/RenderableZoneEntityItem.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// RenderableZoneEntityItem.h
|
||||
//
|
||||
//
|
||||
// Created by Clement on 4/22/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_RenderableZoneEntityItem_h
|
||||
#define hifi_RenderableZoneEntityItem_h
|
||||
|
||||
#include <ZoneEntityItem.h>
|
||||
|
||||
class NetworkGeometry;
|
||||
|
||||
class RenderableZoneEntityItem : public ZoneEntityItem {
|
||||
public:
|
||||
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
||||
RenderableZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
||||
ZoneEntityItem(entityItemID, properties)
|
||||
{ }
|
||||
|
||||
virtual bool setProperties(const EntityItemProperties& properties);
|
||||
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||
ReadBitstreamToTreeParams& args,
|
||||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData);
|
||||
|
||||
virtual bool contains(const glm::vec3& point) const;
|
||||
|
||||
private:
|
||||
|
||||
QSharedPointer<NetworkGeometry> _compoundShapeModel;
|
||||
};
|
||||
|
||||
#endif // hifi_RenderableZoneEntityItem_h
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <glm/gtx/transform.hpp>
|
||||
|
||||
#include <ByteCountCoding.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <Octree.h>
|
||||
|
@ -25,75 +27,53 @@
|
|||
|
||||
bool EntityItem::_sendPhysicsUpdates = true;
|
||||
|
||||
void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) {
|
||||
_id = entityItemID.id;
|
||||
_creatorTokenID = entityItemID.creatorTokenID;
|
||||
|
||||
// init values with defaults before calling setProperties
|
||||
EntityItem::EntityItem(const EntityItemID& entityItemID) :
|
||||
_type(EntityTypes::Unknown),
|
||||
_id(entityItemID.id),
|
||||
_creatorTokenID(entityItemID.creatorTokenID),
|
||||
_newlyCreated(false),
|
||||
_lastSimulated(0),
|
||||
_lastUpdated(0),
|
||||
_lastEdited(0),
|
||||
_lastEditedFromRemote(0),
|
||||
_lastEditedFromRemoteInRemoteTime(0),
|
||||
_created(UNKNOWN_CREATED_TIME),
|
||||
_changedOnServer(0),
|
||||
_position(ENTITY_ITEM_ZERO_VEC3),
|
||||
_dimensions(ENTITY_ITEM_DEFAULT_DIMENSIONS),
|
||||
_rotation(ENTITY_ITEM_DEFAULT_ROTATION),
|
||||
_glowLevel(ENTITY_ITEM_DEFAULT_GLOW_LEVEL),
|
||||
_localRenderAlpha(ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA),
|
||||
_density(ENTITY_ITEM_DEFAULT_DENSITY),
|
||||
_volumeMultiplier(1.0f),
|
||||
_velocity(ENTITY_ITEM_DEFAULT_VELOCITY),
|
||||
_gravity(ENTITY_ITEM_DEFAULT_GRAVITY),
|
||||
_acceleration(ENTITY_ITEM_DEFAULT_ACCELERATION),
|
||||
_damping(ENTITY_ITEM_DEFAULT_DAMPING),
|
||||
_lifetime(ENTITY_ITEM_DEFAULT_LIFETIME),
|
||||
_script(ENTITY_ITEM_DEFAULT_SCRIPT),
|
||||
_registrationPoint(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT),
|
||||
_angularVelocity(ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY),
|
||||
_angularDamping(ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING),
|
||||
_visible(ENTITY_ITEM_DEFAULT_VISIBLE),
|
||||
_ignoreForCollisions(ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS),
|
||||
_collisionsWillMove(ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE),
|
||||
_locked(ENTITY_ITEM_DEFAULT_LOCKED),
|
||||
_userData(ENTITY_ITEM_DEFAULT_USER_DATA),
|
||||
_simulatorID(ENTITY_ITEM_DEFAULT_SIMULATOR_ID),
|
||||
_simulatorIDChangedTime(0),
|
||||
_marketplaceID(ENTITY_ITEM_DEFAULT_MARKETPLACE_ID),
|
||||
_physicsInfo(NULL),
|
||||
_dirtyFlags(0),
|
||||
_element(NULL)
|
||||
{
|
||||
quint64 now = usecTimestampNow();
|
||||
_lastSimulated = now;
|
||||
_lastUpdated = now;
|
||||
_lastEdited = 0;
|
||||
_lastEditedFromRemote = 0;
|
||||
_lastEditedFromRemoteInRemoteTime = 0;
|
||||
_created = UNKNOWN_CREATED_TIME;
|
||||
_changedOnServer = 0;
|
||||
|
||||
_position = ENTITY_ITEM_ZERO_VEC3;
|
||||
_dimensions = ENTITY_ITEM_DEFAULT_DIMENSIONS;
|
||||
_density = ENTITY_ITEM_DEFAULT_DENSITY;
|
||||
_rotation = ENTITY_ITEM_DEFAULT_ROTATION;
|
||||
_glowLevel = ENTITY_ITEM_DEFAULT_GLOW_LEVEL;
|
||||
_localRenderAlpha = ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA;
|
||||
_velocity = ENTITY_ITEM_DEFAULT_VELOCITY;
|
||||
_gravity = ENTITY_ITEM_DEFAULT_GRAVITY;
|
||||
_acceleration = ENTITY_ITEM_DEFAULT_ACCELERATION;
|
||||
_damping = ENTITY_ITEM_DEFAULT_DAMPING;
|
||||
_lifetime = ENTITY_ITEM_DEFAULT_LIFETIME;
|
||||
_script = ENTITY_ITEM_DEFAULT_SCRIPT;
|
||||
_registrationPoint = ENTITY_ITEM_DEFAULT_REGISTRATION_POINT;
|
||||
_angularVelocity = ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY;
|
||||
_angularDamping = ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING;
|
||||
_visible = ENTITY_ITEM_DEFAULT_VISIBLE;
|
||||
_ignoreForCollisions = ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS;
|
||||
_collisionsWillMove = ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE;
|
||||
_locked = ENTITY_ITEM_DEFAULT_LOCKED;
|
||||
_userData = ENTITY_ITEM_DEFAULT_USER_DATA;
|
||||
_simulatorID = ENTITY_ITEM_DEFAULT_SIMULATOR_ID;
|
||||
_marketplaceID = ENTITY_ITEM_DEFAULT_MARKETPLACE_ID;
|
||||
}
|
||||
|
||||
EntityItem::EntityItem(const EntityItemID& entityItemID) {
|
||||
_type = EntityTypes::Unknown;
|
||||
quint64 now = usecTimestampNow();
|
||||
_lastSimulated = now;
|
||||
_lastUpdated = now;
|
||||
_lastEdited = 0;
|
||||
_lastEditedFromRemote = 0;
|
||||
_lastEditedFromRemoteInRemoteTime = 0;
|
||||
_created = UNKNOWN_CREATED_TIME;
|
||||
_dirtyFlags = 0;
|
||||
_changedOnServer = 0;
|
||||
_element = NULL;
|
||||
_simulatorIDChangedTime = 0;
|
||||
_shouldClaimSimulationOwnership = false;
|
||||
initFromEntityItemID(entityItemID);
|
||||
}
|
||||
|
||||
EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) {
|
||||
_type = EntityTypes::Unknown;
|
||||
quint64 now = usecTimestampNow();
|
||||
_lastSimulated = now;
|
||||
_lastUpdated = now;
|
||||
_lastEdited = 0;
|
||||
_lastEditedFromRemote = 0;
|
||||
_lastEditedFromRemoteInRemoteTime = 0;
|
||||
_created = UNKNOWN_CREATED_TIME;
|
||||
_dirtyFlags = 0;
|
||||
_changedOnServer = 0;
|
||||
_element = NULL;
|
||||
_simulatorIDChangedTime = 0;
|
||||
initFromEntityItemID(entityItemID);
|
||||
EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : EntityItem(entityItemID)
|
||||
{
|
||||
setProperties(properties);
|
||||
}
|
||||
|
||||
|
@ -621,7 +601,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
const QUuid& myNodeID = nodeList->getSessionUUID();
|
||||
if (_simulatorID == myNodeID) {
|
||||
if (_simulatorID == myNodeID && !_simulatorID.isNull()) {
|
||||
// the packet that produced this bitstream originally came from physics simulations performed by
|
||||
// this node, so our version has to be newer than what the packet contained.
|
||||
_position = savePosition;
|
||||
|
@ -843,7 +823,27 @@ bool EntityItem::isMoving() const {
|
|||
return hasVelocity() || hasAngularVelocity();
|
||||
}
|
||||
|
||||
bool EntityItem::lifetimeHasExpired() const {
|
||||
glm::mat4 EntityItem::getEntityToWorldMatrix() const {
|
||||
glm::mat4 translation = glm::translate(getPosition());
|
||||
glm::mat4 rotation = glm::mat4_cast(getRotation());
|
||||
glm::mat4 scale = glm::scale(getDimensions());
|
||||
glm::mat4 registration = glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint());
|
||||
return translation * rotation * scale * registration;
|
||||
}
|
||||
|
||||
glm::mat4 EntityItem::getWorldToEntityMatrix() const {
|
||||
return glm::inverse(getEntityToWorldMatrix());
|
||||
}
|
||||
|
||||
glm::vec3 EntityItem::entityToWorld(const glm::vec3 point) const {
|
||||
return glm::vec3(getEntityToWorldMatrix() * glm::vec4(point, 1.0f));
|
||||
}
|
||||
|
||||
glm::vec3 EntityItem::worldToEntity(const glm::vec3 point) const {
|
||||
return glm::vec3(getWorldToEntityMatrix() * glm::vec4(point, 1.0f));
|
||||
}
|
||||
|
||||
bool EntityItem::lifetimeHasExpired() const {
|
||||
return isMortal() && (getAge() > getLifetime());
|
||||
}
|
||||
|
||||
|
@ -1033,12 +1033,6 @@ AABox EntityItem::getAABox() const {
|
|||
return AABox(rotatedExtentsRelativeToRegistrationPoint);
|
||||
}
|
||||
|
||||
AABox EntityItem::getAABoxInDomainUnits() const {
|
||||
AABox box = getAABox();
|
||||
box.scale(1.0f / (float)TREE_SCALE);
|
||||
return box;
|
||||
}
|
||||
|
||||
// NOTE: This should only be used in cases of old bitstreams which only contain radius data
|
||||
// 0,0,0 --> maxDimension,maxDimension,maxDimension
|
||||
// ... has a corner to corner distance of glm::length(maxDimension,maxDimension,maxDimension)
|
||||
|
@ -1066,6 +1060,16 @@ float EntityItem::getRadius() const {
|
|||
return 0.5f * glm::length(_dimensions);
|
||||
}
|
||||
|
||||
bool EntityItem::contains(const glm::vec3& point) const {
|
||||
if (getShapeType() == SHAPE_TYPE_COMPOUND) {
|
||||
return getAABox().contains(point);
|
||||
} else {
|
||||
ShapeInfo info;
|
||||
info.setParams(getShapeType(), glm::vec3(0.5f));
|
||||
return info.contains(worldToEntity(point));
|
||||
}
|
||||
}
|
||||
|
||||
void EntityItem::computeShapeInfo(ShapeInfo& info) {
|
||||
info.setParams(getShapeType(), 0.5f * getDimensions());
|
||||
}
|
||||
|
|
|
@ -145,25 +145,16 @@ public:
|
|||
|
||||
// attributes applicable to all entity types
|
||||
EntityTypes::EntityType getType() const { return _type; }
|
||||
glm::vec3 getPositionInDomainUnits() const { return _position / (float)TREE_SCALE; } /// get position in domain scale units (0.0 - 1.0)
|
||||
const glm::vec3& getPosition() const { return _position; } /// get position in meters
|
||||
|
||||
/// set position in domain scale units (0.0 - 1.0)
|
||||
void setPositionInDomainUnits(const glm::vec3& value)
|
||||
{ setPosition(glm::clamp(value, 0.0f, 1.0f) * (float)TREE_SCALE); }
|
||||
void setPosition(const glm::vec3& value) {
|
||||
_position = value;
|
||||
}
|
||||
|
||||
glm::vec3 getCenterInDomainUnits() const { return getCenter() / (float) TREE_SCALE; }
|
||||
glm::vec3 getCenter() const;
|
||||
|
||||
glm::vec3 getDimensionsInDomainUnits() const { return _dimensions / (float)TREE_SCALE; } /// get dimensions in domain scale units (0.0 - 1.0)
|
||||
const glm::vec3& getDimensions() const { return _dimensions; } /// get dimensions in meters
|
||||
|
||||
/// set dimensions in domain scale units (0.0 - 1.0)
|
||||
virtual void setDimensionsInDomainUnits(const glm::vec3& value) { _dimensions = glm::abs(value) * (float)TREE_SCALE; }
|
||||
|
||||
/// set dimensions in meter units (0.0 - TREE_SCALE)
|
||||
virtual void setDimensions(const glm::vec3& value) { _dimensions = glm::abs(value); }
|
||||
|
||||
|
@ -182,15 +173,11 @@ public:
|
|||
|
||||
float getDensity() const { return _density; }
|
||||
|
||||
glm::vec3 getVelocityInDomainUnits() const { return _velocity / (float)TREE_SCALE; } /// velocity in domain scale units (0.0-1.0) per second
|
||||
const glm::vec3 getVelocity() const { return _velocity; } /// get velocity in meters
|
||||
void setVelocityInDomainUnits(const glm::vec3& value) { _velocity = value * (float)TREE_SCALE; } /// velocity in domain scale units (0.0-1.0) per second
|
||||
void setVelocity(const glm::vec3& value) { _velocity = value; } /// velocity in meters
|
||||
bool hasVelocity() const { return _velocity != ENTITY_ITEM_ZERO_VEC3; }
|
||||
|
||||
glm::vec3 getGravityInDomainUnits() const { return _gravity / (float)TREE_SCALE; } /// gravity in domain scale units (0.0-1.0) per second squared
|
||||
const glm::vec3& getGravity() const { return _gravity; } /// get gravity in meters
|
||||
void setGravityInDomainUnits(const glm::vec3& value) { _gravity = value * (float)TREE_SCALE; } /// gravity in domain scale units (0.0-1.0) per second squared
|
||||
void setGravity(const glm::vec3& value) { _gravity = value; } /// gravity in meters
|
||||
bool hasGravity() const { return _gravity != ENTITY_ITEM_ZERO_VEC3; }
|
||||
|
||||
|
@ -220,7 +207,6 @@ public:
|
|||
AACube getMaximumAACube() const;
|
||||
AACube getMinimumAACube() const;
|
||||
AABox getAABox() const; /// axis aligned bounding box in world-frame (meters)
|
||||
AABox getAABoxInDomainUnits() const; /// axis aligned bounding box in domain scale units (0.0 - 1.0)
|
||||
|
||||
const QString& getScript() const { return _script; }
|
||||
void setScript(const QString& value) { _script = value; }
|
||||
|
@ -258,8 +244,6 @@ public:
|
|||
QUuid getSimulatorID() const { return _simulatorID; }
|
||||
void setSimulatorID(const QUuid& value);
|
||||
quint64 getSimulatorIDChangedTime() const { return _simulatorIDChangedTime; }
|
||||
void setShouldClaimSimulationOwnership(bool value) { _shouldClaimSimulationOwnership = value; }
|
||||
bool getShouldClaimSimulationOwnership() { return _shouldClaimSimulationOwnership; }
|
||||
|
||||
const QString& getMarketplaceID() const { return _marketplaceID; }
|
||||
void setMarketplaceID(const QString& value) { _marketplaceID = value; }
|
||||
|
@ -267,8 +251,7 @@ public:
|
|||
// TODO: get rid of users of getRadius()...
|
||||
float getRadius() const;
|
||||
|
||||
virtual bool contains(const glm::vec3& point) const { return getAABox().contains(point); }
|
||||
virtual bool containsInDomainUnits(const glm::vec3& point) const { return getAABoxInDomainUnits().contains(point); }
|
||||
virtual bool contains(const glm::vec3& point) const;
|
||||
|
||||
virtual bool isReadyToComputeShape() { return true; }
|
||||
virtual void computeShapeInfo(ShapeInfo& info);
|
||||
|
@ -312,12 +295,14 @@ public:
|
|||
static void setSendPhysicsUpdates(bool value) { _sendPhysicsUpdates = value; }
|
||||
static bool getSendPhysicsUpdates() { return _sendPhysicsUpdates; }
|
||||
|
||||
glm::mat4 getEntityToWorldMatrix() const;
|
||||
glm::mat4 getWorldToEntityMatrix() const;
|
||||
glm::vec3 worldToEntity(const glm::vec3 point) const;
|
||||
glm::vec3 entityToWorld(const glm::vec3 point) const;
|
||||
|
||||
protected:
|
||||
|
||||
static bool _sendPhysicsUpdates;
|
||||
|
||||
virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init
|
||||
|
||||
EntityTypes::EntityType _type;
|
||||
QUuid _id;
|
||||
uint32_t _creatorTokenID;
|
||||
|
@ -357,7 +342,6 @@ protected:
|
|||
QString _userData;
|
||||
QUuid _simulatorID; // id of Node which is currently responsible for simulating this Entity
|
||||
quint64 _simulatorIDChangedTime; // when was _simulatorID last updated?
|
||||
bool _shouldClaimSimulationOwnership;
|
||||
QString _marketplaceID;
|
||||
|
||||
// NOTE: Damping is applied like this: v *= pow(1 - damping, dt)
|
||||
|
|
|
@ -44,7 +44,7 @@ EntityItemProperties::EntityItemProperties() :
|
|||
CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT),
|
||||
CONSTRUCT_PROPERTY(color, ),
|
||||
CONSTRUCT_PROPERTY(modelURL, ""),
|
||||
CONSTRUCT_PROPERTY(collisionModelURL, ""),
|
||||
CONSTRUCT_PROPERTY(compoundShapeURL, ""),
|
||||
CONSTRUCT_PROPERTY(animationURL, ""),
|
||||
CONSTRUCT_PROPERTY(animationFPS, ModelEntityItem::DEFAULT_ANIMATION_FPS),
|
||||
CONSTRUCT_PROPERTY(animationFrameIndex, ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX),
|
||||
|
@ -175,7 +175,7 @@ void EntityItemProperties::debugDump() const {
|
|||
qCDebug(entities) << " _position=" << _position.x << "," << _position.y << "," << _position.z;
|
||||
qCDebug(entities) << " _dimensions=" << getDimensions();
|
||||
qCDebug(entities) << " _modelURL=" << _modelURL;
|
||||
qCDebug(entities) << " _collisionModelURL=" << _collisionModelURL;
|
||||
qCDebug(entities) << " _compoundShapeURL=" << _compoundShapeURL;
|
||||
qCDebug(entities) << " changed properties...";
|
||||
EntityPropertyFlags props = getChangedProperties();
|
||||
props.debugDumpBits();
|
||||
|
@ -245,7 +245,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_SCRIPT, script);
|
||||
CHECK_PROPERTY_CHANGE(PROP_COLOR, color);
|
||||
CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_COLLISION_MODEL_URL, collisionModelURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_URL, animationURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_PLAYING, animationIsPlaying);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FRAME_INDEX, animationFrameIndex);
|
||||
|
@ -322,7 +322,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE(visible);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR(color);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(collisionModelURL);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(compoundShapeURL);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(animationIsPlaying);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(animationFPS);
|
||||
|
@ -417,7 +417,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
|
|||
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(collisionModelURL, setCollisionModelURL);
|
||||
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);
|
||||
|
@ -618,7 +618,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
|
|||
|
||||
if (properties.getType() == EntityTypes::Model) {
|
||||
APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, properties.getModelURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLLISION_MODEL_URL, appendValue, properties.getCollisionModelURL());
|
||||
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());
|
||||
|
@ -657,6 +657,9 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
|
|||
APPEND_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, appendValue, properties.getStageAltitude());
|
||||
APPEND_ENTITY_PROPERTY(PROP_STAGE_DAY, appendValue, properties.getStageDay());
|
||||
APPEND_ENTITY_PROPERTY(PROP_STAGE_HOUR, appendValue, properties.getStageHour());
|
||||
|
||||
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_MARKETPLACE_ID, appendValue, properties.getMarketplaceID());
|
||||
|
@ -864,7 +867,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
|
||||
if (properties.getType() == EntityTypes::Model) {
|
||||
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MODEL_URL, setModelURL);
|
||||
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_COLLISION_MODEL_URL, setCollisionModelURL);
|
||||
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_ANIMATION_FPS, float, setAnimationFPS);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex);
|
||||
|
@ -903,6 +906,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_ALTITUDE, float, setStageAltitude);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_DAY, quint16, setStageDay);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_HOUR, float, setStageHour);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType);
|
||||
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL);
|
||||
}
|
||||
|
||||
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MARKETPLACE_ID, setMarketplaceID);
|
||||
|
@ -958,7 +963,7 @@ void EntityItemProperties::markAllChanged() {
|
|||
_visibleChanged = true;
|
||||
_colorChanged = true;
|
||||
_modelURLChanged = true;
|
||||
_collisionModelURLChanged = true;
|
||||
_compoundShapeURLChanged = true;
|
||||
_animationURLChanged = true;
|
||||
_animationIsPlayingChanged = true;
|
||||
_animationFrameIndexChanged = true;
|
||||
|
|
|
@ -93,7 +93,7 @@ enum EntityPropertyList {
|
|||
PROP_LOCAL_GRAVITY,
|
||||
PROP_PARTICLE_RADIUS,
|
||||
|
||||
PROP_COLLISION_MODEL_URL,
|
||||
PROP_COMPOUND_SHAPE_URL,
|
||||
PROP_MARKETPLACE_ID,
|
||||
PROP_ACCELERATION,
|
||||
PROP_SIMULATOR_ID,
|
||||
|
@ -197,7 +197,7 @@ public:
|
|||
DEFINE_PROPERTY_REF(PROP_SCRIPT, Script, script, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor);
|
||||
DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_COLLISION_MODEL_URL, CollisionModelURL, collisionModelURL, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_ANIMATION_URL, AnimationURL, animationURL, QString);
|
||||
DEFINE_PROPERTY(PROP_ANIMATION_FPS, AnimationFPS, animationFPS, float);
|
||||
DEFINE_PROPERTY(PROP_ANIMATION_FRAME_INDEX, AnimationFrameIndex, animationFrameIndex, float);
|
||||
|
@ -340,7 +340,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
|
|||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Script, script, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Color, color, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ModelURL, modelURL, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, CollisionModelURL, collisionModelURL, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, CompoundShapeURL, compoundShapeURL, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationURL, animationURL, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationFPS, animationFPS, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationFrameIndex, animationFrameIndex, "");
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "EntityTree.h"
|
||||
#include "LightEntityItem.h"
|
||||
#include "ModelEntityItem.h"
|
||||
#include "ZoneEntityItem.h"
|
||||
|
||||
|
||||
EntityScriptingInterface::EntityScriptingInterface() :
|
||||
|
@ -64,17 +65,8 @@ void EntityScriptingInterface::setEntityTree(EntityTree* modelTree) {
|
|||
void setSimId(EntityItemProperties& propertiesWithSimID, EntityItem* entity) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
const QUuid myNodeID = nodeList->getSessionUUID();
|
||||
|
||||
// if this entity has non-zero physics/simulation related values, claim simulation ownership
|
||||
if (propertiesWithSimID.velocityChanged() ||
|
||||
propertiesWithSimID.rotationChanged() ||
|
||||
propertiesWithSimID.containsPositionChange()) {
|
||||
propertiesWithSimID.setSimulatorID(myNodeID);
|
||||
entity->setSimulatorID(myNodeID);
|
||||
} else if (entity->getSimulatorID() == myNodeID) {
|
||||
propertiesWithSimID.setSimulatorID(QUuid()); // give up simulation ownership
|
||||
entity->setSimulatorID(QUuid());
|
||||
}
|
||||
propertiesWithSimID.setSimulatorID(myNodeID);
|
||||
entity->setSimulatorID(myNodeID);
|
||||
}
|
||||
|
||||
|
||||
|
@ -315,6 +307,14 @@ bool EntityScriptingInterface::getLightsArePickable() const {
|
|||
return LightEntityItem::getLightsArePickable();
|
||||
}
|
||||
|
||||
void EntityScriptingInterface::setZonesArePickable(bool value) {
|
||||
ZoneEntityItem::setZonesArePickable(value);
|
||||
}
|
||||
|
||||
bool EntityScriptingInterface::getZonesArePickable() const {
|
||||
return ZoneEntityItem::getZonesArePickable();
|
||||
}
|
||||
|
||||
void EntityScriptingInterface::setSendPhysicsUpdates(bool value) {
|
||||
EntityItem::setSendPhysicsUpdates(value);
|
||||
}
|
||||
|
|
|
@ -111,6 +111,9 @@ public slots:
|
|||
Q_INVOKABLE void setLightsArePickable(bool value);
|
||||
Q_INVOKABLE bool getLightsArePickable() const;
|
||||
|
||||
Q_INVOKABLE void setZonesArePickable(bool value);
|
||||
Q_INVOKABLE bool getZonesArePickable() const;
|
||||
|
||||
Q_INVOKABLE void setSendPhysicsUpdates(bool value);
|
||||
Q_INVOKABLE bool getSendPhysicsUpdates() const;
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "ModelEntityItem.h"
|
||||
|
||||
const QString ModelEntityItem::DEFAULT_MODEL_URL = QString("");
|
||||
const QString ModelEntityItem::DEFAULT_COLLISION_MODEL_URL = QString("");
|
||||
const QString ModelEntityItem::DEFAULT_COMPOUND_SHAPE_URL = QString("");
|
||||
const QString ModelEntityItem::DEFAULT_ANIMATION_URL = QString("");
|
||||
const float ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX = 0.0f;
|
||||
const bool ModelEntityItem::DEFAULT_ANIMATION_IS_PLAYING = false;
|
||||
|
@ -47,7 +47,7 @@ EntityItemProperties ModelEntityItem::getProperties() const {
|
|||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(modelURL, getModelURL);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionModelURL, getCollisionModelURL);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationURL, getAnimationURL);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationIsPlaying, getAnimationIsPlaying);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFrameIndex, getAnimationFrameIndex);
|
||||
|
@ -65,7 +65,7 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(modelURL, setModelURL);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionModelURL, setCollisionModelURL);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationURL, setAnimationURL);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationIsPlaying, setAnimationIsPlaying);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFrameIndex, setAnimationFrameIndex);
|
||||
|
@ -98,11 +98,11 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
|
|||
READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color);
|
||||
READ_ENTITY_PROPERTY_STRING(PROP_MODEL_URL, setModelURL);
|
||||
if (args.bitstreamVersion < VERSION_ENTITIES_HAS_COLLISION_MODEL) {
|
||||
setCollisionModelURL("");
|
||||
setCompoundShapeURL("");
|
||||
} else if (args.bitstreamVersion == VERSION_ENTITIES_HAS_COLLISION_MODEL) {
|
||||
READ_ENTITY_PROPERTY_STRING(PROP_COLLISION_MODEL_URL_OLD_VERSION, setCollisionModelURL);
|
||||
READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL);
|
||||
} else {
|
||||
READ_ENTITY_PROPERTY_STRING(PROP_COLLISION_MODEL_URL, setCollisionModelURL);
|
||||
READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL);
|
||||
}
|
||||
READ_ENTITY_PROPERTY_STRING(PROP_ANIMATION_URL, setAnimationURL);
|
||||
|
||||
|
@ -140,7 +140,7 @@ EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams&
|
|||
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
|
||||
|
||||
requestedProperties += PROP_MODEL_URL;
|
||||
requestedProperties += PROP_COLLISION_MODEL_URL;
|
||||
requestedProperties += PROP_COMPOUND_SHAPE_URL;
|
||||
requestedProperties += PROP_ANIMATION_URL;
|
||||
requestedProperties += PROP_ANIMATION_FPS;
|
||||
requestedProperties += PROP_ANIMATION_FRAME_INDEX;
|
||||
|
@ -164,7 +164,7 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
|
|||
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor());
|
||||
APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, getModelURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLLISION_MODEL_URL, appendValue, getCollisionModelURL());
|
||||
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());
|
||||
|
@ -272,7 +272,7 @@ void ModelEntityItem::debugDump() const {
|
|||
qCDebug(entities) << " position:" << getPosition();
|
||||
qCDebug(entities) << " dimensions:" << getDimensions();
|
||||
qCDebug(entities) << " model URL:" << getModelURL();
|
||||
qCDebug(entities) << " collision model URL:" << getCollisionModelURL();
|
||||
qCDebug(entities) << " compound shape URL:" << getCompoundShapeURL();
|
||||
}
|
||||
|
||||
void ModelEntityItem::updateShapeType(ShapeType type) {
|
||||
|
@ -280,8 +280,8 @@ void ModelEntityItem::updateShapeType(ShapeType type) {
|
|||
// we have allowed inconsistent ShapeType's to be stored in SVO files in the past (this was a bug)
|
||||
// but we are now enforcing the entity properties to be consistent. To make the possible we're
|
||||
// introducing a temporary workaround: we will ignore ShapeType updates that conflict with the
|
||||
// _collisionModelURL.
|
||||
if (hasCollisionModel()) {
|
||||
// _compoundShapeURL.
|
||||
if (hasCompoundShapeURL()) {
|
||||
type = SHAPE_TYPE_COMPOUND;
|
||||
}
|
||||
// END_TEMPORARY_WORKAROUND
|
||||
|
@ -295,17 +295,17 @@ void ModelEntityItem::updateShapeType(ShapeType type) {
|
|||
// virtual
|
||||
ShapeType ModelEntityItem::getShapeType() const {
|
||||
if (_shapeType == SHAPE_TYPE_COMPOUND) {
|
||||
return hasCollisionModel() ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE;
|
||||
return hasCompoundShapeURL() ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE;
|
||||
} else {
|
||||
return _shapeType;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelEntityItem::setCollisionModelURL(const QString& url) {
|
||||
if (_collisionModelURL != url) {
|
||||
_collisionModelURL = url;
|
||||
void ModelEntityItem::setCompoundShapeURL(const QString& url) {
|
||||
if (_compoundShapeURL != url) {
|
||||
_compoundShapeURL = url;
|
||||
_dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS;
|
||||
_shapeType = _collisionModelURL.isEmpty() ? SHAPE_TYPE_NONE : SHAPE_TYPE_COMPOUND;
|
||||
_shapeType = _compoundShapeURL.isEmpty() ? SHAPE_TYPE_NONE : SHAPE_TYPE_COMPOUND;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,13 +57,13 @@ public:
|
|||
const rgbColor& getColor() const { return _color; }
|
||||
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
|
||||
bool hasModel() const { return !_modelURL.isEmpty(); }
|
||||
virtual bool hasCollisionModel() const { return !_collisionModelURL.isEmpty(); }
|
||||
virtual bool hasCompoundShapeURL() const { return !_compoundShapeURL.isEmpty(); }
|
||||
|
||||
static const QString DEFAULT_MODEL_URL;
|
||||
const QString& getModelURL() const { return _modelURL; }
|
||||
|
||||
static const QString DEFAULT_COLLISION_MODEL_URL;
|
||||
const QString& getCollisionModelURL() const { return _collisionModelURL; }
|
||||
static const QString DEFAULT_COMPOUND_SHAPE_URL;
|
||||
const QString& getCompoundShapeURL() const { return _compoundShapeURL; }
|
||||
|
||||
bool hasAnimation() const { return !_animationURL.isEmpty(); }
|
||||
static const QString DEFAULT_ANIMATION_URL;
|
||||
|
@ -78,7 +78,7 @@ public:
|
|||
|
||||
// model related properties
|
||||
void setModelURL(const QString& url) { _modelURL = url; }
|
||||
virtual void setCollisionModelURL(const QString& url);
|
||||
virtual void setCompoundShapeURL(const QString& url);
|
||||
void setAnimationURL(const QString& url);
|
||||
static const float DEFAULT_ANIMATION_FRAME_INDEX;
|
||||
void setAnimationFrameIndex(float value);
|
||||
|
@ -126,7 +126,7 @@ protected:
|
|||
|
||||
rgbColor _color;
|
||||
QString _modelURL;
|
||||
QString _collisionModelURL;
|
||||
QString _compoundShapeURL;
|
||||
|
||||
quint64 _lastAnimated;
|
||||
QString _animationURL;
|
||||
|
|
|
@ -96,11 +96,7 @@ bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, cons
|
|||
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
|
||||
void** intersectedObject, bool precisionPicking) const {
|
||||
// determine the ray in the frame of the entity transformed from a unit sphere
|
||||
glm::mat4 translation = glm::translate(getPosition());
|
||||
glm::mat4 rotation = glm::mat4_cast(getRotation());
|
||||
glm::mat4 scale = glm::scale(getDimensions());
|
||||
glm::mat4 registration = glm::translate(glm::vec3(0.5f, 0.5f, 0.5f) - getRegistrationPoint());
|
||||
glm::mat4 entityToWorldMatrix = translation * rotation * scale * registration;
|
||||
glm::mat4 entityToWorldMatrix = getEntityToWorldMatrix();
|
||||
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
|
||||
glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
|
||||
glm::vec3 entityFrameDirection = glm::normalize(glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f)));
|
||||
|
@ -112,7 +108,7 @@ bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, cons
|
|||
glm::vec3 entityFrameHitAt = entityFrameOrigin + (entityFrameDirection * localDistance);
|
||||
// then translate back to work coordinates
|
||||
glm::vec3 hitAt = glm::vec3(entityToWorldMatrix * glm::vec4(entityFrameHitAt, 1.0f));
|
||||
distance = glm::distance(origin,hitAt);
|
||||
distance = glm::distance(origin, hitAt);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -50,9 +50,6 @@ public:
|
|||
_color[BLUE_INDEX] = value.blue;
|
||||
}
|
||||
|
||||
// TODO: implement proper contains for 3D ellipsoid
|
||||
//virtual bool contains(const glm::vec3& point) const;
|
||||
|
||||
virtual ShapeType getShapeType() const { return SHAPE_TYPE_SPHERE; }
|
||||
|
||||
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||
|
|
|
@ -48,11 +48,6 @@ void TextEntityItem::setDimensions(const glm::vec3& value) {
|
|||
_dimensions = glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH);
|
||||
}
|
||||
|
||||
void TextEntityItem::setDimensionsInDomainUnits(const glm::vec3& value) {
|
||||
// NOTE: Text Entities always have a "depth" of 1cm.
|
||||
_dimensions = glm::vec3(value.x * (float)TREE_SCALE, value.y * (float)TREE_SCALE, TEXT_ENTITY_ITEM_FIXED_DEPTH);
|
||||
}
|
||||
|
||||
EntityItemProperties TextEntityItem::getProperties() const {
|
||||
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ public:
|
|||
|
||||
/// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately
|
||||
virtual void setDimensions(const glm::vec3& value);
|
||||
virtual void setDimensionsInDomainUnits(const glm::vec3& value);
|
||||
virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; }
|
||||
|
||||
// methods for getting/setting all properties of an entity
|
||||
|
|
|
@ -31,6 +31,8 @@ const float ZoneEntityItem::DEFAULT_STAGE_LONGITUDE = 122.407f;
|
|||
const float ZoneEntityItem::DEFAULT_STAGE_ALTITUDE = 0.03f;
|
||||
const quint16 ZoneEntityItem::DEFAULT_STAGE_DAY = 60;
|
||||
const float ZoneEntityItem::DEFAULT_STAGE_HOUR = 12.0f;
|
||||
const ShapeType ZoneEntityItem::DEFAULT_SHAPE_TYPE = SHAPE_TYPE_BOX;
|
||||
const QString ZoneEntityItem::DEFAULT_COMPOUND_SHAPE_URL = "";
|
||||
|
||||
EntityItem* ZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
EntityItem* result = new ZoneEntityItem(entityID, properties);
|
||||
|
@ -56,6 +58,8 @@ ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID, const EntityIte
|
|||
_stageAltitude = DEFAULT_STAGE_ALTITUDE;
|
||||
_stageDay = DEFAULT_STAGE_DAY;
|
||||
_stageHour = DEFAULT_STAGE_HOUR;
|
||||
_shapeType = DEFAULT_SHAPE_TYPE;
|
||||
_compoundShapeURL = DEFAULT_COMPOUND_SHAPE_URL;
|
||||
|
||||
setProperties(properties);
|
||||
}
|
||||
|
@ -73,6 +77,8 @@ EntityItemProperties ZoneEntityItem::getProperties() const {
|
|||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(stageAltitude, getStageAltitude);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(stageDay, getStageDay);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(stageHour, getStageHour);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL);
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
@ -91,6 +97,8 @@ bool ZoneEntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(stageAltitude, setStageAltitude);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(stageDay, setStageDay);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(stageHour, setStageHour);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, updateShapeType);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL);
|
||||
|
||||
if (somethingChanged) {
|
||||
bool wantDebug = false;
|
||||
|
@ -122,6 +130,8 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
|
|||
READ_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, float, _stageAltitude);
|
||||
READ_ENTITY_PROPERTY(PROP_STAGE_DAY, quint16, _stageDay);
|
||||
READ_ENTITY_PROPERTY(PROP_STAGE_HOUR, float, _stageHour);
|
||||
READ_ENTITY_PROPERTY_SETTER(PROP_SHAPE_TYPE, ShapeType, updateShapeType);
|
||||
READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL);
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
@ -141,6 +151,8 @@ EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& p
|
|||
requestedProperties += PROP_STAGE_ALTITUDE;
|
||||
requestedProperties += PROP_STAGE_DAY;
|
||||
requestedProperties += PROP_STAGE_HOUR;
|
||||
requestedProperties += PROP_SHAPE_TYPE;
|
||||
requestedProperties += PROP_COMPOUND_SHAPE_URL;
|
||||
|
||||
return requestedProperties;
|
||||
}
|
||||
|
@ -165,6 +177,8 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
|
|||
APPEND_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, appendValue, getStageAltitude());
|
||||
APPEND_ENTITY_PROPERTY(PROP_STAGE_DAY, appendValue, getStageDay());
|
||||
APPEND_ENTITY_PROPERTY(PROP_STAGE_HOUR, appendValue, getStageHour());
|
||||
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, appendValue, (uint32_t)getShapeType());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, getCompoundShapeURL());
|
||||
}
|
||||
|
||||
void ZoneEntityItem::debugDump() const {
|
||||
|
@ -185,3 +199,27 @@ void ZoneEntityItem::debugDump() const {
|
|||
qCDebug(entities) << " _stageHour:" << _stageHour;
|
||||
}
|
||||
|
||||
ShapeType ZoneEntityItem::getShapeType() const {
|
||||
// Zones are not allowed to have a SHAPE_TYPE_NONE... they are always at least a SHAPE_TYPE_BOX
|
||||
if (_shapeType == SHAPE_TYPE_COMPOUND) {
|
||||
return hasCompoundShapeURL() ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_BOX;
|
||||
} else {
|
||||
return _shapeType == SHAPE_TYPE_NONE ? SHAPE_TYPE_BOX : _shapeType;
|
||||
}
|
||||
}
|
||||
|
||||
void ZoneEntityItem::setCompoundShapeURL(const QString& url) {
|
||||
_compoundShapeURL = url;
|
||||
if (!_compoundShapeURL.isEmpty()) {
|
||||
updateShapeType(SHAPE_TYPE_COMPOUND);
|
||||
} else if (_shapeType == SHAPE_TYPE_COMPOUND) {
|
||||
_shapeType = DEFAULT_SHAPE_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
bool ZoneEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
|
||||
void** intersectedObject, bool precisionPicking) const {
|
||||
|
||||
return _zonesArePickable;
|
||||
}
|
||||
|
|
|
@ -91,7 +91,19 @@ public:
|
|||
|
||||
static bool getZonesArePickable() { return _zonesArePickable; }
|
||||
static void setZonesArePickable(bool value) { _zonesArePickable = value; }
|
||||
|
||||
|
||||
virtual bool isReadyToComputeShape() { return false; }
|
||||
void updateShapeType(ShapeType type) { _shapeType = type; }
|
||||
virtual ShapeType getShapeType() const;
|
||||
|
||||
virtual bool hasCompoundShapeURL() const { return !_compoundShapeURL.isEmpty(); }
|
||||
const QString getCompoundShapeURL() const { return _compoundShapeURL; }
|
||||
virtual void setCompoundShapeURL(const QString& url);
|
||||
|
||||
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
|
||||
void** intersectedObject, bool precisionPicking) const;
|
||||
|
||||
virtual void debugDump() const;
|
||||
|
||||
|
@ -105,6 +117,8 @@ public:
|
|||
static const float DEFAULT_STAGE_ALTITUDE;
|
||||
static const quint16 DEFAULT_STAGE_DAY;
|
||||
static const float DEFAULT_STAGE_HOUR;
|
||||
static const ShapeType DEFAULT_SHAPE_TYPE;
|
||||
static const QString DEFAULT_COMPOUND_SHAPE_URL;
|
||||
|
||||
protected:
|
||||
// properties of the "sun" in the zone
|
||||
|
@ -118,6 +132,9 @@ protected:
|
|||
float _stageAltitude;
|
||||
uint16_t _stageDay;
|
||||
float _stageHour;
|
||||
|
||||
ShapeType _shapeType = SHAPE_TYPE_NONE;
|
||||
QString _compoundShapeURL;
|
||||
|
||||
static bool _zonesArePickable;
|
||||
};
|
||||
|
|
|
@ -125,6 +125,51 @@ Extents FBXGeometry::getUnscaledMeshExtents() const {
|
|||
return scaledExtents;
|
||||
}
|
||||
|
||||
// TODO: Move to model::Mesh when Sam's ready
|
||||
bool FBXGeometry::convexHullContains(const glm::vec3& point) const {
|
||||
if (!getUnscaledMeshExtents().containsPoint(point)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto checkEachPrimitive = [=](FBXMesh& mesh, QVector<int> indices, int primitiveSize) -> bool {
|
||||
// Check whether the point is "behind" all the primitives.
|
||||
for (unsigned int j = 0; j < indices.size(); j += primitiveSize) {
|
||||
if (!isPointBehindTrianglesPlane(point,
|
||||
mesh.vertices[indices[j]],
|
||||
mesh.vertices[indices[j + 1]],
|
||||
mesh.vertices[indices[j + 2]])) {
|
||||
// it's not behind at least one so we bail
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// Check that the point is contained in at least one convex mesh.
|
||||
for (auto mesh : meshes) {
|
||||
bool insideMesh = true;
|
||||
|
||||
// To be considered inside a convex mesh,
|
||||
// the point needs to be "behind" all the primitives respective planes.
|
||||
for (auto part : mesh.parts) {
|
||||
// run through all the triangles and quads
|
||||
if (!checkEachPrimitive(mesh, part.triangleIndices, 3) ||
|
||||
!checkEachPrimitive(mesh, part.quadIndices, 4)) {
|
||||
// If not, the point is outside, bail for this mesh
|
||||
insideMesh = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (insideMesh) {
|
||||
// It's inside this mesh, return true.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// It wasn't in any mesh, return false.
|
||||
return false;
|
||||
}
|
||||
|
||||
QString FBXGeometry::getModelNameOfMesh(int meshIndex) const {
|
||||
if (meshIndicesToModelNames.contains(meshIndex)) {
|
||||
return meshIndicesToModelNames.value(meshIndex);
|
||||
|
@ -132,8 +177,6 @@ QString FBXGeometry::getModelNameOfMesh(int meshIndex) const {
|
|||
return QString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int fbxGeometryMetaTypeId = qRegisterMetaType<FBXGeometry>();
|
||||
static int fbxAnimationFrameMetaTypeId = qRegisterMetaType<FBXAnimationFrame>();
|
||||
static int fbxAnimationFrameVectorMetaTypeId = qRegisterMetaType<QVector<FBXAnimationFrame> >();
|
||||
|
|
|
@ -252,6 +252,7 @@ public:
|
|||
/// Returns the unscaled extents of the model's mesh
|
||||
Extents getUnscaledMeshExtents() const;
|
||||
|
||||
bool convexHullContains(const glm::vec3& point) const;
|
||||
|
||||
QHash<int, QString> meshIndicesToModelNames;
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ PacketVersion versionForPacketType(PacketType type) {
|
|||
return 1;
|
||||
case PacketTypeEntityAddOrEdit:
|
||||
case PacketTypeEntityData:
|
||||
return VERSION_ENTITIES_ZONE_ENTITIES_EXIST;
|
||||
return VERSION_ENTITIES_ZONE_ENTITIES_HAVE_DYNAMIC_SHAPE;
|
||||
case PacketTypeEntityErase:
|
||||
return 2;
|
||||
case PacketTypeAudioStreamStats:
|
||||
|
|
|
@ -138,5 +138,6 @@ const PacketVersion VERSION_ENTITIES_HAS_MARKETPLACE_ID = 14;
|
|||
const PacketVersion VERSION_ENTITIES_HAVE_ACCELERATION = 15;
|
||||
const PacketVersion VERSION_ENTITIES_HAVE_UUIDS = 16;
|
||||
const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_EXIST = 17;
|
||||
const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_HAVE_DYNAMIC_SHAPE = 18;
|
||||
|
||||
#endif // hifi_PacketHeaders_h
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
#include "PhysicsHelpers.h"
|
||||
#include "PhysicsLogging.h"
|
||||
|
||||
static const float MEASURED_ACCELERATION_CLOSE_TO_ZERO = 0.05f;
|
||||
static const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f;
|
||||
static const quint8 STEPS_TO_DECIDE_BALLISTIC = 4;
|
||||
|
||||
QSet<EntityItem*>* _outgoingEntityList;
|
||||
|
||||
|
@ -34,8 +35,11 @@ void EntityMotionState::enqueueOutgoingEntity(EntityItem* entity) {
|
|||
_outgoingEntityList->insert(entity);
|
||||
}
|
||||
|
||||
EntityMotionState::EntityMotionState(EntityItem* entity)
|
||||
: _entity(entity) {
|
||||
EntityMotionState::EntityMotionState(EntityItem* entity) :
|
||||
_entity(entity),
|
||||
_accelerationNearlyGravityCount(0),
|
||||
_shouldClaimSimulationOwnership(false)
|
||||
{
|
||||
_type = MOTION_STATE_TYPE_ENTITY;
|
||||
assert(entity != NULL);
|
||||
}
|
||||
|
@ -191,7 +195,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (_entity->getShouldClaimSimulationOwnership()) {
|
||||
if (getShouldClaimSimulationOwnership()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -199,7 +203,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) {
|
|||
const QUuid& myNodeID = nodeList->getSessionUUID();
|
||||
const QUuid& simulatorID = _entity->getSimulatorID();
|
||||
|
||||
if (!simulatorID.isNull() && simulatorID != myNodeID) {
|
||||
if (simulatorID != myNodeID) {
|
||||
// some other Node owns the simulating of this, so don't broadcast the results of local simulation.
|
||||
return false;
|
||||
}
|
||||
|
@ -214,10 +218,26 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
|
|||
if (_outgoingPacketFlags) {
|
||||
EntityItemProperties properties = _entity->getProperties();
|
||||
|
||||
if (glm::length(_measuredAcceleration) < MEASURED_ACCELERATION_CLOSE_TO_ZERO) {
|
||||
_entity->setAcceleration(glm::vec3(0.0f));
|
||||
float gravityLength = glm::length(_entity->getGravity());
|
||||
float accVsGravity = glm::abs(glm::length(_measuredAcceleration) - gravityLength);
|
||||
if (accVsGravity < ACCELERATION_EQUIVALENT_EPSILON_RATIO * gravityLength) {
|
||||
// acceleration measured during the most recent simulation step was close to gravity.
|
||||
if (getAccelerationNearlyGravityCount() < STEPS_TO_DECIDE_BALLISTIC) {
|
||||
// only increment this if we haven't reached the threshold yet. this is to avoid
|
||||
// overflowing the counter.
|
||||
incrementAccelerationNearlyGravityCount();
|
||||
}
|
||||
} else {
|
||||
// acceleration wasn't similar to this entities gravity, so reset the went-ballistic counter
|
||||
resetAccelerationNearlyGravityCount();
|
||||
}
|
||||
|
||||
// if this entity has been accelerated at close to gravity for a certain number of simulation-steps, let
|
||||
// the entity server's estimates include gravity.
|
||||
if (getAccelerationNearlyGravityCount() >= STEPS_TO_DECIDE_BALLISTIC) {
|
||||
_entity->setAcceleration(_entity->getGravity());
|
||||
} else {
|
||||
_entity->setAcceleration(glm::vec3(0.0f));
|
||||
}
|
||||
|
||||
if (_outgoingPacketFlags & EntityItem::DIRTY_POSITION) {
|
||||
|
@ -266,16 +286,13 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
|
|||
QUuid myNodeID = nodeList->getSessionUUID();
|
||||
QUuid simulatorID = _entity->getSimulatorID();
|
||||
|
||||
if (_entity->getShouldClaimSimulationOwnership()) {
|
||||
if (getShouldClaimSimulationOwnership()) {
|
||||
_entity->setSimulatorID(myNodeID);
|
||||
properties.setSimulatorID(myNodeID);
|
||||
_entity->setShouldClaimSimulationOwnership(false);
|
||||
setShouldClaimSimulationOwnership(false);
|
||||
}
|
||||
else if (simulatorID.isNull() && !(zeroSpeed && zeroSpin)) {
|
||||
// The object is moving and nobody thinks they own the motion. set this Node as the simulator
|
||||
_entity->setSimulatorID(myNodeID);
|
||||
properties.setSimulatorID(myNodeID);
|
||||
} else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) {
|
||||
|
||||
if (simulatorID == myNodeID && zeroSpeed && zeroSpin) {
|
||||
// we are the simulator and the object has stopped. give up "simulator" status
|
||||
_entity->setSimulatorID(QUuid());
|
||||
properties.setSimulatorID(QUuid());
|
||||
|
|
|
@ -62,10 +62,18 @@ public:
|
|||
virtual uint32_t getIncomingDirtyFlags() const;
|
||||
virtual void clearIncomingDirtyFlags(uint32_t flags) { _entity->clearDirtyFlags(flags); }
|
||||
|
||||
EntityItem* getEntity() const { return _entity; }
|
||||
void incrementAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount++; }
|
||||
void resetAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount = 0; }
|
||||
quint8 getAccelerationNearlyGravityCount() { return _accelerationNearlyGravityCount; }
|
||||
|
||||
virtual EntityItem* getEntity() const { return _entity; }
|
||||
virtual void setShouldClaimSimulationOwnership(bool value) { _shouldClaimSimulationOwnership = value; }
|
||||
virtual bool getShouldClaimSimulationOwnership() { return _shouldClaimSimulationOwnership; }
|
||||
|
||||
protected:
|
||||
EntityItem* _entity;
|
||||
quint8 _accelerationNearlyGravityCount;
|
||||
bool _shouldClaimSimulationOwnership;
|
||||
};
|
||||
|
||||
#endif // hifi_EntityMotionState_h
|
||||
|
|
|
@ -111,6 +111,12 @@ public:
|
|||
virtual bool isMoving() const = 0;
|
||||
|
||||
friend class PhysicsEngine;
|
||||
|
||||
// these are here so we can call into EntityMotionObject with a base-class pointer
|
||||
virtual EntityItem* getEntity() const { return NULL; }
|
||||
virtual void setShouldClaimSimulationOwnership(bool value) { }
|
||||
virtual bool getShouldClaimSimulationOwnership() { return false; }
|
||||
|
||||
protected:
|
||||
void setRigidBody(btRigidBody* body);
|
||||
|
||||
|
|
|
@ -348,10 +348,10 @@ void PhysicsEngine::stepSimulation() {
|
|||
_characterController->postSimulation();
|
||||
}
|
||||
|
||||
computeCollisionEvents();
|
||||
|
||||
unlock();
|
||||
_entityTree->unlock();
|
||||
|
||||
computeCollisionEvents();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -369,6 +369,9 @@ void PhysicsEngine::stepNonPhysicalKinematics(const quint64& now) {
|
|||
void PhysicsEngine::computeCollisionEvents() {
|
||||
BT_PROFILE("computeCollisionEvents");
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
QUuid myNodeID = nodeList->getSessionUUID();
|
||||
|
||||
const btCollisionObject* characterCollisionObject =
|
||||
_characterController ? _characterController->getCollisionObject() : NULL;
|
||||
|
||||
|
@ -388,21 +391,31 @@ void PhysicsEngine::computeCollisionEvents() {
|
|||
continue;
|
||||
}
|
||||
|
||||
void* a = objectA->getUserPointer();
|
||||
void* b = objectB->getUserPointer();
|
||||
ObjectMotionState* a = static_cast<ObjectMotionState*>(objectA->getUserPointer());
|
||||
ObjectMotionState* b = static_cast<ObjectMotionState*>(objectB->getUserPointer());
|
||||
EntityItem* entityA = a ? a->getEntity() : NULL;
|
||||
EntityItem* entityB = b ? b->getEntity() : NULL;
|
||||
bool aIsDynamic = entityA && !objectA->isStaticOrKinematicObject();
|
||||
bool bIsDynamic = entityB && !objectB->isStaticOrKinematicObject();
|
||||
|
||||
if (a || b) {
|
||||
// the manifold has up to 4 distinct points, but only extract info from the first
|
||||
_contactMap[ContactKey(a, b)].update(_numContactFrames, contactManifold->getContactPoint(0), _originOffset);
|
||||
|
||||
// if our character capsule is colliding with something dynamic, claim simulation ownership.
|
||||
// see EntityMotionState::sendUpdate
|
||||
if (objectA == characterCollisionObject && !objectB->isStaticOrKinematicObject() && b) {
|
||||
EntityItem* entityB = static_cast<EntityMotionState*>(b)->getEntity();
|
||||
entityB->setShouldClaimSimulationOwnership(true);
|
||||
}
|
||||
// collisions cause infectious spread of simulation-ownership. we also attempt to take
|
||||
// ownership of anything that collides with our avatar.
|
||||
if ((aIsDynamic && entityA->getSimulatorID() == myNodeID) ||
|
||||
(a && a->getShouldClaimSimulationOwnership()) ||
|
||||
(objectA == characterCollisionObject)) {
|
||||
if (bIsDynamic) {
|
||||
b->setShouldClaimSimulationOwnership(true);
|
||||
}
|
||||
if (objectB == characterCollisionObject && !objectA->isStaticOrKinematicObject() && a) {
|
||||
EntityItem* entityA = static_cast<EntityMotionState*>(a)->getEntity();
|
||||
entityA->setShouldClaimSimulationOwnership(true);
|
||||
}
|
||||
if ((bIsDynamic && entityB->getSimulatorID() == myNodeID) ||
|
||||
(b && b->getShouldClaimSimulationOwnership()) ||
|
||||
(objectB == characterCollisionObject)) {
|
||||
if (aIsDynamic) {
|
||||
a->setShouldClaimSimulationOwnership(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -413,7 +426,6 @@ void PhysicsEngine::computeCollisionEvents() {
|
|||
// scan known contacts and trigger events
|
||||
ContactMap::iterator contactItr = _contactMap.begin();
|
||||
|
||||
|
||||
while (contactItr != _contactMap.end()) {
|
||||
ObjectMotionState* A = static_cast<ObjectMotionState*>(contactItr->first._a);
|
||||
ObjectMotionState* B = static_cast<ObjectMotionState*>(contactItr->first._b);
|
||||
|
@ -521,9 +533,55 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap
|
|||
motionState->resetMeasuredAcceleration();
|
||||
}
|
||||
|
||||
void PhysicsEngine::bump(EntityItem* bumpEntity) {
|
||||
// If this node is doing something like deleting an entity, scan for contacts involving the
|
||||
// entity. For each found, flag the other entity involved as being simulated by this node.
|
||||
lock();
|
||||
int numManifolds = _collisionDispatcher->getNumManifolds();
|
||||
for (int i = 0; i < numManifolds; ++i) {
|
||||
btPersistentManifold* contactManifold = _collisionDispatcher->getManifoldByIndexInternal(i);
|
||||
if (contactManifold->getNumContacts() > 0) {
|
||||
const btCollisionObject* objectA = static_cast<const btCollisionObject*>(contactManifold->getBody0());
|
||||
const btCollisionObject* objectB = static_cast<const btCollisionObject*>(contactManifold->getBody1());
|
||||
if (objectA && objectB) {
|
||||
void* a = objectA->getUserPointer();
|
||||
void* b = objectB->getUserPointer();
|
||||
if (a && b) {
|
||||
EntityMotionState* entityMotionStateA = static_cast<EntityMotionState*>(a);
|
||||
EntityMotionState* entityMotionStateB = static_cast<EntityMotionState*>(b);
|
||||
EntityItem* entityA = entityMotionStateA ? entityMotionStateA->getEntity() : NULL;
|
||||
EntityItem* entityB = entityMotionStateB ? entityMotionStateB->getEntity() : NULL;
|
||||
if (entityA && entityB) {
|
||||
if (entityA == bumpEntity) {
|
||||
entityMotionStateB->setShouldClaimSimulationOwnership(true);
|
||||
if (!objectB->isActive()) {
|
||||
objectB->setActivationState(ACTIVE_TAG);
|
||||
}
|
||||
}
|
||||
if (entityB == bumpEntity) {
|
||||
entityMotionStateA->setShouldClaimSimulationOwnership(true);
|
||||
if (!objectA->isActive()) {
|
||||
objectA->setActivationState(ACTIVE_TAG);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
void PhysicsEngine::removeObjectFromBullet(ObjectMotionState* motionState) {
|
||||
assert(motionState);
|
||||
btRigidBody* body = motionState->getRigidBody();
|
||||
|
||||
// set the about-to-be-deleted entity active in order to wake up the island it's part of. this is done
|
||||
// so that anything resting on top of it will fall.
|
||||
// body->setActivationState(ACTIVE_TAG);
|
||||
EntityItem* entity = static_cast<EntityMotionState*>(motionState)->getEntity();
|
||||
bump(entity);
|
||||
|
||||
if (body) {
|
||||
const btCollisionShape* shape = body->getCollisionShape();
|
||||
_dynamicsWorld->removeRigidBody(body);
|
||||
|
|
|
@ -98,6 +98,7 @@ private:
|
|||
// return 'true' of update was successful
|
||||
bool updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags);
|
||||
void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags);
|
||||
void bump(EntityItem* bumpEntity);
|
||||
|
||||
btClock _clock;
|
||||
btDefaultCollisionConfiguration* _collisionConfig = NULL;
|
||||
|
|
|
@ -203,6 +203,13 @@ glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2) {
|
|||
return glm::angleAxis(angle, axis);
|
||||
}
|
||||
|
||||
bool isPointBehindTrianglesPlane(glm::vec3 point, glm::vec3 p0, glm::vec3 p1, glm::vec3 p2) {
|
||||
glm::vec3 v1 = p0 - p1, v2 = p2 - p1; // Non-collinear vectors contained in the plane
|
||||
glm::vec3 n = glm::cross(v1, v2); // Plane's normal vector, pointing out of the triangle
|
||||
float d = -glm::dot(n, p0); // Compute plane's equation constant
|
||||
return (glm::dot(n, point) + d) >= 0;
|
||||
}
|
||||
|
||||
glm::vec3 extractTranslation(const glm::mat4& matrix) {
|
||||
return glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2]);
|
||||
}
|
||||
|
|
|
@ -82,6 +82,8 @@ float angleBetween(const glm::vec3& v1, const glm::vec3& v2);
|
|||
|
||||
glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2);
|
||||
|
||||
bool isPointBehindTrianglesPlane(glm::vec3 point, glm::vec3 p0, glm::vec3 p1, glm::vec3 p2);
|
||||
|
||||
glm::vec3 extractTranslation(const glm::mat4& matrix);
|
||||
|
||||
void setTranslation(glm::mat4& matrix, const glm::vec3& translation);
|
||||
|
|
|
@ -114,7 +114,7 @@ float ShapeInfo::computeVolume() const {
|
|||
}
|
||||
case SHAPE_TYPE_CAPSULE_Y: {
|
||||
float radius = _halfExtents.x;
|
||||
volume = PI * radius * radius * (2.0f * _halfExtents.y + 4.0f * radius / 3.0f);
|
||||
volume = PI * radius * radius * (2.0f * (_halfExtents.y - _halfExtents.x) + 4.0f * radius / 3.0f);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -124,6 +124,54 @@ float ShapeInfo::computeVolume() const {
|
|||
return volume;
|
||||
}
|
||||
|
||||
bool ShapeInfo::contains(const glm::vec3& point) const {
|
||||
switch(_type) {
|
||||
case SHAPE_TYPE_SPHERE:
|
||||
return glm::length(point) <= _halfExtents.x;
|
||||
case SHAPE_TYPE_ELLIPSOID: {
|
||||
glm::vec3 scaledPoint = glm::abs(point) / _halfExtents;
|
||||
return glm::length(scaledPoint) <= 1.0f;
|
||||
}
|
||||
case SHAPE_TYPE_CYLINDER_X:
|
||||
return glm::length(glm::vec2(point.y, point.z)) <= _halfExtents.z;
|
||||
case SHAPE_TYPE_CYLINDER_Y:
|
||||
return glm::length(glm::vec2(point.x, point.z)) <= _halfExtents.x;
|
||||
case SHAPE_TYPE_CYLINDER_Z:
|
||||
return glm::length(glm::vec2(point.x, point.y)) <= _halfExtents.y;
|
||||
case SHAPE_TYPE_CAPSULE_X: {
|
||||
if (glm::abs(point.x) <= _halfExtents.x) {
|
||||
return glm::length(glm::vec2(point.y, point.z)) <= _halfExtents.z;
|
||||
} else {
|
||||
glm::vec3 absPoint = glm::abs(point) - _halfExtents.x;
|
||||
return glm::length(absPoint) <= _halfExtents.z;
|
||||
}
|
||||
}
|
||||
case SHAPE_TYPE_CAPSULE_Y: {
|
||||
if (glm::abs(point.y) <= _halfExtents.y) {
|
||||
return glm::length(glm::vec2(point.x, point.z)) <= _halfExtents.x;
|
||||
} else {
|
||||
glm::vec3 absPoint = glm::abs(point) - _halfExtents.y;
|
||||
return glm::length(absPoint) <= _halfExtents.x;
|
||||
}
|
||||
}
|
||||
case SHAPE_TYPE_CAPSULE_Z: {
|
||||
if (glm::abs(point.z) <= _halfExtents.z) {
|
||||
return glm::length(glm::vec2(point.x, point.y)) <= _halfExtents.y;
|
||||
} else {
|
||||
glm::vec3 absPoint = glm::abs(point) - _halfExtents.z;
|
||||
return glm::length(absPoint) <= _halfExtents.y;
|
||||
}
|
||||
}
|
||||
case SHAPE_TYPE_BOX:
|
||||
default: {
|
||||
glm::vec3 absPoint = glm::abs(point);
|
||||
return absPoint.x <= _halfExtents.x
|
||||
&& absPoint.y <= _halfExtents.y
|
||||
&& absPoint.z <= _halfExtents.z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const DoubleHashKey& ShapeInfo::getHash() const {
|
||||
// NOTE: we cache the key so we only ever need to compute it once for any valid ShapeInfo instance.
|
||||
if (_doubleHashKey.isNull() && _type != SHAPE_TYPE_NONE) {
|
||||
|
|
|
@ -57,6 +57,10 @@ public:
|
|||
void appendToPoints (const QVector<glm::vec3>& newPoints) { _points << newPoints; }
|
||||
|
||||
float computeVolume() const;
|
||||
|
||||
/// Returns whether point is inside the shape
|
||||
/// For compound shapes it will only return whether it is inside the bounding box
|
||||
bool contains(const glm::vec3& point) const;
|
||||
|
||||
const DoubleHashKey& getHash() const;
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
props.setHasProperty(PROP_POSITION);
|
||||
props.setHasProperty(PROP_RADIUS);
|
||||
props.setHasProperty(PROP_MODEL_URL);
|
||||
props.setHasProperty(PROP_COLLISION_MODEL_URL);
|
||||
props.setHasProperty(PROP_COMPOUND_SHAPE_URL);
|
||||
props.setHasProperty(PROP_ROTATION);
|
||||
|
||||
QByteArray encoded = props.encode();
|
||||
|
|
Loading…
Reference in a new issue