This commit is contained in:
Niraj Venkat 2015-06-24 17:33:57 -07:00
commit be053cfdc7
83 changed files with 1304 additions and 1082 deletions

View file

@ -21,7 +21,11 @@ if (WIN32)
# FIXME need to account for different architectures
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/LibOVR/Include CACHE TYPE INTERNAL)
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/LibOVR/Lib/Windows/Win32/Release/VS2013/LibOVR.lib CACHE TYPE INTERNAL)
if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/LibOVR/Lib/Windows/x64/Release/VS2013/LibOVR.lib CACHE TYPE INTERNAL)
else()
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/LibOVR/Lib/Windows/Win32/Release/VS2013/LibOVR.lib CACHE TYPE INTERNAL)
endif()
elseif(APPLE)

View file

@ -16,11 +16,16 @@ if (WIN32)
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE PATH "List of glew include directories")
set(_LIB_DIR ${SOURCE_DIR}/lib/Release/Win32)
if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
set(_LIB_DIR ${SOURCE_DIR}/lib/Release/x64)
set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${SOURCE_DIR}/bin/Release/x64 CACHE FILEPATH "Location of GLEW DLL")
else()
set(_LIB_DIR ${SOURCE_DIR}/lib/Release/Win32)
set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${SOURCE_DIR}/bin/Release/Win32 CACHE FILEPATH "Location of GLEW DLL")
endif()
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${_LIB_DIR}/glew32.lib CACHE FILEPATH "Location of GLEW release library")
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "Location of GLEW debug library")
set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${SOURCE_DIR}/bin/Release/Win32 CACHE FILEPATH "Location of GLEW DLL")
endif ()

View file

@ -73,9 +73,14 @@ if (APPLE)
)
elseif (WIN32)
set(_TBB_LIB_DIR "${SOURCE_DIR}/lib/ia32/vc12")
if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
set(_TBB_LIB_DIR "${SOURCE_DIR}/lib/intel64/vc12")
set(${EXTERNAL_NAME_UPPER}_DLL_PATH "${SOURCE_DIR}/bin/intel64/vc12" CACHE PATH "Path to TBB DLLs")
else()
set(_TBB_LIB_DIR "${SOURCE_DIR}/lib/ia32/vc12")
set(${EXTERNAL_NAME_UPPER}_DLL_PATH "${SOURCE_DIR}/bin/ia32/vc12" CACHE PATH "Path to TBB DLLs")
endif()
set(_LIB_EXT "lib")
set(${EXTERNAL_NAME_UPPER}_DLL_PATH "${SOURCE_DIR}/bin/ia32/vc12" CACHE PATH "Path to TBB DLLs")
elseif (ANDROID)
set(_TBB_LIB_DIR "${SOURCE_DIR}/lib")
set(_LIB_PREFIX "lib")

View file

@ -28,7 +28,11 @@ if (APPLE)
elseif (UNIX)
set(ARCH_DIR "UNIX")
elseif (WIN32)
set(ARCH_DIR "Win32")
if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
set(ARCH_DIR "x64")
else()
set(ARCH_DIR "Win32")
endif()
endif ()
find_library(FACESHIFT_LIBRARY_RELEASE NAME faceshift PATH_SUFFIXES lib/${ARCH_DIR} HINTS ${FACESHIFT_SEARCH_DIRS})

View file

@ -16,7 +16,16 @@
#
if (WIN32)
if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
set(ARCH_DIR "x64")
set(ARCH_NAME "64")
else()
set(ARCH_DIR "Win32")
set(ARCH_NAME "32")
endif()
find_path(NSIGHT_INCLUDE_DIRS
NAMES
nvToolsExt.h
@ -25,17 +34,18 @@ if (WIN32)
PATHS
"C:/Program Files/NVIDIA Corporation/NvToolsExt")
find_library(NSIGHT_LIBRARY_RELEASE nvToolsExt32_1
find_library(NSIGHT_LIBRARY_RELEASE "nvToolsExt${ARCH_NAME}_1"
PATH_SUFFIXES
"lib/Win32" "lib"
"lib/${ARCH_DIR}" "lib"
PATHS
"C:/Program Files/NVIDIA Corporation/NvToolsExt")
find_library(NSIGHT_LIBRARY_DEBUG nvToolsExt32_1
find_library(NSIGHT_LIBRARY_DEBUG "nvToolsExt${ARCH_NAME}_1"
PATH_SUFFIXES
"lib/Win32" "lib"
"lib/${ARCH_DIR}" "lib"
PATHS
"C:/Program Files/NVIDIA Corporation/NvToolsExt")
add_paths_to_fixup_libs("C:/Program Files/NVIDIA Corporation/NvToolsExt/bin/${ARCH_DIR}")
include(SelectLibraryConfigurations)
select_library_configurations(NSIGHT)
endif ()

View file

@ -30,12 +30,20 @@ elseif (UNIX)
find_library(SIXENSE_LIBRARY_RELEASE lib/linux_x64/release/libsixense_x64.so HINTS ${SIXENSE_SEARCH_DIRS})
# find_library(SIXENSE_LIBRARY_DEBUG lib/linux_x64/debug/libsixensed_x64.so HINTS ${SIXENSE_SEARCH_DIRS})
elseif (WIN32)
find_library(SIXENSE_LIBRARY_RELEASE lib/win32/release_dll/sixense.lib HINTS ${SIXENSE_SEARCH_DIRS})
find_library(SIXENSE_LIBRARY_DEBUG lib/win32/debug_dll/sixensed.lib HINTS ${SIXENSE_SEARCH_DIRS})
if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
set(ARCH_DIR "x64")
set(ARCH_SUFFIX "_x64")
else()
set(ARCH_DIR "Win32")
set(ARCH_SUFFIX "")
endif()
find_library(SIXENSE_LIBRARY_RELEASE "lib/${ARCH_DIR}/release_dll/sixense${ARCH_SUFFIX}.lib" HINTS ${SIXENSE_SEARCH_DIRS})
find_library(SIXENSE_LIBRARY_DEBUG "lib/${ARCH_DIR}/debug_dll/sixensed.lib" HINTS ${SIXENSE_SEARCH_DIRS})
find_path(SIXENSE_DEBUG_DLL_PATH sixensed.dll PATH_SUFFIXES bin/win32/debug_dll HINTS ${SIXENSE_SEARCH_DIRS})
find_path(SIXENSE_RELEASE_DLL_PATH sixense.dll PATH_SUFFIXES bin/win32/release_dll HINTS ${SIXENSE_SEARCH_DIRS})
find_path(SIXENSE_DEVICE_DLL_PATH DeviceDLL.dll PATH_SUFFIXES samples/win32/sixense_simple3d HINTS ${SIXENSE_SEARCH_DIRS})
find_path(SIXENSE_DEBUG_DLL_PATH "sixensed${ARCH_SUFFIX}.dll" PATH_SUFFIXES bin/${ARCH_DIR}/debug_dll HINTS ${SIXENSE_SEARCH_DIRS})
find_path(SIXENSE_RELEASE_DLL_PATH "sixense${ARCH_SUFFIX}.dll" PATH_SUFFIXES bin/${ARCH_DIR}/release_dll HINTS ${SIXENSE_SEARCH_DIRS})
find_path(SIXENSE_DEVICE_DLL_PATH DeviceDLL.dll PATH_SUFFIXES samples/${ARCH_DIR}/sixense_simple3d HINTS ${SIXENSE_SEARCH_DIRS})
endif ()
include(SelectLibraryConfigurations)

View file

@ -49,7 +49,7 @@ elseif (UNIX AND NOT ANDROID)
endif ()
elseif (WIN32)
if (CMAKE_CL_64)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(_TBB_ARCH_DIR "intel64")
else()
set(_TBB_ARCH_DIR "ia32")

View file

@ -100,12 +100,12 @@ var NUM_BUTTONS = 3;
var screenSize = Controller.getViewportDimensions();
var startX = screenSize.x / 2 - (NUM_BUTTONS * (BUTTON_SIZE + PADDING)) / 2;
Script.include(["../../libraries/toolBars.js"]);
const persistKey = "highfidelity.gun.toolbar.position";
var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL);
toolBar.save = function () {
Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y]));
};
var old = JSON.parse(Settings.getValue(persistKey) || '0');
var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.gun.toolbar", function (screenSize) {
return {
x: startX,
y: (screenSize.y - (BUTTON_SIZE + PADDING)),
};
});
var reticle = Overlays.addOverlay("image", {
x: screenSize.x / 2 - (BUTTON_SIZE / 2),
y: screenSize.y / 2 - (BUTTON_SIZE / 2),
@ -116,8 +116,6 @@ var reticle = Overlays.addOverlay("image", {
});
var offButton = toolBar.addOverlay("image", {
x: old ? old[0] : startX,
y: old ? old[1] : (screenSize.y - (BUTTON_SIZE + PADDING)),
width: BUTTON_SIZE,
height: BUTTON_SIZE,
imageURL: HIFI_PUBLIC_BUCKET + "images/gun/close.svg",
@ -181,7 +179,7 @@ function entityCollisionWithEntity(entity1, entity2, collision) {
}
function shootBullet(position, velocity, grenade) {
var BULLET_SIZE = 0.10;
var BULLET_SIZE = .09;
var BULLET_LIFETIME = 10.0;
var BULLET_GRAVITY = -0.25;
var GRENADE_VELOCITY = 15.0;

View file

@ -18,4 +18,5 @@ Script.load("users.js");
Script.load("grab.js");
Script.load("directory.js");
Script.load("mouseLook.js");
Script.load("hmdControls.js");
Script.load("dialTone.js");

View file

@ -33,15 +33,13 @@ var BUTTON_SIZE = 32;
var PADDING = 3;
Script.include(["libraries/toolBars.js"]);
var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL);
const persistKey = "highfidelity.dice.toolbar.position";
toolBar.save = function () {
Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y]));
};
var old = JSON.parse(Settings.getValue(persistKey) || '0');
var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.dice.toolbar", function (screenSize) {
return {
x: (screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING),
y: (screenSize.y - (BUTTON_SIZE + PADDING))
};
});
var offButton = toolBar.addOverlay("image", {
x: old ? old[0] : (screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING),
y: old ? old[1] : (screenSize.y - (BUTTON_SIZE + PADDING)),
width: BUTTON_SIZE,
height: BUTTON_SIZE,
imageURL: HIFI_PUBLIC_BUCKET + "images/close.png",

View file

@ -49,7 +49,6 @@ selectionManager.addEventListener(function() {
lightOverlayManager.updatePositions();
});
var windowDimensions = Controller.getViewportDimensions();
var toolIconUrl = HIFI_PUBLIC_BUCKET + "images/tools/";
var toolHeight = 50;
var toolWidth = 50;
@ -143,7 +142,12 @@ var toolBar = (function () {
browseMarketplaceButton;
function initialize() {
toolBar = new ToolBar(0, 0, ToolBar.VERTICAL);
toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.edit.toolbar", function (windowDimensions, toolbar) {
return {
x: windowDimensions.x - 8 - toolbar.width,
y: (windowDimensions.y - toolbar.height) / 2
};
});
browseMarketplaceButton = toolBar.addTool({
imageURL: toolIconUrl + "marketplace.svg",
@ -321,38 +325,6 @@ var toolBar = (function () {
}
}
const persistKey = "highfidelity.edit.toolbar.position";
that.move = function () {
var newViewPort,
toolsX,
toolsY;
newViewPort = Controller.getViewportDimensions();
if (toolBar === undefined) {
initialize();
toolBar.save = function () {
Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y]));
};
var old = JSON.parse(Settings.getValue(persistKey) || '0');
if (old) {
windowDimensions = newViewPort;
toolBar.move(old[0], old[1]);
return;
}
} else if (windowDimensions.x === newViewPort.x &&
windowDimensions.y === newViewPort.y) {
return;
}
windowDimensions = newViewPort;
toolsX = windowDimensions.x - 8 - toolBar.width;
toolsY = (windowDimensions.y - toolBar.height) / 2;
toolBar.move(toolsX, toolsY);
};
var newModelButtonDown = false;
var browseMarketplaceButtonDown = false;
that.mousePressEvent = function (event) {
@ -552,6 +524,7 @@ var toolBar = (function () {
toolBar.cleanup();
};
initialize();
return that;
}());
@ -931,7 +904,6 @@ var lastPosition = null;
// Do some stuff regularly, like check for placement of various overlays
Script.update.connect(function (deltaTime) {
toolBar.move();
progressDialog.move();
selectionDisplay.checkMove();
var dOrientation = Math.abs(Quat.dot(Camera.orientation, lastOrientation) - 1);

285
examples/hmdControls.js Normal file
View file

@ -0,0 +1,285 @@
//
// hmdControls.js
// examples
//
// Created by Sam Gondelman on 6/17/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
//
var MOVE_DISTANCE = 10.0;
var PITCH_INCREMENT = 0.5; // degrees
var pitchChange = 0; // degrees
var YAW_INCREMENT = 0.5; // degrees
var VR_YAW_INCREMENT = 15.0; // degrees
var yawChange = 0;
var BOOM_SPEED = 0.5;
var THRESHOLD = 0.2;
var CAMERA_UPDATE_TIME = 0.5;
var yawTimer = CAMERA_UPDATE_TIME;
var shifted = false;
var SHIFT_UPDATE_TIME = 0.5;
var shiftTimer = SHIFT_UPDATE_TIME;
var SHIFT_MAG = 4.0;
var warpActive = false;
var WARP_UPDATE_TIME = .5;
var warpTimer = WARP_UPDATE_TIME;
var warpPosition = { x: 0, y: 0, z: 0 };
var WARP_SPHERE_SIZE = 1;
var warpSphere = Overlays.addOverlay("sphere", {
position: { x: 0, y: 0, z: 0 },
size: WARP_SPHERE_SIZE,
color: { red: 0, green: 255, blue: 0 },
alpha: 1.0,
solid: true,
visible: false,
});
var WARP_LINE_HEIGHT = 10;
var warpLine = Overlays.addOverlay("line3d", {
start: { x: 0, y: 0, z:0 },
end: { x: 0, y: 0, z: 0 },
color: { red: 0, green: 255, blue: 255},
alpha: 1,
lineWidth: 5,
visible: false,
});
var velocity = { x: 0, y: 0, z: 0 };
var VERY_LONG_TIME = 1000000.0;
var active = Menu.isOptionChecked("Enable VR Mode");
var prevVRMode = Menu.isOptionChecked("Enable VR Mode");
var hmdControls = (function () {
function onKeyPressEvent(event) {
if (event.text == 'g' && event.isMeta) {
active = !active;
}
}
function findAction(name) {
var actions = Controller.getAllActions();
for (var i = 0; i < actions.length; i++) {
if (actions[i].actionName == name) {
return i;
}
}
// If the action isn't found, it will default to the first available action
return 0;
}
function onActionEvent(action, state) {
if (!active) {
return;
}
if (state < THRESHOLD) {
if (action == findAction("YAW_LEFT") || action == findAction("YAW_RIGHT")) {
yawTimer = CAMERA_UPDATE_TIME;
} else if (action == findAction("PITCH_UP") || action == findAction("PITCH_DOWN")) {
pitchTimer = CAMERA_UPDATE_TIME;
}
return;
}
switch (action) {
case findAction("LONGITUDINAL_BACKWARD"):
var direction = {x: 0.0, y: 0.0, z:1.0};
direction = Vec3.multiply(Vec3.normalize(direction), shifted ? SHIFT_MAG * MOVE_DISTANCE : MOVE_DISTANCE);
velocity = Vec3.sum(velocity, direction);
break;
case findAction("LONGITUDINAL_FORWARD"):
var direction = {x: 0.0, y: 0.0, z:-1.0};
direction = Vec3.multiply(Vec3.normalize(direction), shifted ? SHIFT_MAG * MOVE_DISTANCE : MOVE_DISTANCE);
velocity = Vec3.sum(velocity, direction);
break;
case findAction("LATERAL_LEFT"):
var direction = {x:-1.0, y: 0.0, z: 0.0}
direction = Vec3.multiply(Vec3.normalize(direction), shifted ? SHIFT_MAG * MOVE_DISTANCE : MOVE_DISTANCE);
velocity = Vec3.sum(velocity, direction);
break;
case findAction("LATERAL_RIGHT"):
var direction = {x:1.0, y: 0.0, z: 0.0};
direction = Vec3.multiply(Vec3.normalize(direction), shifted ? SHIFT_MAG * MOVE_DISTANCE : MOVE_DISTANCE);
velocity = Vec3.sum(velocity, direction);
break;
case findAction("VERTICAL_DOWN"):
var direction = {x: 0.0, y: -1.0, z: 0.0};
direction = Vec3.multiply(Vec3.normalize(direction), shifted ? SHIFT_MAG * MOVE_DISTANCE : MOVE_DISTANCE);
velocity = Vec3.sum(velocity, direction);
break;
case findAction("VERTICAL_UP"):
var direction = {x: 0.0, y: 1.0, z: 0.0};
direction = Vec3.multiply(Vec3.normalize(direction), shifted ? SHIFT_MAG * MOVE_DISTANCE : MOVE_DISTANCE);
velocity = Vec3.sum(velocity, direction);
break;
case findAction("YAW_LEFT"):
if (yawTimer < 0.0 && Menu.isOptionChecked("Enable VR Mode")) {
yawChange = yawChange + (shifted ? SHIFT_MAG * VR_YAW_INCREMENT : VR_YAW_INCREMENT);
yawTimer = CAMERA_UPDATE_TIME;
} else if (!Menu.isOptionChecked("Enable VR Mode")) {
yawChange = yawChange + (shifted ? SHIFT_MAG * YAW_INCREMENT : YAW_INCREMENT);
}
break;
case findAction("YAW_RIGHT"):
if (yawTimer < 0.0 && Menu.isOptionChecked("Enable VR Mode")) {
yawChange = yawChange - (shifted ? SHIFT_MAG * VR_YAW_INCREMENT : VR_YAW_INCREMENT);
yawTimer = CAMERA_UPDATE_TIME;
} else if (!Menu.isOptionChecked("Enable VR Mode")) {
yawChange = yawChange - (shifted ? SHIFT_MAG * YAW_INCREMENT : YAW_INCREMENT);
}
break;
case findAction("PITCH_DOWN"):
if (!Menu.isOptionChecked("Enable VR Mode")) {
pitchChange = pitchChange - (shifted ? SHIFT_MAG * PITCH_INCREMENT : PITCH_INCREMENT);
}
break;
case findAction("PITCH_UP"):
if (!Menu.isOptionChecked("Enable VR Mode")) {
pitchChange = pitchChange + (shifted ? SHIFT_MAG * PITCH_INCREMENT : PITCH_INCREMENT);
}
break;
case findAction("SHIFT"): // speed up
if (shiftTimer < 0.0) {
shifted = !shifted;
shiftTimer = SHIFT_UPDATE_TIME;
}
break;
case findAction("ACTION1"): // start/end warp
if (warpTimer < 0.0) {
warpActive = !warpActive;
if (!warpActive) {
finishWarp();
}
warpTimer = WARP_UPDATE_TIME;
}
break;
case findAction("ACTION2"): // cancel warp
warpActive = false;
Overlays.editOverlay(warpSphere, {
visible: false,
});
Overlays.editOverlay(warpLine, {
visible: false,
});
default:
break;
}
}
function update(dt) {
if (prevVRMode != Menu.isOptionChecked("Enable VR Mode")) {
active = Menu.isOptionChecked("Enable VR Mode");
prevVRMode = Menu.isOptionChecked("Enable VR Mode");
}
if (yawTimer >= 0.0) {
yawTimer = yawTimer - dt;
}
if (shiftTimer >= 0.0) {
shiftTimer = shiftTimer - dt;
}
if (warpTimer >= 0.0) {
warpTimer = warpTimer - dt;
}
if (warpActive) {
updateWarp();
}
if (active) {
Controller.captureActionEvents();
MyAvatar.bodyYaw = MyAvatar.bodyYaw + yawChange;
MyAvatar.headPitch = Math.max(-180, Math.min(180, MyAvatar.headPitch + pitchChange));
yawChange = 0;
pitchChange = 0;
MyAvatar.motorVelocity = velocity;
MyAvatar.motorTimescale = 0.0;
velocity = { x: 0, y: 0, z: 0 };
} else {
Controller.releaseActionEvents();
yawChange = 0;
pitchChange = 0;
MyAvatar.motorVelocity = {x:0.0, y:0.0, z:0.0}
MyAvatar.motorTimescale = VERY_LONG_TIME;
}
}
function updateWarp() {
var look = Quat.getFront(Camera.getOrientation());
var pitch = Math.asin(look.y);
// Get relative to looking straight down
pitch += Math.PI / 2;
// Scale up
pitch *= 2;
var distance = pitch * pitch * pitch;
var warpDirection = Vec3.normalize({ x: look.x, y: 0, z: look.z });
warpPosition = Vec3.multiply(warpDirection, distance);
warpPosition = Vec3.sum(MyAvatar.position, warpPosition);
// Commented out until ray picking can be fixed
// var pickRay = {
// origin: Vec3.sum(warpPosition, WARP_PICK_OFFSET),
// direction: { x: 0, y: -1, z: 0 }
// };
// var intersection = Entities.findRayIntersection(pickRay);
// if (intersection.intersects && intersection.distance < WARP_PICK_MAX_DISTANCE) {
// // Warp 1 meter above the object - this is an approximation
// // TODO Get the actual offset to the Avatar's feet and plant them to
// // the object.
// warpPosition = Vec3.sum(intersection.intersection, { x: 0, y: 1, z:0 });
// }
// Adjust overlays to match warp position
Overlays.editOverlay(warpSphere, {
position: warpPosition,
visible: true,
});
Overlays.editOverlay(warpLine, {
start: warpPosition,
end: Vec3.sum(warpPosition, { x: 0, y: WARP_LINE_HEIGHT, z: 0 }),
visible: true,
});
}
function finishWarp() {
Overlays.editOverlay(warpSphere, {
visible: false,
});
Overlays.editOverlay(warpLine, {
visible: false,
});
MyAvatar.position = warpPosition;
}
function setUp() {
Controller.keyPressEvent.connect(onKeyPressEvent);
Controller.actionEvent.connect(onActionEvent);
Script.update.connect(update);
}
function tearDown() {
Controller.releaseActionEvents();
MyAvatar.motorVelocity = {x:0.0, y:0.0, z:0.0}
MyAvatar.motorTimescale = VERY_LONG_TIME;
}
setUp();
Script.scriptEnding.connect(tearDown);
}());

View file

@ -13,4 +13,5 @@ Script.load("progress.js");
Script.load("lobby.js");
Script.load("notifications.js");
Script.load("controllers/oculus/goTo.js");
Script.load("hmdControls.js");
//Script.load("scripts.js"); // Not created yet

View file

@ -932,6 +932,7 @@
</script>
</head>
<body class="properties" onload='loaded();'>
<div id="properties-list">
<div id="type" class="property">
@ -939,9 +940,12 @@
<label>Type: </label><span id="property-type"></span>
</div>
</div>
<div class="property">
<div id="id" class="property">
<span class="label" style="float: left; margin-right: 6px">
<label>ID: <label>
</span>
<div class="value">
<label id="property-id" class="selectable"></label>
<span id="property-id" class="selectable"></span>
</div>
</div>
<div class="property">
@ -951,17 +955,6 @@
</div>
</div>
<div class="property">
<div class="label">Hyperlink</div>
<div class="input-area">Href<br></div>
<div class="value">
<input id="property-hyperlink-href" class="url"></input>
</div>
<div class="input-area">Description<br></div> <div class="value">
<input id="property-hyperlink-description" class="url"></input>
</div>
</div>
<div class="property">
<span class="label">Locked</span>
<span class="value">
@ -976,6 +969,36 @@
</span>
</div>
<div class="property">
<div class="label">User Data</div>
<div class="value">
<textarea id="property-user-data"></textarea>
</div>
</div>
<div class="sub-section-header">
<label>Hyperlink</label>
</div>
<div class="property">
<div class="label">Href</div>
<div class="value">
<input id="property-hyperlink-href" class="url"></input>
</div>
</div>
<div class="property">
<div class="label">Description</div>
<div class="value">
<input id="property-hyperlink-description" class="url"></input>
</div>
</div>
<div class="section-header">
<label>Spacial Properites</label>
</div>
<div class="property">
<div class="label">Position</div>
<div class="value">
@ -1043,6 +1066,11 @@
</div>
</div>
<div class="section-header">
<label>Physical Properites</label>
</div>
<div class="property">
<div class="label">Linear Velocity</div>
<div class="value">
@ -1109,6 +1137,21 @@
</div>
</div>
<div id="color-section" class="property">
<div class="label">Color</div>
<div class="value">
<div id="property-color" class='color-picker'></div>
<div class="input-area">R <input class="coord" type='number' id="property-color-red"></input></div>
<div class="input-area">G <input class="coord" type='number' id="property-color-green"></input></div>
<div class="input-area">B <input class="coord" type='number' id="property-color-blue"></input></div>
</div>
</div>
<div class="section-header">
<label>Behavior</label>
</div>
<div class="property">
<span class="label">Ignore For Collisions</span>
<span class="value">
@ -1144,74 +1187,9 @@
</div>
</div>
<div class="property">
<div class="label">User Data</div>
<div class="value">
<textarea id="property-user-data"></textarea>
</div>
</div>
<div id="color-section" class="property">
<div class="label">Color</div>
<div class="value">
<div id="property-color" class='color-picker'></div>
<div class="input-area">R <input class="coord" type='number' id="property-color-red"></input></div>
<div class="input-area">G <input class="coord" type='number' id="property-color-green"></input></div>
<div class="input-area">B <input class="coord" type='number' id="property-color-blue"></input></div>
</div>
</div>
<div class="web-section property">
<div class="label">Source URL</div>
<div class="value">
<input type="text" id="property-web-source-url" class="url"></input>
</div>
</div>
<div class="particle-section property">
<div class="label">Max Particles</div>
<div class="value">
<input type='number' id="property-particle-maxparticles" min="0" max="2048" step="1"></input>
</div>
</div>
<div class="particle-section property">
<div class="label">Particle Life Span</div>
<div class="value">
<input type='number' id="property-particle-lifespan" min="0" step="0.1"></input>
</div>
</div>
<div class="particle-section property">
<div class="label">Particle Emission Rate</div>
<div class="value">
<input type='number' id="property-particle-emit-rate" min="0" step="0.5"></input>
</div>
</div>
<div class="particle-section property">
<div class="label">Particle Emission Direction</div>
<div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-particle-emit-direction-x"></input></div>
<div class="input-area">Y <input class="coord" type='number' id="property-particle-emit-direction-y"></input></div>
<div class="input-area">Z <input class="coord" type='number' id="property-particle-emit-direction-z"></input></div>
</div>
</div>
<div class="particle-section property">
<div class="label">Particle Emission Strength</div>
<div class="value">
<input type='number' id="property-particle-emit-strength" min="0" step="0.1"></input>
</div>
</div>
<div class="particle-section property">
<div class="label">Particle Local Gravity</div>
<div class="value">
<input class="coord" type='number' id="property-particle-localgravity" step="0.05"></input>
</div>
</div>
<div class="particle-section property">
<div class="label">Particle Radius</div>
<div class="value">
<input class="coord" type='number' id="property-particle-radius" min="0" step="0.005"></input>
</div>
<div class="section-header model-section zone-section">
<label>Model</label>
</div>
<div class="model-section property">
@ -1220,6 +1198,7 @@
<input type="text" id="property-model-url" class="url"></input>
</div>
</div>
<div class="model-section zone-section property">
<div class="label">Shape Type</div>
<div class="value">
@ -1280,8 +1259,75 @@
</div>
</div>
<div class="section-header web-section">
<label>Web</label>
</div>
<div class="web-section property">
<div class="label">Source URL</div>
<div class="value">
<input type="text" id="property-web-source-url" class="url"></input>
</div>
</div>
<div class="section-header particle-section">
<label>Particle</label>
</div>
<div class="particle-section property">
<div class="label">Max Particles</div>
<div class="value">
<input type='number' id="property-particle-maxparticles" min="0" max="2048" step="1"></input>
</div>
</div>
<div class="particle-section property">
<div class="label">Particle Life Span</div>
<div class="value">
<input type='number' id="property-particle-lifespan" min="0" step="0.1"></input>
</div>
</div>
<div class="particle-section property">
<div class="label">Particle Emission Rate</div>
<div class="value">
<input type='number' id="property-particle-emit-rate" min="0" step="0.5"></input>
</div>
</div>
<div class="particle-section property">
<div class="label">Particle Emission Direction</div>
<div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-particle-emit-direction-x"></input></div>
<div class="input-area">Y <input class="coord" type='number' id="property-particle-emit-direction-y"></input></div>
<div class="input-area">Z <input class="coord" type='number' id="property-particle-emit-direction-z"></input></div>
</div>
</div>
<div class="particle-section property">
<div class="label">Particle Emission Strength</div>
<div class="value">
<input type='number' id="property-particle-emit-strength" min="0" step="0.1"></input>
</div>
</div>
<div class="particle-section property">
<div class="label">Particle Local Gravity</div>
<div class="value">
<input class="coord" type='number' id="property-particle-localgravity" step="0.05"></input>
</div>
</div>
<div class="particle-section property">
<div class="label">Particle Radius</div>
<div class="value">
<input class="coord" type='number' id="property-particle-radius" min="0" step="0.005"></input>
</div>
</div>
<div class="section-header text-section">
<label>Text</label>
</div>
<div class="text-section property">
<div class="label">Text</div>
<div class="label">Text Content</div>
<div class="value">
<input type="text" id="property-text-text"></input>
</div>
@ -1311,6 +1357,11 @@
</div>
</div>
<div class="section-header light-section">
<label>Light</label>
</div>
<div class="light-section property">
<span class="label">Spot Light</span>
<span class="value">
@ -1345,6 +1396,11 @@
</div>
</div>
<div class="section-header zone-section">
<label>Zone</label>
</div>
<div class="zone-section property">
<span class="label">Stage Sun Model Enabled</span>
<span class="value">
@ -1431,6 +1487,12 @@
</select>
</div>
</div>
<div class="sub-section-header zone-section skybox-section">
<label>Skybox</label>
</div>
<div class="zone-section skybox-section property">
<div class="label">Skybox Color</div>
<div class="value">
@ -1446,6 +1508,12 @@
<input type="text" id="property-zone-skybox-url" class="url"></input>
</div>
</div>
<div class="sub-section-header zone-section atmosphere-section">
<label>Atmosphere</label>
</div>
<div class="zone-section atmosphere-section property">
<div class="label">Atmosphere Center</div>
<div class="value">
@ -1495,8 +1563,6 @@
<input type='checkbox' id="property-zone-atmosphere-has-stars">
</span>
</div>
</div>
</body>
</html>

View file

@ -8,7 +8,7 @@ body {
background-color: rgb(76, 76, 76);
color: rgb(204, 204, 204);
font-family: Arial;
font-size: 8.25pt;
font-size: 9.0pt;
-webkit-touch-callout: none;
-webkit-user-select: none;
@ -44,20 +44,31 @@ body {
border: 1.5pt solid black;
}
.section-header {
.section-header, .sub-section-header {
background: #AAA;
border-bottom: 0.75pt solid #CCC;
background-color: #333333;
color: #999;
padding: 3pt;
padding-top: 6pt;
}
.section-header label {
.section-header label, .sub-section-header label {
font-weight: bold;
font-size: 11pt;
}
.sub-section-header {
padding-top: 4px;
}
.sub-section-header label {
font-size: 9pt;
}
.multi-property-section {
}
.property-section {
display: block;
margin: 10 10;
@ -132,7 +143,7 @@ input.no-spin::-webkit-inner-spin-button {
table#entity-table {
border-collapse: collapse;
font-family: Sans-Serif;
font-size: 7.5pt;
font-size: 9pt;
width: 100%;
}
@ -156,7 +167,7 @@ table#entity-table {
}
#entity-table td {
font-size: 8.25pt;
font-size: 9.0pt;
border: 0pt black solid;
word-wrap: nowrap;
white-space: nowrap;
@ -176,29 +187,29 @@ th#entity-type {
div.input-area {
display: inline-block;
font-size: 7.5pt;
font-size: 9pt;
}
input {
}
#type {
font-size: 10.5pt;
#type, #id {
font-size: 9.0pt;
}
#type label {
#type label, #id label {
color: rgb(150, 150, 150);
}
input, textarea {
background-color: rgb(102, 102, 102);
color: rgb(204, 204, 204);
background-color: rgb(63, 63, 63);
color: rgb(255, 255, 255);
border: none;
font-size: 7.5pt;
font-size: 9pt;
}
input:disabled, textarea:disabled {
background-color: rgb(102, 102, 102);
background-color: rgb(63, 63, 63);
color: rgb(160, 160, 160);
}
@ -224,7 +235,7 @@ input:disabled, textarea:disabled {
#properties-list .property {
padding: 4pt;
border-bottom: 0.75pt solid rgb(63, 63, 63);
min-height: 1em;
min-height: 12pt;
}
@ -245,7 +256,6 @@ table#properties-list {
font-weight: bold;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
height: 1.2em;
}
@ -270,9 +280,7 @@ div.inner {
}
td {
vertical-align: top;
vertical-align: top;
}
#no-entities {

View file

@ -126,12 +126,12 @@ Tool.prototype = new Overlay2D;
Tool.IMAGE_HEIGHT = 50;
Tool.IMAGE_WIDTH = 50;
ToolBar = function(x, y, direction) {
ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPositionFunction) {
this.tools = new Array();
this.x = x;
this.y = y;
this.width = 0;
this.height = 0;
this.height = ToolBar.TITLE_BAR_HEIGHT;
this.back = this.back = Overlays.addOverlay("text", {
backgroundColor: { red: 255, green: 255, blue: 255 },
x: this.x,
@ -336,7 +336,7 @@ ToolBar = function(x, y, direction) {
return (that.x <= x) && (x <= (that.x + that.width)) &&
(that.y <= y) && (y <= (that.y + that.height));
}
that.hover = function (enable) {
that.hover = function (enable) { // Can be overriden or extended by clients.
that.isHovering = enable;
if (that.back) {
if (enable) {
@ -348,16 +348,36 @@ ToolBar = function(x, y, direction) {
});
}
};
that.windowDimensions = Controller.getViewportDimensions();
// Maybe fixme: Keeping the same percent of the window size isn't always the right thing.
// For example, maybe we want "keep the same percentage to whatever two edges are closest to the edge of screen".
// If we change that, the places to do so are onResizeViewport, save (maybe), and the initial move based on Settings, below.
that.onResizeViewport = function (newSize) { // Can be overridden or extended by clients.
var fractionX = that.x / that.windowDimensions.x;
var fractionY = that.y / that.windowDimensions.y;
that.windowDimensions = newSize || Controller.getViewportDimensions();
that.move(fractionX * that.windowDimensions.x, fractionY * that.windowDimensions.y);
};
if (optionalPersistenceKey) {
this.fractionKey = optionalPersistenceKey + '.fraction';
this.save = function () {
var screenSize = Controller.getViewportDimensions();
var fraction = {x: that.x / screenSize.x, y: that.y / screenSize.y};
Settings.setValue(this.fractionKey, JSON.stringify(fraction));
}
} else {
this.save = function () { }; // Called on move. Can be overriden or extended by clients.
}
// These are currently only doing that which is necessary for toolbar hover and toolbar drag.
// They have not yet been extended to tool hover/click/release, etc.
this.mousePressEvent = function (event) {
if (!that.contains(event)) {
if (Overlays.getOverlayAtPoint({ x: event.x, y: event.y }) == that.back) {
that.mightBeDragging = true;
that.dragOffsetX = that.x - event.x;
that.dragOffsetY = that.y - event.y;
} else {
that.mightBeDragging = false;
return;
}
that.mightBeDragging = true;
that.dragOffsetX = that.x - event.x;
that.dragOffsetY = that.y - event.y;
};
this.mouseMove = function (event) {
if (!that.mightBeDragging || !event.isLeftButton) {
@ -375,15 +395,19 @@ ToolBar = function(x, y, direction) {
}
that.move(that.dragOffsetX + event.x, that.dragOffsetY + event.y);
};
that.checkResize = function () { // Can be overriden or extended, but usually not. See onResizeViewport.
var currentWindowSize = Controller.getViewportDimensions();
if ((currentWindowSize.x !== that.windowDimensions.x) || (currentWindowSize.y !== that.windowDimensions.y)) {
that.onResizeViewport(currentWindowSize);
}
};
Controller.mousePressEvent.connect(this.mousePressEvent);
Controller.mouseMoveEvent.connect(this.mouseMove);
// Called on move. A different approach would be to have all this on the prototype,
// and let apps extend where needed. Ex. app defines its toolbar.move() to call this.__proto__.move and then save.
this.save = function () { };
Script.update.connect(that.checkResize);
// This compatability hack breaks the model, but makes converting existing scripts easier:
this.addOverlay = function (ignored, oldSchoolProperties) {
var properties = JSON.parse(JSON.stringify(oldSchoolProperties)); // a copy
if (that.numberOfTools() === 0) {
if ((that.numberOfTools() === 0) && (properties.x != undefined) && (properties.y != undefined)) {
that.move(properties.x, properties.y);
}
delete properties.x;
@ -392,7 +416,25 @@ ToolBar = function(x, y, direction) {
var id = that.tools[index].overlay();
return id;
}
if (this.fractionKey || optionalInitialPositionFunction) {
var savedFraction = JSON.parse(Settings.getValue(this.fractionKey) || '0'); // getValue can answer empty string
var screenSize = Controller.getViewportDimensions();
if (savedFraction) {
// If we have saved data, keep the toolbar at the same proportion of the screen width/height.
that.move(savedFraction.x * screenSize.x, savedFraction.y * screenSize.y);
} else if (!optionalInitialPositionFunction) {
print("No initPosition(screenSize, intializedToolbar) specified for ToolBar");
} else {
// Call the optionalInitialPositionFunctinon() AFTER the client has had a chance to set up.
var that = this;
Script.setTimeout(function () {
var position = optionalInitialPositionFunction(screenSize, that);
that.move(position.x, position.y);
}, 0);
}
}
}
ToolBar.SPACING = 4;
ToolBar.VERTICAL = 0;
ToolBar.HORIZONTAL = 1;
ToolBar.TITLE_BAR_HEIGHT = 10;

View file

@ -10,17 +10,16 @@
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include('lineRider.js')
var MAX_POINTS_PER_LINE = 30;
var LINE_LIFETIME = 60 * 5 //5 minute lifetime
var LINE_DIMENSIONS = 5;
var LIFETIME = 6000;
var colorPalette = [{
red: 236,
green: 208,
blue: 120
}, {
red: 217,
red: 214,
green: 91,
blue: 67
}, {
@ -40,15 +39,6 @@ var colorPalette = [{
var currentColorIndex = 0;
var currentColor = colorPalette[currentColorIndex];
if (hydraCheck() === true) {
HydraPaint();
} else {
MousePaint();
}
function cycleColor() {
currentColor = colorPalette[++currentColorIndex];
if (currentColorIndex === colorPalette.length - 1) {
@ -57,42 +47,17 @@ function cycleColor() {
}
function hydraCheck() {
var numberOfButtons = Controller.getNumberOfButtons();
var numberOfTriggers = Controller.getNumberOfTriggers();
var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
hydrasConnected = (numberOfButtons == 12 && numberOfTriggers == 2 && controllersPerTrigger == 2);
return hydrasConnected; //hydrasConnected;
}
//************ Mouse Paint **************************
MousePaint();
function MousePaint() {
var DRAWING_DISTANCE = 2;
var DRAWING_DISTANCE = 5;
var lines = [];
var deletedLines = [];
var isDrawing = false;
var path = [];
var lineRider = new LineRider();
lineRider.addStartHandler(function() {
var points = [];
//create points array from list of all points in path
path.forEach(function(point) {
points.push(point);
});
lineRider.setPath(points);
});
var LINE_WIDTH = 7;
var line;
var points = [];
var line, linePosition;
var BRUSH_SIZE = 0.02;
var BRUSH_SIZE = .05;
var brush = Entities.addEntity({
type: 'Sphere',
@ -110,51 +75,42 @@ function MousePaint() {
});
function newLine(point) {
function newLine(position) {
linePosition = position;
line = Entities.addEntity({
position: MyAvatar.position,
position: position,
type: "Line",
color: currentColor,
dimensions: {
x: 10,
y: 10,
z: 10
x: LINE_DIMENSIONS,
y: LINE_DIMENSIONS,
z: LINE_DIMENSIONS
},
linePoints: [],
lineWidth: LINE_WIDTH,
lifetime: LINE_LIFETIME
lifetime: LIFETIME
});
points = [];
if (point) {
points.push(point);
path.push(point);
}
lines.push(line);
}
function mouseMoveEvent(event) {
var worldPoint = computeWorldPoint(event);
Entities.editEntity(brush, {
position: worldPoint
});
if (!isDrawing) {
return;
}
var pickRay = Camera.computePickRay(event.x, event.y);
var addVector = Vec3.multiply(Vec3.normalize(pickRay.direction), DRAWING_DISTANCE);
var point = Vec3.sum(Camera.getPosition(), addVector);
points.push(point);
path.push(point);
Entities.editEntity(line, {
linePoints: points
});
Entities.editEntity(brush, {
position: point
});
var localPoint = computeLocalPoint(event)
var success = Entities.appendPoint(line, localPoint);
if (points.length === MAX_POINTS_PER_LINE) {
//We need to start a new line!
newLine(point);
if (!success) {
newLine(worldPoint);
Entities.appendPoint(line, computeLocalPoint(event));
}
}
@ -171,17 +127,26 @@ function MousePaint() {
lines.push(restoredLine);
}
function computeWorldPoint(event) {
var pickRay = Camera.computePickRay(event.x, event.y);
var addVector = Vec3.multiply(Vec3.normalize(pickRay.direction), DRAWING_DISTANCE);
return Vec3.sum(Camera.getPosition(), addVector);
}
function computeLocalPoint(event) {
var localPoint = Vec3.subtract(computeWorldPoint(event), linePosition);
return localPoint;
}
function mousePressEvent(event) {
if(!event.isLeftButton) {
if (!event.isLeftButton) {
isDrawing = false;
return;
}
lineRider.mousePressEvent(event);
path = [];
newLine();
newLine(computeWorldPoint(event));
isDrawing = true;
}
function mouseReleaseEvent() {
@ -198,21 +163,21 @@ function MousePaint() {
if (event.text === "z") {
undoStroke();
}
if(event.text === "x") {
if (event.text === "x") {
redoStroke();
}
}
function cleanup() {
lines.forEach(function(line) {
Entities.deleteEntity(line);
// Entities.deleteEntity(line);
});
Entities.deleteEntity(brush);
lineRider.cleanup();
}
Controller.mousePressEvent.connect(mousePressEvent);
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
Controller.mouseMoveEvent.connect(mouseMoveEvent);
@ -222,266 +187,6 @@ function MousePaint() {
}
//*****************HYDRA PAINT *******************************************
function HydraPaint() {
var lineRider = new LineRider();
lineRider.addStartHandler(function() {
var points = [];
//create points array from list of all points in path
rightController.path.forEach(function(point) {
points.push(point);
});
lineRider.setPath(points);
});
var LEFT = 0;
var RIGHT = 1;
var currentTime = 0;
var minBrushSize = .02;
var maxBrushSize = .04
var minLineWidth = 5;
var maxLineWidth = 10;
var currentLineWidth = minLineWidth;
var MIN_PAINT_TRIGGER_THRESHOLD = .01;
var COLOR_CHANGE_TIME_FACTOR = 0.1;
var RIGHT_BUTTON_1 = 7
var RIGHT_BUTTON_2 = 8
var RIGHT_BUTTON_3 = 9;
var RIGHT_BUTTON_4 = 10
var LEFT_BUTTON_1 = 1;
var LEFT_BUTTON_2 = 2;
var LEFT_BUTTON_3 = 3;
var LEFT_BUTTON_4 = 4;
var STROKE_SMOOTH_FACTOR = 1;
var MIN_DRAW_DISTANCE = 0.2;
var MAX_DRAW_DISTANCE = 0.4;
function controller(side, undoButton, redoButton, cycleColorButton, startRideButton) {
this.triggerHeld = false;
this.triggerThreshold = 0.9;
this.side = side;
this.palm = 2 * side;
this.tip = 2 * side + 1;
this.trigger = side;
this.lines = [];
this.deletedLines = [] //just an array of properties objects
this.isPainting = false;
this.undoButton = undoButton;
this.undoButtonPressed = false;
this.prevUndoButtonPressed = false;
this.redoButton = redoButton;
this.redoButtonPressed = false;
this.prevRedoButtonPressed = false;
this.cycleColorButton = cycleColorButton;
this.cycleColorButtonPressed = false;
this.prevColorCycleButtonPressed = false;
this.startRideButton = startRideButton;
this.startRideButtonPressed = false;
this.prevStartRideButtonPressed = false;
this.strokeCount = 0;
this.currentBrushSize = minBrushSize;
this.points = [];
this.path = [];
this.brush = Entities.addEntity({
type: 'Sphere',
position: {
x: 0,
y: 0,
z: 0
},
color: currentColor,
dimensions: {
x: minBrushSize,
y: minBrushSize,
z: minBrushSize
}
});
this.newLine = function(point) {
this.line = Entities.addEntity({
position: MyAvatar.position,
type: "Line",
color: currentColor,
dimensions: {
x: 10,
y: 10,
z: 10
},
lineWidth: 5,
lifetime: LINE_LIFETIME
});
this.points = [];
if (point) {
this.points.push(point);
this.path.push(point);
}
this.lines.push(this.line);
}
this.update = function(deltaTime) {
this.updateControllerState();
this.avatarPalmOffset = Vec3.subtract(this.palmPosition, MyAvatar.position);
this.projectedForwardDistance = Vec3.dot(Quat.getFront(Camera.getOrientation()), this.avatarPalmOffset);
this.mappedPalmOffset = map(this.projectedForwardDistance, -.5, .5, MIN_DRAW_DISTANCE, MAX_DRAW_DISTANCE);
this.tipDirection = Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition));
this.offsetVector = Vec3.multiply(this.mappedPalmOffset, this.tipDirection);
this.drawPoint = Vec3.sum(this.palmPosition, this.offsetVector);
this.currentBrushSize = map(this.triggerValue, 0, 1, minBrushSize, maxBrushSize);
Entities.editEntity(this.brush, {
position: this.drawPoint,
dimensions: {
x: this.currentBrushSize,
y: this.currentBrushSize,
z: this.currentBrushSize
},
color: currentColor
});
if (this.triggerValue > MIN_PAINT_TRIGGER_THRESHOLD) {
if (!this.isPainting) {
this.isPainting = true;
this.newLine();
this.path = [];
}
if (this.strokeCount % STROKE_SMOOTH_FACTOR === 0) {
this.paint(this.drawPoint);
}
this.strokeCount++;
} else if (this.triggerValue < MIN_PAINT_TRIGGER_THRESHOLD && this.isPainting) {
this.releaseTrigger();
}
this.oldPalmPosition = this.palmPosition;
this.oldTipPosition = this.tipPosition;
}
this.releaseTrigger = function() {
this.isPainting = false;
}
this.updateControllerState = function() {
this.undoButtonPressed = Controller.isButtonPressed(this.undoButton);
this.redoButtonPressed = Controller.isButtonPressed(this.redoButton);
this.cycleColorButtonPressed = Controller.isButtonPressed(this.cycleColorButton);
this.startRideButtonPressed = Controller.isButtonPressed(this.startRideButton);
//This logic gives us button release
if (this.prevUndoButtonPressed === true && this.undoButtonPressed === false) {
//User released undo button, so undo
this.undoStroke();
}
if (this.prevRedoButtonPressed === true && this.redoButtonPressed === false) {
this.redoStroke();
}
if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) {
cycleColor();
Entities.editEntity(this.brush, {
color: currentColor
});
}
if (this.prevStartRideButtonPressed === true && this.startRideButtonPressed === false) {
lineRider.toggleRide();
}
this.prevRedoButtonPressed = this.redoButtonPressed;
this.prevUndoButtonPressed = this.undoButtonPressed;
this.prevCycleColorButtonPressed = this.cycleColorButtonPressed;
this.prevStartRideButtonPressed = this.startRideButtonPressed;
this.palmPosition = Controller.getSpatialControlPosition(this.palm);
this.tipPosition = Controller.getSpatialControlPosition(this.tip);
this.triggerValue = Controller.getTriggerValue(this.trigger);
}
this.undoStroke = function() {
var deletedLine = this.lines.pop();
var deletedLineProps = Entities.getEntityProperties(deletedLine);
this.deletedLines.push(deletedLineProps);
Entities.deleteEntity(deletedLine);
}
this.redoStroke = function() {
var restoredLine = Entities.addEntity(this.deletedLines.pop());
Entities.addEntity(restoredLine);
this.lines.push(restoredLine);
}
this.paint = function(point) {
currentLineWidth = map(this.triggerValue, 0, 1, minLineWidth, maxLineWidth);
this.points.push(point);
this.path.push(point);
Entities.editEntity(this.line, {
linePoints: this.points,
lineWidth: currentLineWidth,
});
if (this.points.length > MAX_POINTS_PER_LINE) {
this.newLine(point);
}
}
this.cleanup = function() {
Entities.deleteEntity(this.brush);
this.lines.forEach(function(line) {
Entities.deleteEntity(line);
});
}
}
function update(deltaTime) {
rightController.update(deltaTime);
leftController.update(deltaTime);
currentTime += deltaTime;
}
function cleanup() {
rightController.cleanup();
leftController.cleanup();
lineRider.cleanup();
}
function mousePressEvent(event) {
lineRider.mousePressEvent(event);
}
function vectorIsZero(v) {
return v.x === 0 && v.y === 0 && v.z === 0;
}
var rightController = new controller(RIGHT, RIGHT_BUTTON_3, RIGHT_BUTTON_4, RIGHT_BUTTON_1, RIGHT_BUTTON_2);
var leftController = new controller(LEFT, LEFT_BUTTON_3, LEFT_BUTTON_4, LEFT_BUTTON_1, LEFT_BUTTON_2);
Script.update.connect(update);
Script.scriptEnding.connect(cleanup);
Controller.mousePressEvent.connect(mousePressEvent);
}
function randFloat(low, high) {
return low + Math.random() * (high - low);
}

View file

@ -29,19 +29,13 @@ var buttonOnColor = {
};
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var screenSize = Controller.getViewportDimensions();
var userCanPoint = false;
Script.include(["libraries/toolBars.js"]);
const persistKey = "highfidelity.pointer.toolbar.position";
var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL);
toolBar.save = function () {
Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y]));
};
var old = JSON.parse(Settings.getValue(persistKey) || '0');
var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.pointer.toolbar", function (screenSize) {
return {x: screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING, y: screenSize.y - (BUTTON_SIZE + PADDING)},
});
var pointerButton = toolBar.addOverlay("image", {
x: old ? old[0] : screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING,
y: old ? old[1] : screenSize.y - (BUTTON_SIZE + PADDING),
width: BUTTON_SIZE,
height: BUTTON_SIZE,
imageURL: HIFI_PUBLIC_BUCKET + "images/laser.png",

View file

@ -9,48 +9,52 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
function hslToRgb(hslColor) {
var h = hslColor.hue;
var s = hslColor.sat;
var l = hslColor.light;
var r, g, b;
if (s == 0) {
r = g = b = l; // achromatic
} else {
var hue2rgb = function hue2rgb(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
map = function(value, min1, max1, min2, max2) {
return min2 + (max2 - min2) * ((value - min1) / (max1 - min1));
}
hslToRgb = function(hslColor) {
var h = hslColor.hue;
var s = hslColor.sat;
var l = hslColor.light;
var r, g, b;
if (s == 0) {
r = g = b = l; // achromatic
} else {
var hue2rgb = function hue2rgb(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
return {
red: Math.round(r * 255),
green: Math.round(g * 255),
blue: Math.round(b * 255)
};
return {
red: Math.round(r * 255),
green: Math.round(g * 255),
blue: Math.round(b * 255)
};
}
function map(value, min1, max1, min2, max2) {
return min2 + (max2 - min2) * ((value - min1) / (max1 - min1));
}
function randFloat(low, high) {
return low + Math.random() * (high - low);
randFloat = function(low, high) {
return low + Math.random() * (high - low);
}
function randInt(low, high) {
return Math.floor(randFloat(low, high));
randInt = function(low, high) {
return Math.floor(randFloat(low, high));
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 369 B

View file

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Layer_1"
x="0px"
y="0px"
viewBox="133.1 714.2 21.3 33.4"
enable-background="new 133.1 714.2 21.3 33.4"
xml:space="preserve"
inkscape:version="0.91 r13725"
sodipodi:docname="left-arrow.svg"><metadata
id="metadata13"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs11" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1440"
inkscape:window-height="775"
id="namedview9"
showgrid="false"
inkscape:zoom="14.131736"
inkscape:cx="12.772881"
inkscape:cy="16.700001"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g5" /><g
id="g3"
transform="matrix(-1,0,0,1,287.5,0)"><g
id="g5"><path
d="m 133.1,714.2 21.3,16.7 -21.3,16.7 0,-33.4 z"
id="path7"
inkscape:connector-curvature="0"
style="fill:#cccccc;fill-opacity:1" /></g></g></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 369 B

View file

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns:xl="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="133.1 714.2 21.3 33.4"
enable-background="new 133.1 714.2 21.3 33.4" xml:space="preserve">
<g>
<g>
<path fill="#7E7E7E" d="M133.1,714.2l21.3,16.7l-21.3,16.7V714.2z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 501 B

View file

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns:xl="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="133.1 714.2 21.3 33.4"
enable-background="new 133.1 714.2 21.3 33.4" xml:space="preserve">
<g>
<g>
<path fill="#FF5353" d="M133.1,714.2l21.3,16.7l-21.3,16.7V714.2z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 501 B

View file

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns:xl="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="225.8 714.2 326.5 512"
enable-background="new 225.8 714.2 326.5 512" xml:space="preserve">
<g>
<g>
<path fill="#FF5353" d="M552.4,1226.2l-326.5-256l326.5-256V1226.2z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 503 B

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns:xl="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="133.1 714.2 21.3 33.4"
enable-background="new 133.1 714.2 21.3 33.4" xml:space="preserve">
<g>
<g>
<path fill="#CCCCCC" d="M133.1,714.2l21.3,16.7l-21.3,16.7V714.2z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 507 B

View file

Before

Width:  |  Height:  |  Size: 501 B

After

Width:  |  Height:  |  Size: 501 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 B

View file

@ -1,3 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="344 454 26 74" width="26pt" height="74pt"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>2015-06-12 18:23Z</dc:date><!-- Produced by OmniGraffle Professional 5.4.4 --></metadata><defs></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><title>Canvas 1</title><rect fill="white" width="1728" height="1466"/><g><title> Navi Bar</title><line x1="356.58927" y1="466.42861" x2="356.58927" y2="515.4286" stroke="#b3b3b3" stroke-linecap="butt" stroke-linejoin="miter" stroke-width="3"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 778 B

View file

@ -46,10 +46,40 @@ DialogContainer {
property int inputAreaHeight: 56.0 * root.scale // Height of the background's input area
property int inputAreaStep: (height - inputAreaHeight) / 2
MouseArea {
// Drag the icon
width: parent.height
height: parent.height
x: 0
y: 0
drag {
target: root
minimumX: -parent.inputAreaStep
minimumY: -parent.inputAreaStep
maximumX: root.parent ? root.maximumX : 0
maximumY: root.parent ? root.maximumY + parent.inputAreaStep : 0
}
}
MouseArea {
// Drag the input rectangle
width: parent.width - parent.height
height: parent.inputAreaHeight
x: parent.height
y: parent.inputAreaStep
drag {
target: root
minimumX: -parent.inputAreaStep
minimumY: -parent.inputAreaStep
maximumX: root.parent ? root.maximumX : 0
maximumY: root.parent ? root.maximumY + parent.inputAreaStep : 0
}
}
Image {
id: backArrow
source: addressBarDialog.backEnabled ? "../images/left-arrow.svg" : "../images/redarrow_reversed.svg"
source: addressBarDialog.backEnabled ? "../images/left-arrow.svg" : "../images/left-arrow-disabled.svg"
anchors {
fill: parent
@ -71,7 +101,7 @@ DialogContainer {
Image {
id: forwardArrow
source: addressBarDialog.forwardEnabled ? "../images/darkgreyarrow.svg" : "../images/redarrow.svg"
source: addressBarDialog.forwardEnabled ? "../images/right-arrow.svg" : "../images/right-arrow-disabled.svg"
anchors {
fill: parent
@ -111,38 +141,7 @@ DialogContainer {
addressBarDialog.loadAddress(addressLine.text)
}
}
MouseArea {
// Drag the icon
width: parent.height
height: parent.height
x: 0
y: 0
drag {
target: root
minimumX: -parent.inputAreaStep
minimumY: -parent.inputAreaStep
maximumX: root.parent ? root.maximumX : 0
maximumY: root.parent ? root.maximumY + parent.inputAreaStep : 0
}
}
// Add this code to make text bar draggable
/*
MouseArea {
// Drag the input rectangle
width: parent.width - parent.height
height: parent.inputAreaHeight
x: parent.height
y: parent.inputAreaStep
drag {
target: root
minimumX: -parent.inputAreaStep
minimumY: -parent.inputAreaStep
maximumX: root.parent ? root.maximumX : 0
maximumY: root.parent ? root.maximumY + parent.inputAreaStep : 0
}
}*/
}
}

View file

@ -12,11 +12,6 @@ Item {
implicitWidth: row.width
anchors.horizontalCenter: parent.horizontalCenter
readonly property int sTATS_GENERAL_MIN_WIDTH: 165
readonly property int sTATS_PING_MIN_WIDTH: 190
readonly property int sTATS_GEO_MIN_WIDTH: 240
readonly property int sTATS_OCTREE_MIN_WIDTH: 410
readonly property int fontSize: 12
readonly property string fontColor: "white"
readonly property string bgColor: "#99333333"
@ -37,7 +32,6 @@ Item {
Column {
id: generalCol
spacing: 4; x: 4; y: 4;
width: sTATS_GENERAL_MIN_WIDTH
Text {
color: root.fontColor;
font.pixelSize: root.fontSize
@ -78,7 +72,6 @@ Item {
Column {
id: pingCol
spacing: 4; x: 4; y: 4;
width: sTATS_PING_MIN_WIDTH
Text {
color: root.fontColor
font.pixelSize: root.fontSize
@ -114,7 +107,6 @@ Item {
Column {
id: geoCol
spacing: 4; x: 4; y: 4;
width: sTATS_GEO_MIN_WIDTH
Text {
color: root.fontColor;
font.pixelSize: root.fontSize
@ -157,7 +149,6 @@ Item {
Column {
id: octreeCol
spacing: 4; x: 4; y: 4;
width: sTATS_OCTREE_MIN_WIDTH
Text {
color: root.fontColor;
font.pixelSize: root.fontSize

View file

@ -984,7 +984,7 @@ void Application::paintGL() {
glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo));
glBlitFramebuffer(0, 0, _renderResolution.x, _renderResolution.y,
0, 0, _glWidget->getDeviceSize().width(), _glWidget->getDeviceSize().height(),
GL_COLOR_BUFFER_BIT, GL_NEAREST);
GL_COLOR_BUFFER_BIT, GL_LINEAR);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
_compositor.displayOverlayTexture(&renderArgs);
@ -1063,9 +1063,7 @@ void Application::resizeGL() {
auto offscreenUi = DependencyManager::get<OffscreenUi>();
auto canvasSize = _glWidget->size();
if (canvasSize != offscreenUi->getWindow()->size()) {
offscreenUi->resize(canvasSize);
}
offscreenUi->resize(canvasSize);
_glWidget->makeCurrent();
}
@ -2453,16 +2451,18 @@ void Application::update(float deltaTime) {
// Transfer the user inputs to the driveKeys
_myAvatar->clearDriveKeys();
_myAvatar->setDriveKeys(FWD, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_FORWARD));
_myAvatar->setDriveKeys(BACK, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_BACKWARD));
_myAvatar->setDriveKeys(UP, _userInputMapper.getActionState(UserInputMapper::VERTICAL_UP));
_myAvatar->setDriveKeys(DOWN, _userInputMapper.getActionState(UserInputMapper::VERTICAL_DOWN));
_myAvatar->setDriveKeys(LEFT, _userInputMapper.getActionState(UserInputMapper::LATERAL_LEFT));
_myAvatar->setDriveKeys(RIGHT, _userInputMapper.getActionState(UserInputMapper::LATERAL_RIGHT));
_myAvatar->setDriveKeys(ROT_UP, _userInputMapper.getActionState(UserInputMapper::PITCH_UP));
_myAvatar->setDriveKeys(ROT_DOWN, _userInputMapper.getActionState(UserInputMapper::PITCH_DOWN));
_myAvatar->setDriveKeys(ROT_LEFT, _userInputMapper.getActionState(UserInputMapper::YAW_LEFT));
_myAvatar->setDriveKeys(ROT_RIGHT, _userInputMapper.getActionState(UserInputMapper::YAW_RIGHT));
if (!_controllerScriptingInterface.areActionsCaptured()) {
_myAvatar->setDriveKeys(FWD, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_FORWARD));
_myAvatar->setDriveKeys(BACK, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_BACKWARD));
_myAvatar->setDriveKeys(UP, _userInputMapper.getActionState(UserInputMapper::VERTICAL_UP));
_myAvatar->setDriveKeys(DOWN, _userInputMapper.getActionState(UserInputMapper::VERTICAL_DOWN));
_myAvatar->setDriveKeys(LEFT, _userInputMapper.getActionState(UserInputMapper::LATERAL_LEFT));
_myAvatar->setDriveKeys(RIGHT, _userInputMapper.getActionState(UserInputMapper::LATERAL_RIGHT));
_myAvatar->setDriveKeys(ROT_UP, _userInputMapper.getActionState(UserInputMapper::PITCH_UP));
_myAvatar->setDriveKeys(ROT_DOWN, _userInputMapper.getActionState(UserInputMapper::PITCH_DOWN));
_myAvatar->setDriveKeys(ROT_LEFT, _userInputMapper.getActionState(UserInputMapper::YAW_LEFT));
_myAvatar->setDriveKeys(ROT_RIGHT, _userInputMapper.getActionState(UserInputMapper::YAW_RIGHT));
}
_myAvatar->setDriveKeys(BOOM_IN, _userInputMapper.getActionState(UserInputMapper::BOOM_IN));
_myAvatar->setDriveKeys(BOOM_OUT, _userInputMapper.getActionState(UserInputMapper::BOOM_OUT));
@ -4748,3 +4748,10 @@ mat4 Application::getEyePose(int eye) const {
return mat4();
}
mat4 Application::getHeadPose() const {
if (isHMDMode()) {
return OculusManager::getHeadPose();
}
return mat4();
}

View file

@ -107,6 +107,7 @@ Avatar::Avatar() :
}
Avatar::~Avatar() {
assert(_motionState == nullptr);
for(auto attachment : _unusedAttachments) {
delete attachment;
}

View file

@ -114,6 +114,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
// DO NOT update or fade out uninitialized Avatars
++avatarIterator;
} else if (avatar->shouldDie()) {
removeAvatarMotionState(avatar);
_avatarFades.push_back(avatarIterator.value());
avatarIterator = _avatarHash.erase(avatarIterator);
} else {
@ -163,12 +164,13 @@ AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWe
}
// protected
void AvatarManager::removeAvatarMotionState(Avatar* avatar) {
AvatarMotionState* motionState= avatar->_motionState;
void AvatarManager::removeAvatarMotionState(AvatarSharedPointer avatar) {
auto rawPointer = std::static_pointer_cast<Avatar>(avatar);
AvatarMotionState* motionState= rawPointer->_motionState;
if (motionState) {
// clean up physics stuff
motionState->clearObjectBackPointer();
avatar->_motionState = nullptr;
rawPointer->_motionState = nullptr;
_avatarMotionStates.remove(motionState);
_motionStatesToAdd.remove(motionState);
_motionStatesToDelete.push_back(motionState);
@ -181,7 +183,7 @@ void AvatarManager::removeAvatar(const QUuid& sessionUUID) {
if (avatarIterator != _avatarHash.end()) {
std::shared_ptr<Avatar> avatar = std::dynamic_pointer_cast<Avatar>(avatarIterator.value());
if (avatar != _myAvatar && avatar->isInitialized()) {
removeAvatarMotionState(avatar.get());
removeAvatarMotionState(avatar);
_avatarFades.push_back(avatarIterator.value());
_avatarHash.erase(avatarIterator);
}
@ -197,7 +199,7 @@ void AvatarManager::clearOtherAvatars() {
// don't remove myAvatar or uninitialized avatars from the list
++avatarIterator;
} else {
removeAvatarMotionState(avatar.get());
removeAvatarMotionState(avatar);
_avatarFades.push_back(avatarIterator.value());
avatarIterator = _avatarHash.erase(avatarIterator);
}

View file

@ -73,7 +73,7 @@ private:
// virtual overrides
virtual AvatarSharedPointer newSharedAvatar();
virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer);
void removeAvatarMotionState(Avatar* avatar);
void removeAvatarMotionState(AvatarSharedPointer avatar);
virtual void removeAvatar(const QUuid& sessionUUID);
QVector<AvatarSharedPointer> _avatarFades;

View file

@ -124,18 +124,25 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
if (!(_isFaceTrackerConnected || billboard)) {
// Update eye saccades
const float AVERAGE_MICROSACCADE_INTERVAL = 0.50f;
const float AVERAGE_SACCADE_INTERVAL = 4.0f;
const float AVERAGE_MICROSACCADE_INTERVAL = 1.0f;
const float AVERAGE_SACCADE_INTERVAL = 6.0f;
const float MICROSACCADE_MAGNITUDE = 0.002f;
const float SACCADE_MAGNITUDE = 0.04f;
const float MAXIMUM_SACCADE_SPEED = 0.8f;
if (randFloat() < deltaTime / AVERAGE_MICROSACCADE_INTERVAL) {
_saccadeTarget = MICROSACCADE_MAGNITUDE * randVector();
} else if (randFloat() < deltaTime / AVERAGE_SACCADE_INTERVAL) {
_saccadeTarget = SACCADE_MAGNITUDE * randVector();
}
_saccade += (_saccadeTarget - _saccade) * 0.50f;
glm::vec3 saccadeDelta = (_saccadeTarget - _saccade) * 0.5f;
float speed = glm::length(saccadeDelta) / deltaTime;
if (speed > MAXIMUM_SACCADE_SPEED) {
saccadeDelta = saccadeDelta * MAXIMUM_SACCADE_SPEED / speed;
}
_saccade += saccadeDelta;
// Detect transition from talking to not; force blink after that and a delay
bool forceBlink = false;
const float TALKING_LOUDNESS = 100.0f;

View file

@ -76,7 +76,6 @@ const float MyAvatar::ZOOM_DEFAULT = 1.5f;
MyAvatar::MyAvatar() :
Avatar(),
_turningKeyPressTime(0.0f),
_gravity(0.0f, 0.0f, 0.0f),
_wasPushing(false),
_isPushing(false),
@ -1205,28 +1204,9 @@ bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& c
}
void MyAvatar::updateOrientation(float deltaTime) {
// Gather rotation information from keyboard
const float TIME_BETWEEN_HMD_TURNS = 0.5f;
const float HMD_TURN_DEGREES = 22.5f;
if (!qApp->isHMDMode()) {
// Smoothly rotate body with arrow keys if not in HMD
_bodyYawDelta -= _driveKeys[ROT_RIGHT] * YAW_SPEED * deltaTime;
_bodyYawDelta += _driveKeys[ROT_LEFT] * YAW_SPEED * deltaTime;
} else {
// Jump turns if in HMD
if (_driveKeys[ROT_RIGHT] || _driveKeys[ROT_LEFT]) {
if (_turningKeyPressTime == 0.0f) {
setOrientation(getOrientation() *
glm::quat(glm::radians(glm::vec3(0.f, _driveKeys[ROT_LEFT] ? HMD_TURN_DEGREES : -HMD_TURN_DEGREES, 0.0f))));
}
_turningKeyPressTime += deltaTime;
if (_turningKeyPressTime > TIME_BETWEEN_HMD_TURNS) {
_turningKeyPressTime = 0.0f;
}
} else {
_turningKeyPressTime = 0.0f;
}
}
// Smoothly rotate body with arrow keys
_bodyYawDelta -= _driveKeys[ROT_RIGHT] * YAW_SPEED * deltaTime;
_bodyYawDelta += _driveKeys[ROT_LEFT] * YAW_SPEED * deltaTime;
getHead()->setBasePitch(getHead()->getBasePitch() + (_driveKeys[ROT_UP] - _driveKeys[ROT_DOWN]) * PITCH_SPEED * deltaTime);
// update body orientation by movement inputs

View file

@ -210,7 +210,6 @@ private:
virtual void setFaceModelURL(const QUrl& faceModelURL);
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
float _turningKeyPressTime;
glm::vec3 _gravity;
float _driveKeys[MAX_DRIVE_KEYS];

View file

@ -17,7 +17,7 @@
#include "Joystick.h"
const float CONTROLLER_THRESHOLD = 0.25f;
const float CONTROLLER_THRESHOLD = 0.3f;
#ifdef HAVE_SDL2
const float MAX_AXIS = 32768.0f;
@ -173,9 +173,7 @@ void Joystick::assignDefaultInputMapping(UserInputMapper& mapper) {
// Button controls
mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(SDL_CONTROLLER_BUTTON_Y), DPAD_MOVE_SPEED);
mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(SDL_CONTROLLER_BUTTON_A), DPAD_MOVE_SPEED);
mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(SDL_CONTROLLER_BUTTON_X), JOYSTICK_YAW_SPEED);
mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(SDL_CONTROLLER_BUTTON_B), JOYSTICK_YAW_SPEED);
mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(SDL_CONTROLLER_BUTTON_X), DPAD_MOVE_SPEED);
// Zoom
mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(RIGHT_SHOULDER), BOOM_SPEED);
@ -203,13 +201,16 @@ void Joystick::assignDefaultInputMapping(UserInputMapper& mapper) {
// Button controls
mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(SDL_CONTROLLER_BUTTON_Y), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), DPAD_MOVE_SPEED/2.0f);
mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(SDL_CONTROLLER_BUTTON_A), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), DPAD_MOVE_SPEED/2.0f);
mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(SDL_CONTROLLER_BUTTON_X), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_YAW_SPEED/2.0f);
mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(SDL_CONTROLLER_BUTTON_B), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), JOYSTICK_YAW_SPEED/2.0f);
mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(SDL_CONTROLLER_BUTTON_X), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), DPAD_MOVE_SPEED/2.0f);
// Zoom
mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(RIGHT_SHOULDER), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), BOOM_SPEED/2.0f);
mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(LEFT_SHOULDER), makeInput(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), BOOM_SPEED/2.0f);
mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(SDL_CONTROLLER_BUTTON_LEFTSHOULDER));
mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(SDL_CONTROLLER_BUTTON_B));
mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(SDL_CONTROLLER_BUTTON_A));
#endif
}

View file

@ -276,7 +276,10 @@ void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) {
mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(MOUSE_AXIS_WHEEL_X_POS), BUTTON_YAW_SPEED);
#endif
mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(Qt::Key_Space));
mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(Qt::Key_R));
mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(Qt::Key_T));
}
float KeyboardMouseDevice::getButton(int channel) const {

View file

@ -11,10 +11,10 @@
//
#include "InterfaceConfig.h"
#include "OculusManager.h"
#include "ui/overlays/Text3DOverlay.h"
#include <CursorManager.h>
#include <QDesktopWidget>
#include <QGuiApplication>
#include <QScreen>
@ -37,7 +37,6 @@
#include "InterfaceLogging.h"
#include "Application.h"
template <typename Function>
void for_each_eye(Function function) {
for (ovrEyeType eye = ovrEyeType::ovrEye_Left;
@ -54,6 +53,71 @@ void for_each_eye(const ovrHmd & hmd, Function function) {
function(eye);
}
}
enum CalibrationState {
UNCALIBRATED,
WAITING_FOR_DELTA,
WAITING_FOR_ZERO,
WAITING_FOR_ZERO_HELD,
CALIBRATED
};
inline glm::mat4 toGlm(const ovrMatrix4f & om) {
return glm::transpose(glm::make_mat4(&om.M[0][0]));
}
inline glm::mat4 toGlm(const ovrFovPort & fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) {
return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true));
}
inline glm::vec3 toGlm(const ovrVector3f & ov) {
return glm::make_vec3(&ov.x);
}
inline glm::vec2 toGlm(const ovrVector2f & ov) {
return glm::make_vec2(&ov.x);
}
inline glm::ivec2 toGlm(const ovrVector2i & ov) {
return glm::ivec2(ov.x, ov.y);
}
inline glm::uvec2 toGlm(const ovrSizei & ov) {
return glm::uvec2(ov.w, ov.h);
}
inline glm::quat toGlm(const ovrQuatf & oq) {
return glm::make_quat(&oq.x);
}
inline glm::mat4 toGlm(const ovrPosef & op) {
glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation));
glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position));
return translation * orientation;
}
inline ovrMatrix4f ovrFromGlm(const glm::mat4 & m) {
ovrMatrix4f result;
glm::mat4 transposed(glm::transpose(m));
memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16);
return result;
}
inline ovrVector3f ovrFromGlm(const glm::vec3 & v) {
return{ v.x, v.y, v.z };
}
inline ovrVector2f ovrFromGlm(const glm::vec2 & v) {
return{ v.x, v.y };
}
inline ovrSizei ovrFromGlm(const glm::uvec2 & v) {
return{ (int)v.x, (int)v.y };
}
inline ovrQuatf ovrFromGlm(const glm::quat & q) {
return{ q.x, q.y, q.z, q.w };
}
#ifdef Q_OS_WIN
@ -171,50 +235,54 @@ private:
}
};
SwapFramebufferWrapper* OculusManager::_swapFbo{ nullptr };
MirrorFramebufferWrapper* OculusManager::_mirrorFbo{ nullptr };
ovrLayerEyeFov OculusManager::_sceneLayer;
static SwapFramebufferWrapper* _swapFbo{ nullptr };
static MirrorFramebufferWrapper* _mirrorFbo{ nullptr };
static ovrLayerEyeFov _sceneLayer;
#else
ovrTexture OculusManager::_eyeTextures[ovrEye_Count];
GlWindow* OculusManager::_outputWindow{ nullptr };
static ovrTexture _eyeTextures[ovrEye_Count];
static GlWindow* _outputWindow{ nullptr };
#endif
bool OculusManager::_isConnected = false;
ovrHmd OculusManager::_ovrHmd;
ovrFovPort OculusManager::_eyeFov[ovrEye_Count];
ovrVector3f OculusManager::_eyeOffset[ovrEye_Count];
ovrEyeRenderDesc OculusManager::_eyeRenderDesc[ovrEye_Count];
ovrSizei OculusManager::_renderTargetSize;
glm::mat4 OculusManager::_eyeProjection[ovrEye_Count];
unsigned int OculusManager::_frameIndex = 0;
bool OculusManager::_frameTimingActive = false;
Camera* OculusManager::_camera = NULL;
ovrEyeType OculusManager::_activeEye = ovrEye_Count;
bool OculusManager::_hswDismissed = false;
static bool _isConnected = false;
static ovrHmd _ovrHmd;
static ovrFovPort _eyeFov[ovrEye_Count];
static ovrVector3f _eyeOffset[ovrEye_Count];
static ovrEyeRenderDesc _eyeRenderDesc[ovrEye_Count];
static ovrSizei _renderTargetSize;
static glm::mat4 _eyeProjection[ovrEye_Count];
static unsigned int _frameIndex = 0;
static bool _frameTimingActive = false;
static Camera* _camera = NULL;
static ovrEyeType _activeEye = ovrEye_Count;
static bool _hswDismissed = false;
float OculusManager::CALIBRATION_DELTA_MINIMUM_LENGTH = 0.02f;
float OculusManager::CALIBRATION_DELTA_MINIMUM_ANGLE = 5.0f * RADIANS_PER_DEGREE;
float OculusManager::CALIBRATION_ZERO_MAXIMUM_LENGTH = 0.01f;
float OculusManager::CALIBRATION_ZERO_MAXIMUM_ANGLE = 2.0f * RADIANS_PER_DEGREE;
quint64 OculusManager::CALIBRATION_ZERO_HOLD_TIME = 3000000; // usec
float OculusManager::CALIBRATION_MESSAGE_DISTANCE = 2.5f;
OculusManager::CalibrationState OculusManager::_calibrationState;
glm::vec3 OculusManager::_calibrationPosition;
glm::quat OculusManager::_calibrationOrientation;
quint64 OculusManager::_calibrationStartTime;
int OculusManager::_calibrationMessage = 0;
glm::vec3 OculusManager::_eyePositions[ovrEye_Count];
static const float CALIBRATION_DELTA_MINIMUM_LENGTH = 0.02f;
static const float CALIBRATION_DELTA_MINIMUM_ANGLE = 5.0f * RADIANS_PER_DEGREE;
static const float CALIBRATION_ZERO_MAXIMUM_LENGTH = 0.01f;
static const float CALIBRATION_ZERO_MAXIMUM_ANGLE = 2.0f * RADIANS_PER_DEGREE;
static const quint64 CALIBRATION_ZERO_HOLD_TIME = 3000000; // usec
static const float CALIBRATION_MESSAGE_DISTANCE = 2.5f;
static CalibrationState _calibrationState;
static glm::vec3 _calibrationPosition;
static glm::quat _calibrationOrientation;
static quint64 _calibrationStartTime;
static int _calibrationMessage = 0;
static glm::vec3 _eyePositions[ovrEye_Count];
// TODO expose this as a developer toggle
bool OculusManager::_eyePerFrameMode = false;
ovrEyeType OculusManager::_lastEyeRendered = ovrEye_Count;
ovrSizei OculusManager::_recommendedTexSize = { 0, 0 };
float OculusManager::_offscreenRenderScale = 1.0;
static bool _eyePerFrameMode = false;
static ovrEyeType _lastEyeRendered = ovrEye_Count;
static ovrSizei _recommendedTexSize = { 0, 0 };
static float _offscreenRenderScale = 1.0;
static glm::mat4 _combinedProjection;
static ovrPosef _eyeRenderPoses[ovrEye_Count];
ovrRecti OculusManager::_eyeViewports[ovrEye_Count];
static ovrRecti _eyeViewports[ovrEye_Count];
static ovrVector3f _eyeOffsets[ovrEye_Count];
glm::vec3 OculusManager::getLeftEyePosition() { return _eyePositions[ovrEye_Left]; }
glm::vec3 OculusManager::getRightEyePosition() { return _eyePositions[ovrEye_Right]; }
void OculusManager::connect(QOpenGLContext* shareContext) {
qCDebug(interfaceapp) << "Oculus SDK" << OVR_VERSION_STRING;
@ -267,6 +335,8 @@ void OculusManager::connect(QOpenGLContext* shareContext) {
_eyeFov[eye] = _ovrHmd->DefaultEyeFov[eye];
_eyeProjection[eye] = toGlm(ovrMatrix4f_Projection(_eyeFov[eye],
DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded));
ovrEyeRenderDesc erd = ovrHmd_GetRenderDesc(_ovrHmd, eye, _eyeFov[eye]);
_eyeOffsets[eye] = erd.HmdToEyeViewOffset;
});
ovrFovPort combinedFov = _ovrHmd->MaxEyeFov[0];
combinedFov.RightTan = _ovrHmd->MaxEyeFov[1].RightTan;
@ -389,7 +459,7 @@ void OculusManager::disconnect() {
}
}
void OculusManager::positionCalibrationBillboard(Text3DOverlay* billboard) {
void positionCalibrationBillboard(Text3DOverlay* billboard) {
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
glm::quat headOrientation = myAvatar->getHeadOrientation();
headOrientation.x = 0;
@ -400,7 +470,7 @@ void OculusManager::positionCalibrationBillboard(Text3DOverlay* billboard) {
billboard->setRotation(headOrientation);
}
void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) {
void calibrate(const glm::vec3& position, const glm::quat& orientation) {
static QString instructionMessage = "Hold still to calibrate";
static QString progressMessage;
static Text3DOverlay* billboard;
@ -605,9 +675,8 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const
}
trackerPosition = bodyOrientation * trackerPosition;
static ovrVector3f eyeOffsets[2] = { { 0, 0, 0 }, { 0, 0, 0 } };
ovrPosef eyePoses[ovrEye_Count];
ovrHmd_GetEyePoses(_ovrHmd, _frameIndex, eyeOffsets, eyePoses, nullptr);
ovrHmd_GetEyePoses(_ovrHmd, _frameIndex, _eyeOffsets, eyePoses, nullptr);
#ifndef Q_OS_WIN
ovrHmd_BeginFrame(_ovrHmd, _frameIndex);
#endif
@ -721,7 +790,18 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const
ovrHmd_EndFrame(_ovrHmd, _eyeRenderPoses, _eyeTextures);
glCanvas->makeCurrent();
#endif
// in order to account account for changes in the pick ray caused by head movement
// we need to force a mouse move event on every frame (perhaps we could change this
// to based on the head moving a minimum distance from the last position in which we
// sent?)
{
QMouseEvent mouseEvent(QEvent::MouseMove, glCanvas->mapFromGlobal(QCursor::pos()),
Qt::NoButton, Qt::NoButton, 0);
qApp->mouseMoveEvent(&mouseEvent, 0);
}
}
@ -826,3 +906,8 @@ mat4 OculusManager::getEyeProjection(int eye) {
mat4 OculusManager::getEyePose(int eye) {
return toGlm(_eyeRenderPoses[eye]);
}
mat4 OculusManager::getHeadPose() {
ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds());
return toGlm(ts.HeadPose.ThePose);
}

View file

@ -13,8 +13,6 @@
#ifndef hifi_OculusManager_h
#define hifi_OculusManager_h
#include <OVR_CAPI.h>
#include <ProgramObject.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
@ -23,17 +21,7 @@
#include "RenderArgs.h"
class QOpenGLContext;
class Camera;
class GlWindow;
class PalmData;
class Text3DOverlay;
#ifdef Q_OS_WIN
struct SwapFramebufferWrapper;
struct MirrorFramebufferWrapper;
#endif
/// Handles interaction with the Oculus Rift.
class OculusManager {
@ -57,124 +45,14 @@ public:
static void overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal,
float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane);
static glm::vec3 getLeftEyePosition() { return _eyePositions[ovrEye_Left]; }
static glm::vec3 getRightEyePosition() { return _eyePositions[ovrEye_Right]; }
static glm::vec3 getLeftEyePosition();
static glm::vec3 getRightEyePosition();
static int getHMDScreen();
static glm::mat4 getEyeProjection(int eye);
static glm::mat4 getEyePose(int eye);
private:
static void initSdk();
static void shutdownSdk();
static bool _isConnected;
static glm::vec3 _eyePositions[ovrEye_Count];
static ovrHmd _ovrHmd;
static ovrFovPort _eyeFov[ovrEye_Count];
static ovrVector3f _eyeOffset[ovrEye_Count];
static glm::mat4 _eyeProjection[ovrEye_Count];
static ovrEyeRenderDesc _eyeRenderDesc[ovrEye_Count];
static ovrRecti _eyeViewports[ovrEye_Count];
static ovrSizei _renderTargetSize;
static unsigned int _frameIndex;
static bool _frameTimingActive;
static Camera* _camera;
static ovrEyeType _activeEye;
static bool _hswDismissed;
static void calibrate(const glm::vec3 position, const glm::quat orientation);
enum CalibrationState {
UNCALIBRATED,
WAITING_FOR_DELTA,
WAITING_FOR_ZERO,
WAITING_FOR_ZERO_HELD,
CALIBRATED
};
static void positionCalibrationBillboard(Text3DOverlay* message);
static float CALIBRATION_DELTA_MINIMUM_LENGTH;
static float CALIBRATION_DELTA_MINIMUM_ANGLE;
static float CALIBRATION_ZERO_MAXIMUM_LENGTH;
static float CALIBRATION_ZERO_MAXIMUM_ANGLE;
static quint64 CALIBRATION_ZERO_HOLD_TIME;
static float CALIBRATION_MESSAGE_DISTANCE;
static CalibrationState _calibrationState;
static glm::vec3 _calibrationPosition;
static glm::quat _calibrationOrientation;
static quint64 _calibrationStartTime;
static int _calibrationMessage;
// TODO drop this variable and use the existing 'Developer | Render | Scale Resolution' value
static ovrSizei _recommendedTexSize;
static float _offscreenRenderScale;
static bool _eyePerFrameMode;
static ovrEyeType _lastEyeRendered;
#ifdef Q_OS_WIN
static SwapFramebufferWrapper* _swapFbo;
static MirrorFramebufferWrapper* _mirrorFbo;
static ovrLayerEyeFov _sceneLayer;
#else
static ovrTexture _eyeTextures[ovrEye_Count];
static GlWindow* _outputWindow;
#endif
static glm::mat4 getHeadPose();
};
inline glm::mat4 toGlm(const ovrMatrix4f & om) {
return glm::transpose(glm::make_mat4(&om.M[0][0]));
}
inline glm::mat4 toGlm(const ovrFovPort & fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) {
return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true));
}
inline glm::vec3 toGlm(const ovrVector3f & ov) {
return glm::make_vec3(&ov.x);
}
inline glm::vec2 toGlm(const ovrVector2f & ov) {
return glm::make_vec2(&ov.x);
}
inline glm::ivec2 toGlm(const ovrVector2i & ov) {
return glm::ivec2(ov.x, ov.y);
}
inline glm::uvec2 toGlm(const ovrSizei & ov) {
return glm::uvec2(ov.w, ov.h);
}
inline glm::quat toGlm(const ovrQuatf & oq) {
return glm::make_quat(&oq.x);
}
inline glm::mat4 toGlm(const ovrPosef & op) {
glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation));
glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position));
return translation * orientation;
}
inline ovrMatrix4f ovrFromGlm(const glm::mat4 & m) {
ovrMatrix4f result;
glm::mat4 transposed(glm::transpose(m));
memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16);
return result;
}
inline ovrVector3f ovrFromGlm(const glm::vec3 & v) {
return{ v.x, v.y, v.z };
}
inline ovrVector2f ovrFromGlm(const glm::vec2 & v) {
return{ v.x, v.y };
}
inline ovrSizei ovrFromGlm(const glm::uvec2 & v) {
return{ (int)v.x, (int)v.y };
}
inline ovrQuatf ovrFromGlm(const glm::quat & q) {
return{ q.x, q.y, q.z, q.w };
}
#endif // hifi_OculusManager_h

View file

@ -36,6 +36,8 @@ const float NECK_X = 0.25f; // meters
const float NECK_Y = 0.3f; // meters
const float NECK_Z = 0.3f; // meters
const float CONTROLLER_THRESHOLD = 0.35f;
#ifdef __APPLE__
typedef int (*SixenseBaseFunction)();
typedef int (*SixenseTakeIntFunction)(int);
@ -326,6 +328,12 @@ void SixenseManager::update(float deltaTime) {
}
_controllersAtBase = (numControllersAtBase == 2);
}
for (auto axisState : _axisStateMap) {
if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) {
_axisStateMap[axisState.first] = 0.0f;
}
}
#endif // HAVE_SIXENSE
}
@ -724,6 +732,13 @@ void SixenseManager::assignDefaultInputMapping(UserInputMapper& mapper) {
mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(BUTTON_3, 1), BUTTON_MOVE_SPEED);
mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(BUTTON_1, 1), BUTTON_MOVE_SPEED);
mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_2, 0));
mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_2, 1));
mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(BUTTON_4, 0));
mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(BUTTON_4, 1));
}
float SixenseManager::getButton(int channel) const {

View file

@ -23,7 +23,7 @@
#ifdef Q_OS_WIN
static BOOL CALLBACK enumWindowsCallback(HWND hWnd, LPARAM lParam) {
const UINT TIMEOUT = 200; // ms
DWORD response;
DWORD_PTR response;
LRESULT result = SendMessageTimeout(hWnd, UWM_IDENTIFY_INSTANCES, 0, 0, SMTO_BLOCK | SMTO_ABORTIFHUNG, TIMEOUT, &response);
if (result == 0) { // Timeout; continue search.
return TRUE;

View file

@ -28,6 +28,7 @@ ControllerScriptingInterface::ControllerScriptingInterface() :
{
}
static int actionMetaTypeId = qRegisterMetaType<UserInputMapper::Action>();
static int inputChannelMetaTypeId = qRegisterMetaType<UserInputMapper::InputChannel>();
static int inputMetaTypeId = qRegisterMetaType<UserInputMapper::Input>();

View file

@ -79,6 +79,7 @@ public:
bool isMouseCaptured() const { return _mouseCaptured; }
bool isTouchCaptured() const { return _touchCaptured; }
bool isWheelCaptured() const { return _wheelCaptured; }
bool areActionsCaptured() const { return _actionsCaptured; }
bool isJoystickCaptured(int joystickIndex) const;
void updateInputControllers();
@ -123,6 +124,9 @@ public slots:
virtual void captureWheelEvents() { _wheelCaptured = true; }
virtual void releaseWheelEvents() { _wheelCaptured = false; }
virtual void captureActionEvents() { _actionsCaptured = true; }
virtual void releaseActionEvents() { _actionsCaptured = false; }
virtual void captureJoystick(int joystickIndex);
virtual void releaseJoystick(int joystickIndex);
@ -143,6 +147,7 @@ private:
bool _mouseCaptured;
bool _touchCaptured;
bool _wheelCaptured;
bool _actionsCaptured;
QMultiMap<int,KeyEvent> _capturedKeys;
QSet<int> _capturedJoysticks;

View file

@ -182,7 +182,8 @@ void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) {
updateTooltips();
vec2 canvasSize = qApp->getCanvasSize();
auto deviceSize = qApp->getDeviceSize();
glViewport(0, 0, deviceSize.width(), deviceSize.height());
//Handle fading and deactivation/activation of UI
gpu::Batch batch;
@ -204,6 +205,7 @@ void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) {
//draw the mouse pointer
// Get the mouse coordinates and convert to NDC [-1, 1]
vec2 canvasSize = qApp->getCanvasSize();
vec2 mousePosition = toNormalizedDeviceScale(vec2(qApp->getMouse()), canvasSize);
// Invert the Y axis
mousePosition.y *= -1.0f;
@ -334,12 +336,12 @@ void ApplicationCompositor::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& or
// Intersection UI overlay space
glm::vec3 worldSpaceDirection = overlayOrientation * overlaySpaceDirection;
glm::vec3 intersectionWithUi = glm::normalize(worldSpaceDirection) * _oculusUIRadius;
intersectionWithUi += overlayPosition;
glm::vec3 worldSpaceIntersection = (glm::normalize(worldSpaceDirection) * _oculusUIRadius) + overlayPosition;
glm::vec3 worldSpaceHeadPosition = (overlayOrientation * glm::vec3(qApp->getHeadPose()[3])) + overlayPosition;
// Intersection in world space
origin = overlayPosition;
direction = glm::normalize(intersectionWithUi - origin);
origin = worldSpaceHeadPosition;
direction = glm::normalize(worldSpaceIntersection - worldSpaceHeadPosition);
}
//Caculate the click location using one of the sixense controllers. Scale is not applied
@ -394,42 +396,13 @@ bool ApplicationCompositor::calculateRayUICollisionPoint(const glm::vec3& positi
void ApplicationCompositor::renderPointers(gpu::Batch& batch) {
if (qApp->isHMDMode() && !qApp->getLastMouseMoveWasSimulated() && !qApp->isMouseHidden()) {
//If we are in oculus, render reticle later
if (_lastMouseMove == 0) {
_lastMouseMove = usecTimestampNow();
}
QPoint position = QPoint(qApp->getTrueMouseX(), qApp->getTrueMouseY());
static const int MAX_IDLE_TIME = 3;
if (_reticlePosition[MOUSE] != position) {
_lastMouseMove = usecTimestampNow();
} else if (usecTimestampNow() - _lastMouseMove > MAX_IDLE_TIME * USECS_PER_SECOND) {
//float pitch = 0.0f, yaw = 0.0f, roll = 0.0f; // radians
//OculusManager::getEulerAngles(yaw, pitch, roll);
glm::quat orientation = qApp->getHeadOrientation(); // (glm::vec3(pitch, yaw, roll));
glm::vec3 result;
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
if (calculateRayUICollisionPoint(myAvatar->getEyePosition(),
myAvatar->getOrientation() * orientation * IDENTITY_FRONT,
result)) {
glm::vec3 lookAtDirection = glm::inverse(myAvatar->getOrientation()) * (result - myAvatar->getDefaultEyePosition());
glm::vec2 spericalPos = directionToSpherical(glm::normalize(lookAtDirection));
glm::vec2 screenPos = sphericalToScreen(spericalPos);
position = QPoint(screenPos.x, screenPos.y);
// FIXME
//glCanvas->cursor().setPos(glCanvas->mapToGlobal(position));
} else {
qDebug() << "No collision point";
}
}
_reticlePosition[MOUSE] = position;
_reticleActive[MOUSE] = true;
_magActive[MOUSE] = _magnifier;
_reticleActive[LEFT_CONTROLLER] = false;
_reticleActive[RIGHT_CONTROLLER] = false;
} else if (qApp->getLastMouseMoveWasSimulated() && Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) {
_lastMouseMove = 0;
//only render controller pointer if we aren't already rendering a mouse pointer
_reticleActive[MOUSE] = false;
_magActive[MOUSE] = false;

View file

@ -97,7 +97,6 @@ private:
QPoint _reticlePosition[NUMBER_OF_RETICLES];
bool _magActive[NUMBER_OF_RETICLES];
float _magSizeMult[NUMBER_OF_RETICLES];
quint64 _lastMouseMove{ 0 };
bool _magnifier{ true };
float _alpha{ 1.0f };

View file

@ -35,7 +35,8 @@ AvatarInputs* AvatarInputs::getInstance() {
AvatarInputs::AvatarInputs(QQuickItem* parent) : QQuickItem(parent) {
INSTANCE = this;
_mirrorZoomed = rearViewZoomLevel.get() != 0;
int zoomSetting = rearViewZoomLevel.get();
_mirrorZoomed = zoomSetting == 0;
}
#define AI_UPDATE(name, src) \
@ -50,7 +51,7 @@ AvatarInputs::AvatarInputs(QQuickItem* parent) : QQuickItem(parent) {
#define AI_UPDATE_FLOAT(name, src, epsilon) \
{ \
float val = src; \
if (abs(_##name - val) >= epsilon) { \
if (fabs(_##name - val) >= epsilon) { \
_##name = val; \
emit name##Changed(); \
} \

View file

@ -86,7 +86,7 @@ bool Stats::includeTimingRecord(const QString& name) {
#define STAT_UPDATE_FLOAT(name, src, epsilon) \
{ \
float val = src; \
if (abs(_##name - val) >= epsilon) { \
if (fabs(_##name - val) >= epsilon) { \
_##name = val; \
emit name##Changed(); \
} \

View file

@ -29,7 +29,7 @@ class Stats : public QQuickItem {
HIFI_QML_DECL
Q_PROPERTY(bool expanded READ isExpanded WRITE setExpanded NOTIFY expandedChanged)
Q_PROPERTY(bool timingExpanded READ isTimingExpanded NOTIFY timingExpandedChanged)
Q_PROPERTY(QString monospaceFont READ monospaceFont)
Q_PROPERTY(QString monospaceFont READ monospaceFont CONSTANT)
STATS_PROPERTY(int, serverCount, 0)
STATS_PROPERTY(int, framerate, 0)

View file

@ -8,9 +8,12 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "UserInputMapper.h"
#include <algorithm>
#include "Application.h"
#include "UserInputMapper.h"
// UserInputMapper Class
@ -207,6 +210,9 @@ void UserInputMapper::update(float deltaTime) {
// Scale all the channel step with the scale
for (auto i = 0; i < NUM_ACTIONS; i++) {
_actionStates[i] *= _actionScales[i];
if (_actionStates[i] > 0) {
emit Application::getInstance()->getControllerScriptingInterface()->actionEvent(i, _actionStates[i]);
}
}
}
@ -241,6 +247,9 @@ void UserInputMapper::assignDefaulActionScales() {
_actionScales[PITCH_UP] = 1.0f; // 1 degree per unit
_actionScales[BOOM_IN] = 1.0f; // 1m per unit
_actionScales[BOOM_OUT] = 1.0f; // 1m per unit
_actionStates[SHIFT] = 1.0f; // on
_actionStates[ACTION1] = 1.0f; // default
_actionStates[ACTION2] = 1.0f; // default
}
// This is only necessary as long as the actions are hardcoded
@ -258,4 +267,7 @@ void UserInputMapper::createActionNames() {
_actionNames[PITCH_UP] = "PITCH_UP";
_actionNames[BOOM_IN] = "BOOM_IN";
_actionNames[BOOM_OUT] = "BOOM_OUT";
_actionNames[SHIFT] = "SHIFT";
_actionNames[ACTION1] = "ACTION1";
_actionNames[ACTION2] = "ACTION2";
}

View file

@ -139,6 +139,11 @@ public:
BOOM_IN,
BOOM_OUT,
SHIFT,
ACTION1,
ACTION2,
NUM_ACTIONS,
};

View file

@ -107,7 +107,7 @@ void Circle3DOverlay::render(RenderArgs* args) {
Transform transform;
transform.setTranslation(getCenter());
transform.setRotation(getRotation());
transform.setScale(glm::vec3(getDimensions(), 0.01f));
transform.setScale(glm::vec3(getDimensions(), 0.01f) / 2.0f);
auto& batch = *args->_batch;

View file

@ -14,10 +14,12 @@
#include "Application.h"
#include "Text3DOverlay.h"
#include <RenderDeferredTask.h>
const xColor DEFAULT_BACKGROUND_COLOR = { 0, 0, 0 };
const float DEFAULT_BACKGROUND_ALPHA = 0.7f;
const float DEFAULT_MARGIN = 0.1f;
const int FIXED_FONT_SCALING_RATIO = FIXED_FONT_POINT_SIZE * 40.0f; // this is a ratio determined through experimentation
const int FIXED_FONT_SCALING_RATIO = FIXED_FONT_POINT_SIZE * 80.0f; // this is a ratio determined through experimentation
const float LINE_SCALE_RATIO = 1.2f;
Text3DOverlay::Text3DOverlay() :
@ -52,7 +54,7 @@ Text3DOverlay::~Text3DOverlay() {
xColor Text3DOverlay::getBackgroundColor() {
if (_colorPulse == 0.0f) {
return _backgroundColor;
return _backgroundColor;
}
float pulseLevel = updatePulse();
@ -75,19 +77,23 @@ void Text3DOverlay::render(RenderArgs* args) {
return; // do nothing if we're not visible
}
glPushMatrix(); {
glTranslatef(_position.x, _position.y, _position.z);
auto batch = args->_batch;
if (batch) {
glm::quat rotation;
if (_isFacingAvatar) {
// rotate about vertical to face the camera
rotation = Application::getInstance()->getCamera()->getRotation();
} else {
rotation = getRotation();
}
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
Transform transform;
transform.setTranslation(_position);
transform.setRotation(rotation);
batch->setModelTransform(transform);
const float MAX_COLOR = 255.0f;
xColor backgroundColor = getBackgroundColor();
@ -96,51 +102,38 @@ void Text3DOverlay::render(RenderArgs* args) {
glm::vec2 dimensions = getDimensions();
glm::vec2 halfDimensions = dimensions * 0.5f;
const float SLIGHTLY_BEHIND = -0.005f;
glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, SLIGHTLY_BEHIND);
glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, SLIGHTLY_BEHIND);
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, quadColor);
DependencyManager::get<GeometryCache>()->renderQuad(*batch, topLeft, bottomRight, quadColor);
// Same font properties as textSize()
float maxHeight = (float)_textRenderer->computeExtent("Xy").y * LINE_SCALE_RATIO;
float scaleFactor = (maxHeight / FIXED_FONT_SCALING_RATIO) * _lineHeight;
glTranslatef(-(halfDimensions.x - _leftMargin), halfDimensions.y - _topMargin, 0.0f);
float scaleFactor = (maxHeight / FIXED_FONT_SCALING_RATIO) * _lineHeight;
glm::vec2 clipMinimum(0.0f, 0.0f);
glm::vec2 clipDimensions((dimensions.x - (_leftMargin + _rightMargin)) / scaleFactor,
glm::vec2 clipDimensions((dimensions.x - (_leftMargin + _rightMargin)) / scaleFactor,
(dimensions.y - (_topMargin + _bottomMargin)) / scaleFactor);
glScalef(scaleFactor, -scaleFactor, scaleFactor);
enableClipPlane(GL_CLIP_PLANE0, -1.0f, 0.0f, 0.0f, clipMinimum.x + clipDimensions.x);
enableClipPlane(GL_CLIP_PLANE1, 1.0f, 0.0f, 0.0f, -clipMinimum.x);
enableClipPlane(GL_CLIP_PLANE2, 0.0f, -1.0f, 0.0f, clipMinimum.y + clipDimensions.y);
enableClipPlane(GL_CLIP_PLANE3, 0.0f, 1.0f, 0.0f, -clipMinimum.y);
transform.setTranslation(_position);
transform.postTranslate(glm::vec3(-(halfDimensions.x - _leftMargin) , halfDimensions.y - _topMargin, 0.01f));
transform.setScale(scaleFactor);
batch->setModelTransform(transform);
glm::vec4 textColor = { _color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR, getAlpha() };
_textRenderer->draw(0, 0, _text, textColor);
_textRenderer->draw(*batch, 0, 0, _text, textColor);
glDisable(GL_CLIP_PLANE0);
glDisable(GL_CLIP_PLANE1);
glDisable(GL_CLIP_PLANE2);
glDisable(GL_CLIP_PLANE3);
} glPopMatrix();
}
batch->setPipeline(DrawOverlay3D::getOpaquePipeline());
}
void Text3DOverlay::enableClipPlane(GLenum plane, float x, float y, float z, float w) {
GLdouble coefficients[] = { x, y, z, w };
glClipPlane(plane, coefficients);
glEnable(plane);
}
void Text3DOverlay::setProperties(const QScriptValue& properties) {
Planar3DOverlay::setProperties(properties);
QScriptValue text = properties.property("text");
if (text.isValid()) {
setText(text.toVariant().toString());

View file

@ -17,7 +17,7 @@
#include <QString>
#include <RenderArgs.h>
#include <TextRenderer.h>
#include <TextRenderer3D.h>
#include "Planar3DOverlay.h"
@ -60,9 +60,7 @@ public:
virtual Text3DOverlay* createClone() const;
private:
void enableClipPlane(GLenum plane, float x, float y, float z, float w);
TextRenderer* _textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE);
TextRenderer3D* _textRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE);
QString _text;
xColor _backgroundColor;

View file

@ -80,6 +80,7 @@ void TextOverlay::render(RenderArgs* args) {
glm::vec2 topLeft(left, top);
glm::vec2 bottomRight(right, bottom);
glBindTexture(GL_TEXTURE_2D, 0);
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, quadColor);
const int leftAdjust = -1; // required to make text render relative to left edge of bounds

View file

@ -795,6 +795,11 @@ void AudioClient::handleAudioInput() {
delete[] inputAudioSamples;
// Remove DC offset
if (!_isStereoInput && !_audioSourceInjectEnabled) {
_inputGate.removeDCOffset(networkAudioSamples, numNetworkSamples);
}
// only impose the noise gate and perform tone injection if we are sending mono audio
if (!_isStereoInput && !_audioSourceInjectEnabled && _isNoiseGateEnabled) {
_inputGate.gateSamples(networkAudioSamples, numNetworkSamples);

View file

@ -33,6 +33,32 @@ AudioNoiseGate::AudioNoiseGate() :
}
void AudioNoiseGate::removeDCOffset(int16_t* samples, int numSamples) {
//
// DC Offset correction
//
// Measure the DC offset over a trailing number of frames, and remove it from the input signal.
// This causes the noise background measurements and server muting to be more accurate. Many off-board
// ADC's have a noticeable DC offset.
//
const float DC_OFFSET_AVERAGING = 0.99f;
float measuredDcOffset = 0.0f;
// Remove trailing DC offset from samples
for (int i = 0; i < numSamples; i++) {
measuredDcOffset += samples[i];
samples[i] -= (int16_t) _dcOffset;
}
// Update measured DC offset
measuredDcOffset /= numSamples;
if (_dcOffset == 0.0f) {
// On first frame, copy over measured offset
_dcOffset = measuredDcOffset;
} else {
_dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset;
}
}
void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
//
// Impose Noise Gate
@ -61,17 +87,12 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
const int NOISE_GATE_WIDTH = 5;
const int NOISE_GATE_CLOSE_FRAME_DELAY = 5;
const int NOISE_GATE_FRAMES_TO_AVERAGE = 5;
const float DC_OFFSET_AVERAGING = 0.99f;
// Check clipping, adjust DC offset, and check if should open noise gate
float measuredDcOffset = 0.0f;
// Check clipping, and check if should open noise gate
_didClipInLastFrame = false;
for (int i = 0; i < numSamples; i++) {
measuredDcOffset += samples[i];
samples[i] -= (int16_t) _dcOffset;
thisSample = std::abs(samples[i]);
if (thisSample >= ((float) AudioConstants::MAX_SAMPLE_VALUE * CLIPPING_THRESHOLD)) {
_didClipInLastFrame = true;
}
@ -83,14 +104,6 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
}
}
measuredDcOffset /= numSamples;
if (_dcOffset == 0.0f) {
// On first frame, copy over measured offset
_dcOffset = measuredDcOffset;
} else {
_dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset;
}
_lastLoudness = fabs(loudness / numSamples);
if (_quietestFrame > _lastLoudness) {

View file

@ -21,6 +21,7 @@ public:
AudioNoiseGate();
void gateSamples(int16_t* samples, int numSamples);
void removeDCOffset(int16_t* samples, int numSamples);
bool clippedInLastFrame() const { return _didClipInLastFrame; }
float getMeasuredFloor() const { return _measuredFloor; }

View file

@ -7,4 +7,10 @@ add_dependency_external_projects(glm)
find_package(GLM REQUIRED)
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
link_hifi_libraries(networking shared)
# we use libsoxr for resampling
add_dependency_external_projects(soxr)
find_package(Soxr REQUIRED)
target_link_libraries(${TARGET_NAME} ${SOXR_LIBRARIES})
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${SOXR_INCLUDE_DIRS})
link_hifi_libraries(networking shared)

View file

@ -16,10 +16,12 @@
#include <PacketHeaders.h>
#include <SharedUtil.h>
#include <UUID.h>
#include <soxr.h>
#include "AbstractAudioInterface.h"
#include "AudioRingBuffer.h"
#include "AudioLogging.h"
#include "SoundCache.h"
#include "AudioInjector.h"
@ -91,7 +93,6 @@ void AudioInjector::injectAudio() {
}
void AudioInjector::restart() {
qCDebug(audio) << "Restarting an AudioInjector by stopping and starting over.";
connect(this, &AudioInjector::finished, this, &AudioInjector::restartPortionAfterFinished);
if (!_isStarted || _isFinished) {
emit finished();
@ -284,3 +285,66 @@ void AudioInjector::stopAndDeleteLater() {
stop();
QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
}
AudioInjector* AudioInjector::playSound(const QString& soundUrl, const float volume, const float stretchFactor, const glm::vec3 position) {
if (soundUrl.isEmpty()) {
return NULL;
}
auto soundCache = DependencyManager::get<SoundCache>();
if (soundCache.isNull()) {
return NULL;
}
SharedSoundPointer sound = soundCache.data()->getSound(QUrl(soundUrl));
if (sound.isNull() || !sound->isReady()) {
return NULL;
}
AudioInjectorOptions options;
options.stereo = sound->isStereo();
options.position = position;
options.volume = volume;
QByteArray samples = sound->getByteArray();
if (stretchFactor == 1.0f) {
return playSound(samples, options, NULL);
}
soxr_io_spec_t spec = soxr_io_spec(SOXR_INT16_I, SOXR_INT16_I);
soxr_quality_spec_t qualitySpec = soxr_quality_spec(SOXR_MQ, 0);
const int channelCount = sound->isStereo() ? 2 : 1;
const int standardRate = AudioConstants::SAMPLE_RATE;
const int resampledRate = standardRate * stretchFactor;
const int nInputSamples = samples.size() / sizeof(int16_t);
const int nOutputSamples = nInputSamples * stretchFactor;
QByteArray resampled(nOutputSamples * sizeof(int16_t), '\0');
const int16_t* receivedSamples = reinterpret_cast<const int16_t*>(samples.data());
soxr_error_t soxError = soxr_oneshot(standardRate, resampledRate, channelCount,
receivedSamples, nInputSamples, NULL,
reinterpret_cast<int16_t*>(resampled.data()), nOutputSamples, NULL,
&spec, &qualitySpec, 0);
if (soxError) {
qCDebug(audio) << "Unable to resample" << soundUrl << "from" << nInputSamples << "@" << standardRate << "to" << nOutputSamples << "@" << resampledRate;
resampled = samples;
}
return playSound(resampled, options, NULL);
}
AudioInjector* AudioInjector::playSound(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface) {
QThread* injectorThread = new QThread();
injectorThread->setObjectName("Audio Injector Thread");
AudioInjector* injector = new AudioInjector(buffer, options);
injector->setLocalAudioInterface(localInterface);
injector->moveToThread(injectorThread);
// start injecting when the injector thread starts
connect(injectorThread, &QThread::started, injector, &AudioInjector::injectAudio);
// connect the right slots and signals for AudioInjector and thread cleanup
connect(injector, &AudioInjector::destroyed, injectorThread, &QThread::quit);
connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater);
injectorThread->start();
return injector;
}

View file

@ -45,6 +45,10 @@ public:
bool isLocalOnly() const { return _options.localOnly; }
void setLocalAudioInterface(AbstractAudioInterface* localAudioInterface) { _localAudioInterface = localAudioInterface; }
static AudioInjector* playSound(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface);
static AudioInjector* playSound(const QString& soundUrl, const float volume, const float stretchFactor, const glm::vec3 position);
public slots:
void injectAudio();
void restart();

View file

@ -17,10 +17,4 @@ find_package(PolyVox REQUIRED)
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${POLYVOX_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${POLYVOX_LIBRARIES})
# for changing the pitch of collision sounds
add_dependency_external_projects(soxr)
find_package(Soxr REQUIRED)
target_link_libraries(${TARGET_NAME} ${SOXR_LIBRARIES})
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${SOXR_INCLUDE_DIRS})
link_hifi_libraries(shared gpu script-engine render render-utils)

View file

@ -27,10 +27,6 @@
#include <SceneScriptingInterface.h>
#include <ScriptEngine.h>
#include <TextureCache.h>
#include <SoundCache.h>
#include <soxr.h>
#include <AudioConstants.h>
#include "EntityTreeRenderer.h"
@ -48,16 +44,12 @@
#include "RenderablePolyVoxEntityItem.h"
#include "EntitiesRendererLogging.h"
#include "DependencyManager.h"
#include "AddressManager.h"
EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterface* viewState,
AbstractScriptingServicesInterface* scriptingServices) :
OctreeRenderer(),
_wantScripts(wantScripts),
_entitiesScriptEngine(NULL),
_sandboxScriptEngine(NULL),
_localAudioInterface(NULL),
_lastMouseEventValid(false),
_viewState(viewState),
_scriptingServices(scriptingServices),
@ -1057,7 +1049,6 @@ void EntityTreeRenderer::checkAndCallUnload(const EntityItemID& entityID) {
}
}
void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision) {
EntityItemPointer entity = entityTree->findEntityByEntityItemID(id);
if (!entity) {
@ -1100,61 +1091,15 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT
if (energyFactorOfFull < COLLISION_MINIMUM_VOLUME) {
return;
}
auto soundCache = DependencyManager::get<SoundCache>();
if (soundCache.isNull()) {
return;
}
SharedSoundPointer sound = soundCache.data()->getSound(QUrl(collisionSoundURL));
if (sound.isNull() || !sound->isReady()) {
return;
}
// This is a hack. Quiet sound aren't really heard at all, so we compress everything to the range [1-c, 1], if we play it all.
// Quiet sound aren't really heard at all, so we can compress everything to the range [1-c, 1], if we play it all.
const float COLLISION_SOUND_COMPRESSION_RANGE = 1.0f; // This section could be removed when the value is 1, but let's see how it goes.
float volume = energyFactorOfFull;
volume = (volume * COLLISION_SOUND_COMPRESSION_RANGE) + (1.0f - COLLISION_SOUND_COMPRESSION_RANGE);
// This is quite similar to AudioScriptingInterface::playSound() and should probably be refactored.
AudioInjectorOptions options;
options.stereo = sound->isStereo();
options.position = position;
options.volume = volume;
const float volume = (energyFactorOfFull * COLLISION_SOUND_COMPRESSION_RANGE) + (1.0f - COLLISION_SOUND_COMPRESSION_RANGE);
// Shift the pitch down by ln(1 + (size / COLLISION_SIZE_FOR_STANDARD_PITCH)) / ln(2)
const float COLLISION_SIZE_FOR_STANDARD_PITCH = 0.2f;
QByteArray samples = sound->getByteArray();
soxr_io_spec_t spec = soxr_io_spec(SOXR_INT16_I, SOXR_INT16_I);
soxr_quality_spec_t qualitySpec = soxr_quality_spec(SOXR_MQ, 0);
const int channelCount = sound->isStereo() ? 2 : 1;
const float factor = log(1.0f + (entity->getMinimumAACube().getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2);
const int standardRate = AudioConstants::SAMPLE_RATE;
const int resampledRate = standardRate * factor;
const int nInputSamples = samples.size() / sizeof(int16_t);
const int nOutputSamples = nInputSamples * factor;
QByteArray resampled(nOutputSamples * sizeof(int16_t), '\0');
const int16_t* receivedSamples = reinterpret_cast<const int16_t*>(samples.data());
soxr_error_t soxError = soxr_oneshot(standardRate, resampledRate, channelCount,
receivedSamples, nInputSamples, NULL,
reinterpret_cast<int16_t*>(resampled.data()), nOutputSamples, NULL,
&spec, &qualitySpec, 0);
if (soxError) {
qCDebug(entitiesrenderer) << "Unable to resample" << collisionSoundURL << "from" << nInputSamples << "@" << standardRate << "to" << nOutputSamples << "@" << resampledRate;
resampled = samples;
}
AudioInjector* injector = new AudioInjector(resampled, options);
injector->setLocalAudioInterface(_localAudioInterface);
injector->triggerDeleteAfterFinish();
QThread* injectorThread = new QThread();
injectorThread->setObjectName("Audio Injector Thread");
injector->moveToThread(injectorThread);
// start injecting when the injector thread starts
connect(injectorThread, &QThread::started, injector, &AudioInjector::injectAudio);
// connect the right slots and signals for AudioInjector and thread cleanup
connect(injector, &AudioInjector::destroyed, injectorThread, &QThread::quit);
connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater);
injectorThread->start();
const float stretchFactor = log(1.0f + (entity->getMinimumAACube().getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2);
AudioInjector::playSound(collisionSoundURL, volume, stretchFactor, position);
}
void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB,

View file

@ -158,7 +158,6 @@ private:
QHash<EntityItemID, EntityScriptDetails> _entityScripts;
void playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision);
AbstractAudioInterface* _localAudioInterface; // So we can render collision sounds
bool _lastMouseEventValid;
MouseEvent _lastMouseEvent;

View file

@ -43,9 +43,9 @@ void RenderableLineEntityItem::render(RenderArgs* args) {
Q_ASSERT(args->_batch);
gpu::Batch& batch = *args->_batch;
// TODO: Figure out clean , efficient way to do relative line positioning. For now we'll just use absolute positioning.
//batch.setModelTransform(getTransformToCenter());
batch.setModelTransform(Transform());
Transform transform = Transform();
transform.setTranslation(getPosition());
batch.setModelTransform(transform);
batch._glLineWidth(getLineWidth());
if (getLinePoints().size() > 1) {

View file

@ -197,6 +197,8 @@ public:
QString getSimulatorIDAsString() const { return _simulatorID.toString().mid(1,36).toUpper(); }
void setVoxelDataDirty() { _voxelDataChanged = true; }
void setLinePointsDirty() {_linePointsChanged = true; }
void setCreated(QDateTime& v);

View file

@ -442,6 +442,43 @@ bool EntityScriptingInterface::setVoxels(QUuid entityID,
return true;
}
bool EntityScriptingInterface::setPoints(QUuid entityID, std::function<bool(LineEntityItem&)> actor) {
if (!_entityTree) {
return false;
}
EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID));
if (!entity) {
qCDebug(entities) << "EntityScriptingInterface::setPoints no entity with ID" << entityID;
}
EntityTypes::EntityType entityType = entity->getType();
if (entityType != EntityTypes::Line) {
return false;
}
auto now = usecTimestampNow();
LineEntityItem* lineEntity = static_cast<LineEntityItem*>(entity.get());
_entityTree->lockForWrite();
bool success = actor(*lineEntity);
entity->setLastEdited(now);
entity->setLastBroadcast(now);
_entityTree->unlock();
_entityTree->lockForRead();
EntityItemProperties properties = entity->getProperties();
_entityTree->unlock();
properties.setLinePointsDirty();
properties.setLastEdited(now);
queueEntityMessage(PacketTypeEntityEdit, entityID, properties);
return success;
}
bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value) {
return setVoxels(entityID, [center, radius, value](PolyVoxEntityItem& polyVoxEntity) {
polyVoxEntity.setSphere(center, radius, value);
@ -460,6 +497,21 @@ bool EntityScriptingInterface::setAllVoxels(QUuid entityID, int value) {
});
}
bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector<glm::vec3>& points) {
return setPoints(entityID, [points](LineEntityItem& lineEntity) -> bool
{
return lineEntity.setLinePoints(points);
});
}
bool EntityScriptingInterface::appendPoint(QUuid entityID, const glm::vec3& point) {
return setPoints(entityID, [point](LineEntityItem& lineEntity) -> bool
{
return lineEntity.appendPoint(point);
});
}
bool EntityScriptingInterface::actionWorker(const QUuid& entityID,
std::function<bool(EntitySimulation*, EntityItemPointer)> actor) {

View file

@ -22,6 +22,7 @@
#include <OctreeScriptingInterface.h>
#include <RegisteredMetaTypes.h>
#include "PolyVoxEntityItem.h"
#include "LineEntityItem.h"
#include "EntityEditPacketSender.h"
@ -121,6 +122,9 @@ public slots:
Q_INVOKABLE bool setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value);
Q_INVOKABLE bool setVoxel(QUuid entityID, const glm::vec3& position, int value);
Q_INVOKABLE bool setAllVoxels(QUuid entityID, int value);
Q_INVOKABLE bool setAllPoints(QUuid entityID, const QVector<glm::vec3>& points);
Q_INVOKABLE bool appendPoint(QUuid entityID, const glm::vec3& point);
Q_INVOKABLE void dumpTree() const;
@ -157,6 +161,7 @@ signals:
private:
bool actionWorker(const QUuid& entityID, std::function<bool(EntitySimulation*, EntityItemPointer)> actor);
bool setVoxels(QUuid entityID, std::function<void(PolyVoxEntityItem&)> actor);
bool setPoints(QUuid entityID, std::function<bool(LineEntityItem&)> actor);
void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties);
/// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode

View file

@ -23,6 +23,7 @@
const float LineEntityItem::DEFAULT_LINE_WIDTH = 2.0f;
const int LineEntityItem::MAX_POINTS_PER_LINE = 70;
EntityItemPointer LineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
@ -85,24 +86,38 @@ bool LineEntityItem::setProperties(const EntityItemProperties& properties) {
return somethingChanged;
}
void LineEntityItem::setLinePoints(const QVector<glm::vec3>& points) {
QVector<glm::vec3> sanitizedPoints;
int invalidPoints = 0;
bool LineEntityItem::appendPoint(const glm::vec3& point) {
if (_points.size() > MAX_POINTS_PER_LINE - 1) {
qDebug() << "MAX POINTS REACHED!";
return false;
}
glm::vec3 halfBox = getDimensions() * 0.5f;
if ( (point.x < - halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < - halfBox.z || point.z > halfBox.z) ) {
qDebug() << "Point is outside entity's bounding box";
return false;
}
_points << point;
_pointsChanged = true;
return true;
}
bool LineEntityItem::setLinePoints(const QVector<glm::vec3>& points) {
if (points.size() > MAX_POINTS_PER_LINE) {
return false;
}
for (int i = 0; i < points.size(); i++) {
glm::vec3 point = points.at(i);
// Make sure all of our points are valid numbers.
// Must be greater than 0 because vector component is set to 0 if it is invalid data. Also should never be greater than TREE_SCALE
if ( (point.x > 0 && point.x < TREE_SCALE) && (point.y > 0 && point.y < TREE_SCALE) && (point.z > 0 && point.z < TREE_SCALE) ) {
sanitizedPoints << point;
} else {
++invalidPoints;
glm::vec3 pos = getPosition();
glm::vec3 halfBox = getDimensions() * 0.5f;
if ( (point.x < - halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < - halfBox.z || point.z > halfBox.z) ) {
qDebug() << "Point is outside entity's bounding box";
return false;
}
}
if (invalidPoints > 0) {
qDebug() << "Line with" << invalidPoints << "INVALID POINTS";
}
_points = sanitizedPoints;
_points = points;
_pointsChanged = true;
return true;
}
int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,

View file

@ -54,7 +54,8 @@ class LineEntityItem : public EntityItem {
void setLineWidth(float lineWidth){ _lineWidth = lineWidth; }
float getLineWidth() const{ return _lineWidth; }
void setLinePoints(const QVector<glm::vec3>& points);
bool setLinePoints(const QVector<glm::vec3>& points);
bool appendPoint(const glm::vec3& point);
const QVector<glm::vec3>& getLinePoints() const{ return _points; }
@ -68,6 +69,7 @@ class LineEntityItem : public EntityItem {
virtual void debugDump() const;
static const float DEFAULT_LINE_WIDTH;
static const int MAX_POINTS_PER_LINE;
protected:
rgbColor _color;

View file

@ -308,6 +308,9 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const
handlePath(returnedPath, trigger);
}
} else {
// we're going to hit the index path, set that as the _newHostLookupPath
_newHostLookupPath = INDEX_PATH;
// we didn't override the path or get one back - ask the DS for the viewpoint of its index path
// which we will jump to if it exists
emit pathChangeRequired(INDEX_PATH);
@ -479,6 +482,7 @@ bool AddressManager::handleViewpoint(const QString& viewpointString, bool should
// We use _newHostLookupPath to determine if the client has already stored its last address
// before moving to a new host thanks to the information in the same lookup URL.
if (definitelyPathOnly || (!pathString.isEmpty() && pathString != _newHostLookupPath)) {
addCurrentAddressToHistory(LookupTrigger::UserInput);
}

View file

@ -350,6 +350,19 @@ void OctreePersistThread::rollOldBackupVersions(const BackupRule& rule) {
if (rule.extensionFormat.contains("%N")) {
if (rule.maxBackupVersions > 0) {
qCDebug(octree) << "Rolling old backup versions for rule" << rule.name << "...";
// Delete maximum rolling file because rename() fails on Windows if target exists
QString backupMaxExtensionN = rule.extensionFormat;
backupMaxExtensionN.replace(QString("%N"), QString::number(rule.maxBackupVersions));
QString backupMaxFilenameN = _filename + backupMaxExtensionN;
QFile backupMaxFileN(backupMaxFilenameN);
if (backupMaxFileN.exists()) {
int result = remove(qPrintable(backupMaxFilenameN));
if (result != 0) {
qCDebug(octree) << "ERROR deleting old backup file " << backupMaxFilenameN;
}
}
for(int n = rule.maxBackupVersions - 1; n > 0; n--) {
QString backupExtensionN = rule.extensionFormat;
QString backupExtensionNplusOne = rule.extensionFormat;

View file

@ -545,11 +545,6 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
// we can use the AABox's ray intersection by mapping our origin and direction into the model frame
// and testing intersection there.
if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face)) {
if (!_calculatedMeshBoxesValid) {
recalculateMeshBoxes(pickAgainstTriangles);
}
float bestDistance = std::numeric_limits<float>::max();
float distanceToSubMesh;
@ -560,6 +555,11 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
// If we hit the models box, then consider the submeshes...
_mutex.lock();
if (!_calculatedMeshBoxesValid) {
recalculateMeshBoxes(pickAgainstTriangles);
}
foreach(const AABox& subMeshBox, _calculatedMeshBoxes) {
if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace)) {
@ -1811,7 +1811,9 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
// We need to make sure we have valid offsets calculated before we can render
if (!_calculatedMeshPartOffsetValid) {
_mutex.lock();
recalculateMeshPartOffsets();
_mutex.unlock();
}
auto textureCache = DependencyManager::get<TextureCache>();
@ -2019,7 +2021,9 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
}
}
_mutex.lock();
qint64 offset = _calculatedMeshPartOffset[QPair<int,int>(meshIndex, partIndex)];
_mutex.unlock();
if (part.quadIndices.size() > 0) {
batch.drawIndexed(gpu::QUADS, part.quadIndices.size(), offset);

View file

@ -174,11 +174,11 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
}
const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() const {
gpu::PipelinePointer DrawOverlay3D::_opaquePipeline;
const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() {
if (!_opaquePipeline) {
auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(overlay3D_vert)));
auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(overlay3D_frag)));
auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps));
auto state = gpu::StatePointer(new gpu::State());
@ -238,4 +238,3 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon
args->_batch = nullptr;
args->_whiteTexture.reset();
}

View file

@ -53,10 +53,10 @@ public:
};
class DrawOverlay3D {
mutable gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable
static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable
public:
const gpu::PipelinePointer& getOpaquePipeline() const;
static const gpu::PipelinePointer& getOpaquePipeline();
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
typedef render::Job::Model<DrawOverlay3D> JobModel;

View file

@ -83,6 +83,9 @@ public slots:
virtual void captureWheelEvents() = 0;
virtual void releaseWheelEvents() = 0;
virtual void captureActionEvents() = 0;
virtual void releaseActionEvents() = 0;
virtual void captureJoystick(int joystickIndex) = 0;
virtual void releaseJoystick(int joystickIndex) = 0;
@ -112,6 +115,8 @@ signals:
void touchUpdateEvent(const TouchEvent& event);
void wheelEvent(const WheelEvent& event);
void actionEvent(int action, float state);
};

View file

@ -46,24 +46,7 @@ ScriptAudioInjector* AudioScriptingInterface::playSound(Sound* sound, const Audi
AudioInjectorOptions optionsCopy = injectorOptions;
optionsCopy.stereo = sound->isStereo();
QThread* injectorThread = new QThread();
injectorThread->setObjectName("Audio Injector Thread");
AudioInjector* injector = new AudioInjector(sound, optionsCopy);
injector->setLocalAudioInterface(_localAudioInterface);
injector->moveToThread(injectorThread);
// start injecting when the injector thread starts
connect(injectorThread, &QThread::started, injector, &AudioInjector::injectAudio);
// connect the right slots and signals for AudioInjector and thread cleanup
connect(injector, &AudioInjector::destroyed, injectorThread, &QThread::quit);
connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater);
injectorThread->start();
return new ScriptAudioInjector(injector);
return new ScriptAudioInjector(AudioInjector::playSound(sound->getByteArray(), optionsCopy, _localAudioInterface));
} else {
qCDebug(scriptengine) << "AudioScriptingInterface::playSound called with null Sound object.";

View file

@ -28,7 +28,7 @@ public slots:
void restart() { _injector->restart(); }
void stop() { _injector->stop(); }
void setOptions(AudioInjectorOptions& options) { _injector->setOptions(options); }
void setOptions(const AudioInjectorOptions& options) { _injector->setOptions(options); }
float getLoudness() const { return _injector->getLoudness(); }
bool isPlaying() const { return _injector->isPlaying(); }

View file

@ -317,7 +317,10 @@ void ScriptEngine::init() {
registerAnimationTypes(this);
registerAvatarTypes(this);
registerAudioMetaTypes(this);
_controllerScriptingInterface->registerControllerTypes(this);
if (_controllerScriptingInterface) {
_controllerScriptingInterface->registerControllerTypes(this);
}
qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly);
qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue);

View file

@ -20,6 +20,7 @@
static int vec4MetaTypeId = qRegisterMetaType<glm::vec4>();
static int vec3MetaTypeId = qRegisterMetaType<glm::vec3>();
static int qVectorVec3MetaTypeId = qRegisterMetaType<QVector<glm::vec3>>();
static int vec2MetaTypeId = qRegisterMetaType<glm::vec2>();
static int quatMetaTypeId = qRegisterMetaType<glm::quat>();
static int xColorMetaTypeId = qRegisterMetaType<xColor>();
@ -31,6 +32,7 @@ static int collisionMetaTypeId = qRegisterMetaType<Collision>();
void registerMetaTypes(QScriptEngine* engine) {
qScriptRegisterMetaType(engine, vec4toScriptValue, vec4FromScriptValue);
qScriptRegisterMetaType(engine, vec3toScriptValue, vec3FromScriptValue);
qScriptRegisterMetaType(engine, qVectorVec3ToScriptValue, qVectorVec3FromScriptValue);
qScriptRegisterMetaType(engine, vec2toScriptValue, vec2FromScriptValue);
qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue);
qScriptRegisterMetaType(engine, qRectToScriptValue, qRectFromScriptValue);
@ -93,6 +95,16 @@ QVector<glm::vec3> qVectorVec3FromScriptValue(const QScriptValue& array){
return newVector;
}
void qVectorVec3FromScriptValue(const QScriptValue& array, QVector<glm::vec3>& vector ) {
int length = array.property("length").toInteger();
for (int i = 0; i < length; i++) {
glm::vec3 newVec3 = glm::vec3();
vec3FromScriptValue(array.property(i), newVec3);
vector << newVec3;
}
}
QScriptValue vec2toScriptValue(QScriptEngine* engine, const glm::vec2 &vec2) {
QScriptValue obj = engine->newObject();
obj.setProperty("x", vec2.x);

View file

@ -57,6 +57,7 @@ QScriptValue qURLToScriptValue(QScriptEngine* engine, const QUrl& url);
void qURLFromScriptValue(const QScriptValue& object, QUrl& url);
QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector<glm::vec3>& vector);
void qVectorVec3FromScriptValue(const QScriptValue& array, QVector<glm::vec3>& vector);
QVector<glm::vec3> qVectorVec3FromScriptValue( const QScriptValue& array);
class PickRay {