mirror of
https://github.com/overte-org/overte.git
synced 2025-08-14 13:07:50 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into tablet-ui-edit-js
This commit is contained in:
commit
298e842fd1
6 changed files with 105 additions and 33 deletions
|
@ -25,6 +25,9 @@ void KeyboardMouseDevice::pluginUpdate(float deltaTime, const controller::InputC
|
|||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
userInputMapper->withLock([&, this]() {
|
||||
_inputDevice->update(deltaTime, inputCalibrationData);
|
||||
|
||||
_inputDevice->_axisStateMap[MOUSE_AXIS_X] = _lastCursor.x();
|
||||
_inputDevice->_axisStateMap[MOUSE_AXIS_Y] = _lastCursor.y();
|
||||
});
|
||||
|
||||
// For touch event, we need to check that the last event is not too long ago
|
||||
|
@ -249,6 +252,9 @@ controller::Input::NamedVector KeyboardMouseDevice::InputDevice::getAvailableInp
|
|||
availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_Y_POS), "MouseMoveUp"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_Y_NEG), "MouseMoveDown"));
|
||||
|
||||
availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_X), "MouseX"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_Y), "MouseY"));
|
||||
|
||||
availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_Y_POS), "MouseWheelRight"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_Y_NEG), "MouseWheelLeft"));
|
||||
availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_WHEEL_X_POS), "MouseWheelUp"));
|
||||
|
|
|
@ -47,6 +47,8 @@ public:
|
|||
MOUSE_AXIS_X_NEG,
|
||||
MOUSE_AXIS_Y_POS,
|
||||
MOUSE_AXIS_Y_NEG,
|
||||
MOUSE_AXIS_X,
|
||||
MOUSE_AXIS_Y,
|
||||
MOUSE_AXIS_WHEEL_Y_POS,
|
||||
MOUSE_AXIS_WHEEL_Y_NEG,
|
||||
MOUSE_AXIS_WHEEL_X_POS,
|
||||
|
|
|
@ -26,6 +26,10 @@ glm::mat4 Mat4::createFromScaleRotAndTrans(const glm::vec3& scale, const glm::qu
|
|||
return createMatFromScaleQuatAndPos(scale, rot, trans);
|
||||
}
|
||||
|
||||
glm::mat4 Mat4::createFromColumns(const glm::vec4& col0, const glm::vec4& col1, const glm::vec4& col2, const glm::vec4& col3) const {
|
||||
return glm::mat4(col0, col1, col2, col3);
|
||||
}
|
||||
|
||||
glm::vec3 Mat4::extractTranslation(const glm::mat4& m) const {
|
||||
return ::extractTranslation(m);
|
||||
}
|
||||
|
|
|
@ -23,8 +23,10 @@ class Mat4 : public QObject {
|
|||
|
||||
public slots:
|
||||
glm::mat4 multiply(const glm::mat4& m1, const glm::mat4& m2) const;
|
||||
|
||||
glm::mat4 createFromRotAndTrans(const glm::quat& rot, const glm::vec3& trans) const;
|
||||
glm::mat4 createFromScaleRotAndTrans(const glm::vec3& scale, const glm::quat& rot, const glm::vec3& trans) const;
|
||||
glm::mat4 createFromColumns(const glm::vec4& col0, const glm::vec4& col1, const glm::vec4& col2, const glm::vec4& col3) const;
|
||||
|
||||
glm::vec3 extractTranslation(const glm::mat4& m) const;
|
||||
glm::quat extractRotation(const glm::mat4& m) const;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
/* global getControllerWorldLocation, setEntityCustomData, Tablet, WebTablet:true, HMD, Settings, Script,
|
||||
Vec3, Quat, MyAvatar, Entities, Overlays, Camera, Messages, Xform */
|
||||
Vec3, Quat, MyAvatar, Entities, Overlays, Camera, Messages, Xform, clamp */
|
||||
|
||||
Script.include(Script.resolvePath("../libraries/utils.js"));
|
||||
Script.include(Script.resolvePath("../libraries/controllers.js"));
|
||||
|
@ -118,7 +118,7 @@ WebTablet = function (url, width, dpi, hand, clientOnly) {
|
|||
};
|
||||
|
||||
// compute position, rotation & parentJointIndex of the tablet
|
||||
this.calculateTabletAttachmentProperties(hand, tabletProperties);
|
||||
this.calculateTabletAttachmentProperties(hand, true, tabletProperties);
|
||||
|
||||
this.cleanUpOldTablets();
|
||||
this.tabletEntityID = Entities.addEntity(tabletProperties, clientOnly);
|
||||
|
@ -252,31 +252,78 @@ WebTablet.prototype.destroy = function () {
|
|||
WebTablet.prototype.geometryChanged = function (geometry) {
|
||||
if (!HMD.active) {
|
||||
var tabletProperties = {};
|
||||
|
||||
// compute position, rotation & parentJointIndex of the tablet
|
||||
this.calculateTabletAttachmentProperties(NO_HANDS, tabletProperties);
|
||||
this.calculateTabletAttachmentProperties(NO_HANDS, false, tabletProperties);
|
||||
Entities.editEntity(this.tabletEntityID, tabletProperties);
|
||||
}
|
||||
};
|
||||
|
||||
function gluPerspective(fovy, aspect, zNear, zFar) {
|
||||
var cotan = 1 / Math.tan(fovy / 2);
|
||||
var alpha = -(zFar + zNear) / (zFar - zNear);
|
||||
var beta = -(2 * zFar * zNear) / (zFar - zNear);
|
||||
var col0 = {x: cotan / aspect, y: 0, z: 0, w: 0};
|
||||
var col1 = {x: 0, y: cotan, z: 0, w: 0};
|
||||
var col2 = {x: 0, y: 0, z: alpha, w: -1};
|
||||
var col3 = {x: 0, y: 0, z: beta, w: 0};
|
||||
return Mat4.createFromColumns(col0, col1, col2, col3);
|
||||
}
|
||||
|
||||
// calclulate the appropriate position of the tablet in world space, such that it fits in the center of the screen.
|
||||
// with a bit of padding on the top and bottom.
|
||||
WebTablet.prototype.calculateWorldAttitudeRelativeToCamera = function () {
|
||||
// windowPos is used to position the center of the tablet at the given position.
|
||||
WebTablet.prototype.calculateWorldAttitudeRelativeToCamera = function (windowPos) {
|
||||
|
||||
var DEFAULT_DESKTOP_TABLET_SCALE = 75;
|
||||
var DESKTOP_TABLET_SCALE = Settings.getValue("desktopTabletScale") || DEFAULT_DESKTOP_TABLET_SCALE;
|
||||
|
||||
// clamp window pos so 2d tablet is not off-screen.
|
||||
var TABLET_TEXEL_PADDING = {x: 60, y: 90};
|
||||
var X_CLAMP = (DESKTOP_TABLET_SCALE / 100) * ((TABLET_TEXTURE_RESOLUTION.x / 2) + TABLET_TEXEL_PADDING.x);
|
||||
var Y_CLAMP = (DESKTOP_TABLET_SCALE / 100) * ((TABLET_TEXTURE_RESOLUTION.y / 2) + TABLET_TEXEL_PADDING.y);
|
||||
windowPos.x = clamp(windowPos.x, X_CLAMP, Window.innerWidth - X_CLAMP);
|
||||
windowPos.y = clamp(windowPos.y, Y_CLAMP, Window.innerHeight - Y_CLAMP);
|
||||
|
||||
var fov = (Settings.getValue('fieldOfView') || DEFAULT_VERTICAL_FIELD_OF_VIEW) * (Math.PI / 180);
|
||||
var MAX_PADDING_FACTOR = 2.2;
|
||||
var PADDING_FACTOR = Math.min(Window.innerHeight / TABLET_TEXTURE_RESOLUTION.y, MAX_PADDING_FACTOR);
|
||||
var TABLET_HEIGHT = (TABLET_TEXTURE_RESOLUTION.y / this.dpi) * INCHES_TO_METERS;
|
||||
var WEB_ENTITY_Z_OFFSET = (this.depth / 2);
|
||||
|
||||
// calcualte distance from camera
|
||||
var dist = (PADDING_FACTOR * TABLET_HEIGHT) / (2 * Math.tan(fov / 2) * (DESKTOP_TABLET_SCALE / 100)) - WEB_ENTITY_Z_OFFSET;
|
||||
|
||||
var Z_NEAR = 0.01;
|
||||
var Z_FAR = 100.0;
|
||||
|
||||
// calculate mouse position in clip space
|
||||
var alpha = -(Z_FAR + Z_NEAR) / (Z_FAR - Z_NEAR);
|
||||
var beta = -(2 * Z_FAR * Z_NEAR) / (Z_FAR - Z_NEAR);
|
||||
var clipZ = (beta / dist) - alpha;
|
||||
var clipMousePosition = {x: (2 * windowPos.x / Window.innerWidth) - 1,
|
||||
y: (2 * ((Window.innerHeight - windowPos.y) / Window.innerHeight)) - 1,
|
||||
z: clipZ};
|
||||
|
||||
// calculate projection matrix
|
||||
var aspect = Window.innerWidth / Window.innerHeight;
|
||||
var projMatrix = gluPerspective(fov, aspect, Z_NEAR, Z_FAR);
|
||||
|
||||
// transform mouse clip position into view coordinates.
|
||||
var viewMousePosition = Mat4.transformPoint(Mat4.inverse(projMatrix), clipMousePosition);
|
||||
|
||||
// transform view mouse position into world coordinates.
|
||||
var viewToWorldMatrix = Mat4.createFromRotAndTrans(Camera.orientation, Camera.position);
|
||||
var worldMousePosition = Mat4.transformPoint(viewToWorldMatrix, viewMousePosition);
|
||||
|
||||
return {
|
||||
position: Vec3.sum(Camera.position, Vec3.multiply(dist, Quat.getFront(Camera.orientation))),
|
||||
position: worldMousePosition,
|
||||
rotation: Quat.multiply(Camera.orientation, ROT_Y_180)
|
||||
};
|
||||
};
|
||||
|
||||
// compute position, rotation & parentJointIndex of the tablet
|
||||
WebTablet.prototype.calculateTabletAttachmentProperties = function (hand, tabletProperties) {
|
||||
WebTablet.prototype.calculateTabletAttachmentProperties = function (hand, useMouse, tabletProperties) {
|
||||
if (HMD.active) {
|
||||
// in HMD mode, the tablet should be relative to the sensor to world matrix.
|
||||
tabletProperties.parentJointIndex = SENSOR_TO_ROOM_MATRIX;
|
||||
|
@ -289,8 +336,16 @@ WebTablet.prototype.calculateTabletAttachmentProperties = function (hand, tablet
|
|||
// in desktop mode, the tablet should be relative to the camera
|
||||
tabletProperties.parentJointIndex = CAMERA_MATRIX;
|
||||
|
||||
// compute the appropriate postion of the tablet such that it fits in the center of the screen nicely.
|
||||
var attitude = this.calculateWorldAttitudeRelativeToCamera();
|
||||
var windowPos;
|
||||
if (useMouse) {
|
||||
// compute the appropriate postion of the tablet such that it fits in the center of the screen nicely.
|
||||
windowPos = {x: Controller.getValue(Controller.Hardware.Keyboard.MouseX),
|
||||
y: Controller.getValue(Controller.Hardware.Keyboard.MouseY)};
|
||||
} else {
|
||||
windowPos = {x: Window.innerWidth / 2,
|
||||
y: Window.innerHeight / 2};
|
||||
}
|
||||
var attitude = this.calculateWorldAttitudeRelativeToCamera(windowPos);
|
||||
tabletProperties.position = attitude.position;
|
||||
tabletProperties.rotation = attitude.rotation;
|
||||
}
|
||||
|
@ -310,7 +365,7 @@ WebTablet.prototype.onHmdChanged = function () {
|
|||
|
||||
var tabletProperties = {};
|
||||
// compute position, rotation & parentJointIndex of the tablet
|
||||
this.calculateTabletAttachmentProperties(NO_HANDS, tabletProperties);
|
||||
this.calculateTabletAttachmentProperties(NO_HANDS, false, tabletProperties);
|
||||
Entities.editEntity(this.tabletEntityID, tabletProperties);
|
||||
|
||||
// Full scene FXAA should be disabled on the overlay when the tablet in desktop mode.
|
||||
|
@ -398,7 +453,7 @@ WebTablet.prototype.cameraModeChanged = function (newMode) {
|
|||
var self = this;
|
||||
var tabletProperties = {};
|
||||
// compute position, rotation & parentJointIndex of the tablet
|
||||
self.calculateTabletAttachmentProperties(NO_HANDS, tabletProperties);
|
||||
self.calculateTabletAttachmentProperties(NO_HANDS, false, tabletProperties);
|
||||
Entities.editEntity(self.tabletEntityID, tabletProperties);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function() { // BEGIN LOCAL_SCOPE
|
||||
|
||||
// hardcoding these as it appears we cannot traverse the originalTextures in overlays??? Maybe I've missed
|
||||
// something, will revisit as this is sorta horrible.
|
||||
const UNSELECTED_TEXTURES = {"idle-D": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-idle.png"),
|
||||
|
@ -27,7 +29,7 @@ const UNSELECTED_COLOR = { red: 0x1F, green: 0xC6, blue: 0xA6};
|
|||
const SELECTED_COLOR = {red: 0xF3, green: 0x91, blue: 0x29};
|
||||
const HOVER_COLOR = {red: 0xD0, green: 0xD0, blue: 0xD0}; // almost white for now
|
||||
|
||||
(function() { // BEGIN LOCAL_SCOPE
|
||||
var conserveResources = true;
|
||||
|
||||
Script.include("/~/system/libraries/controllers.js");
|
||||
|
||||
|
@ -265,15 +267,16 @@ pal.fromQml.connect(function (message) { // messages are {method, params}, like
|
|||
function addAvatarNode(id) {
|
||||
var selected = ExtendedOverlay.isSelected(id);
|
||||
return new ExtendedOverlay(id, "sphere", {
|
||||
drawInFront: true,
|
||||
solid: true,
|
||||
alpha: 0.8,
|
||||
color: color(selected, false, 0.0),
|
||||
ignoreRayIntersection: false}, selected, true);
|
||||
drawInFront: true,
|
||||
solid: true,
|
||||
alpha: 0.8,
|
||||
color: color(selected, false, 0.0),
|
||||
ignoreRayIntersection: false}, selected, !conserveResources);
|
||||
}
|
||||
function populateUserList(selectData) {
|
||||
var data = [];
|
||||
AvatarList.getAvatarIdentifiers().sort().forEach(function (id) { // sorting the identifiers is just an aid for debugging
|
||||
var data = [], avatars = AvatarList.getAvatarIdentifiers();
|
||||
conserveResources = avatars.length > 20;
|
||||
avatars.forEach(function (id) { // sorting the identifiers is just an aid for debugging
|
||||
var avatar = AvatarList.getAvatar(id);
|
||||
var avatarPalDatum = {
|
||||
displayName: avatar.sessionDisplayName,
|
||||
|
@ -498,6 +501,9 @@ if (Settings.getValue("HUDUIEnabled")) {
|
|||
});
|
||||
}
|
||||
var isWired = false;
|
||||
var audioTimer;
|
||||
var AUDIO_LEVEL_UPDATE_INTERVAL_MS = 100; // 10hz for now (change this and change the AVERAGING_RATIO too)
|
||||
var AUDIO_LEVEL_CONSERVED_UPDATE_INTERVAL_MS = 300;
|
||||
function off() {
|
||||
if (isWired) { // It is not ok to disconnect these twice, hence guard.
|
||||
Script.update.disconnect(updateOverlays);
|
||||
|
@ -505,6 +511,7 @@ function off() {
|
|||
Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent);
|
||||
isWired = false;
|
||||
}
|
||||
if (audioTimer) { Script.clearInterval(audioTimer); }
|
||||
triggerMapping.disable(); // It's ok if we disable twice.
|
||||
triggerPressMapping.disable(); // see above
|
||||
removeOverlays();
|
||||
|
@ -521,7 +528,7 @@ function onClicked() {
|
|||
Controller.mouseMoveEvent.connect(handleMouseMoveEvent);
|
||||
triggerMapping.enable();
|
||||
triggerPressMapping.enable();
|
||||
createAudioInterval();
|
||||
audioTimer = createAudioInterval(conserveResources ? AUDIO_LEVEL_CONSERVED_UPDATE_INTERVAL_MS : AUDIO_LEVEL_UPDATE_INTERVAL_MS);
|
||||
} else {
|
||||
off();
|
||||
}
|
||||
|
@ -557,9 +564,7 @@ var AVERAGING_RATIO = 0.05;
|
|||
var LOUDNESS_FLOOR = 11.0;
|
||||
var LOUDNESS_SCALE = 2.8 / 5.0;
|
||||
var LOG2 = Math.log(2.0);
|
||||
var AUDIO_LEVEL_UPDATE_INTERVAL_MS = 100; // 10hz for now (change this and change the AVERAGING_RATIO too)
|
||||
var myData = {}; // we're not includied in ExtendedOverlay.get.
|
||||
var audioInterval;
|
||||
|
||||
function getAudioLevel(id) {
|
||||
// the VU meter should work similarly to the one in AvatarInputs: log scale, exponentially averaged
|
||||
|
@ -591,21 +596,19 @@ function getAudioLevel(id) {
|
|||
return audioLevel;
|
||||
}
|
||||
|
||||
function createAudioInterval() {
|
||||
function createAudioInterval(interval) {
|
||||
// we will update the audioLevels periodically
|
||||
// TODO: tune for efficiency - expecially with large numbers of avatars
|
||||
return Script.setInterval(function () {
|
||||
if (pal.visible) {
|
||||
var param = {};
|
||||
AvatarList.getAvatarIdentifiers().forEach(function (id) {
|
||||
var level = getAudioLevel(id);
|
||||
// qml didn't like an object with null/empty string for a key, so...
|
||||
var userId = id || 0;
|
||||
param[userId] = level;
|
||||
});
|
||||
pal.sendToQml({method: 'updateAudioLevel', params: param});
|
||||
}
|
||||
}, AUDIO_LEVEL_UPDATE_INTERVAL_MS);
|
||||
var param = {};
|
||||
AvatarList.getAvatarIdentifiers().forEach(function (id) {
|
||||
var level = getAudioLevel(id);
|
||||
// qml didn't like an object with null/empty string for a key, so...
|
||||
var userId = id || 0;
|
||||
param[userId] = level;
|
||||
});
|
||||
pal.sendToQml({method: 'updateAudioLevel', params: param});
|
||||
}, interval);
|
||||
}
|
||||
|
||||
function avatarDisconnected(nodeID) {
|
||||
|
|
Loading…
Reference in a new issue