mirror of
https://github.com/overte-org/overte.git
synced 2025-08-19 09:28:26 +02:00
merge from upstream
This commit is contained in:
commit
908481d5d4
86 changed files with 1417 additions and 1147 deletions
|
@ -272,6 +272,18 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio
|
|||
tree->setWantTerseEditLogging(wantTerseEditLogging);
|
||||
}
|
||||
|
||||
void EntityServer::nodeAdded(SharedNodePointer node) {
|
||||
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
|
||||
tree->knowAvatarID(node->getUUID());
|
||||
OctreeServer::nodeAdded(node);
|
||||
}
|
||||
|
||||
void EntityServer::nodeKilled(SharedNodePointer node) {
|
||||
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
|
||||
tree->deleteDescendantsOfAvatar(node->getUUID());
|
||||
tree->forgetAvatarID(node->getUUID());
|
||||
OctreeServer::nodeKilled(node);
|
||||
}
|
||||
|
||||
// FIXME - this stats tracking is somewhat temporary to debug the Whiteboard issues. It's not a bad
|
||||
// set of stats to have, but we'd probably want a different data structure if we keep it very long.
|
||||
|
|
|
@ -58,6 +58,8 @@ public:
|
|||
virtual void trackViewerGone(const QUuid& sessionID) override;
|
||||
|
||||
public slots:
|
||||
virtual void nodeAdded(SharedNodePointer node);
|
||||
virtual void nodeKilled(SharedNodePointer node);
|
||||
void pruneDeletedEntities();
|
||||
|
||||
protected:
|
||||
|
|
|
@ -127,8 +127,8 @@ public:
|
|||
public slots:
|
||||
/// runs the octree server assignment
|
||||
void run();
|
||||
void nodeAdded(SharedNodePointer node);
|
||||
void nodeKilled(SharedNodePointer node);
|
||||
virtual void nodeAdded(SharedNodePointer node);
|
||||
virtual void nodeKilled(SharedNodePointer node);
|
||||
void sendStatsPacket();
|
||||
|
||||
private slots:
|
||||
|
|
|
@ -46,6 +46,8 @@ function(AUTOSCRIBE_SHADER SHADER_FILE)
|
|||
set(SHADER_TARGET ${SHADER_TARGET}_frag.h)
|
||||
endif()
|
||||
|
||||
set(SHADER_TARGET "${SHADERS_DIR}/${SHADER_TARGET}")
|
||||
|
||||
# Target dependant Custom rule on the SHADER_FILE
|
||||
if (APPLE)
|
||||
set(GLPROFILE MAC_GL)
|
||||
|
@ -87,10 +89,14 @@ macro(AUTOSCRIBE_SHADER_LIB)
|
|||
file(GLOB_RECURSE SHADER_INCLUDE_FILES src/*.slh)
|
||||
file(GLOB_RECURSE SHADER_SOURCE_FILES src/*.slv src/*.slf)
|
||||
|
||||
#make the shader folder
|
||||
set(SHADERS_DIR "${CMAKE_CURRENT_BINARY_DIR}/shaders/${TARGET_NAME}")
|
||||
file(MAKE_DIRECTORY ${SHADERS_DIR})
|
||||
|
||||
#message(${SHADER_INCLUDE_FILES})
|
||||
foreach(SHADER_FILE ${SHADER_SOURCE_FILES})
|
||||
AUTOSCRIBE_SHADER(${SHADER_FILE} ${SHADER_INCLUDE_FILES})
|
||||
file(TO_CMAKE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${AUTOSCRIBE_SHADER_RETURN}" AUTOSCRIBE_GENERATED_FILE)
|
||||
file(TO_CMAKE_PATH "${AUTOSCRIBE_SHADER_RETURN}" AUTOSCRIBE_GENERATED_FILE)
|
||||
list(APPEND AUTOSCRIBE_SHADER_SRC ${AUTOSCRIBE_GENERATED_FILE})
|
||||
endforeach()
|
||||
#message(${AUTOSCRIBE_SHADER_SRC})
|
||||
|
@ -105,4 +111,7 @@ macro(AUTOSCRIBE_SHADER_LIB)
|
|||
list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${SHADER_SOURCE_FILES})
|
||||
list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${AUTOSCRIBE_SHADER_SRC})
|
||||
|
||||
# Link library shaders, if they exist
|
||||
include_directories("${SHADERS_DIR}")
|
||||
|
||||
endmacro()
|
||||
|
|
|
@ -19,20 +19,14 @@ macro(LINK_HIFI_LIBRARIES)
|
|||
endif ()
|
||||
|
||||
include_directories("${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src")
|
||||
include_directories("${CMAKE_BINARY_DIR}/libraries/${HIFI_LIBRARY}/shaders")
|
||||
|
||||
add_dependencies(${TARGET_NAME} ${HIFI_LIBRARY})
|
||||
|
||||
# link the actual library - it is static so don't bubble it up
|
||||
target_link_libraries(${TARGET_NAME} ${HIFI_LIBRARY})
|
||||
|
||||
# ask the library what its include dependencies are and link them
|
||||
get_target_property(LINKED_TARGET_DEPENDENCY_INCLUDES ${HIFI_LIBRARY} DEPENDENCY_INCLUDES)
|
||||
|
||||
if(LINKED_TARGET_DEPENDENCY_INCLUDES)
|
||||
list(APPEND ${TARGET_NAME}_DEPENDENCY_INCLUDES ${LINKED_TARGET_DEPENDENCY_INCLUDES})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
setup_memory_debugger()
|
||||
|
||||
endmacro(LINK_HIFI_LIBRARIES)
|
||||
endmacro(LINK_HIFI_LIBRARIES)
|
||||
|
|
|
@ -152,9 +152,19 @@ function maybeMoveOverlay() {
|
|||
|
||||
// MAIN CONTROL
|
||||
var wasMuted, isAway;
|
||||
var wasOverlaysVisible = Menu.isOptionChecked("Overlays");
|
||||
var eventMappingName = "io.highfidelity.away"; // goActive on hand controller button events, too.
|
||||
var eventMapping = Controller.newMapping(eventMappingName);
|
||||
|
||||
// backward compatible version of getting HMD.mounted, so it works in old clients
|
||||
function safeGetHMDMounted() {
|
||||
if (HMD.mounted === undefined) {
|
||||
return true;
|
||||
}
|
||||
return HMD.mounted;
|
||||
}
|
||||
var wasHmdMounted = safeGetHMDMounted();
|
||||
|
||||
function goAway() {
|
||||
if (isAway) {
|
||||
return;
|
||||
|
@ -169,12 +179,20 @@ function goAway() {
|
|||
playAwayAnimation(); // animation is still seen by others
|
||||
showOverlay();
|
||||
|
||||
// remember the View > Overlays state...
|
||||
wasOverlaysVisible = Menu.isOptionChecked("Overlays");
|
||||
|
||||
// show overlays so that people can see the "Away" message
|
||||
Menu.setIsOptionChecked("Overlays", true);
|
||||
|
||||
// tell the Reticle, we want to stop capturing the mouse until we come back
|
||||
Reticle.allowMouseCapture = false;
|
||||
if (HMD.active) {
|
||||
Reticle.visible = false;
|
||||
}
|
||||
wasHmdMounted = safeGetHMDMounted(); // always remember the correct state
|
||||
}
|
||||
|
||||
function goActive() {
|
||||
if (!isAway) {
|
||||
return;
|
||||
|
@ -188,12 +206,16 @@ function goActive() {
|
|||
stopAwayAnimation();
|
||||
hideOverlay();
|
||||
|
||||
// restore overlays state to what it was when we went "away"
|
||||
Menu.setIsOptionChecked("Overlays", wasOverlaysVisible);
|
||||
|
||||
// tell the Reticle, we are ready to capture the mouse again and it should be visible
|
||||
Reticle.allowMouseCapture = true;
|
||||
Reticle.visible = true;
|
||||
if (HMD.active) {
|
||||
Reticle.position = HMD.getHUDLookAtPosition2D();
|
||||
}
|
||||
wasHmdMounted = safeGetHMDMounted(); // always remember the correct state
|
||||
}
|
||||
|
||||
function maybeGoActive(event) {
|
||||
|
@ -206,6 +228,7 @@ function maybeGoActive(event) {
|
|||
goActive();
|
||||
}
|
||||
}
|
||||
|
||||
var wasHmdActive = HMD.active;
|
||||
var wasMouseCaptured = Reticle.mouseCaptured;
|
||||
|
||||
|
@ -225,6 +248,13 @@ function maybeGoAway() {
|
|||
goAway();
|
||||
}
|
||||
}
|
||||
|
||||
// If you've removed your HMD from your head, and we can detect it, we will also go away...
|
||||
var hmdMounted = safeGetHMDMounted();
|
||||
if (HMD.active && !hmdMounted && wasHmdMounted) {
|
||||
wasHmdMounted = hmdMounted;
|
||||
goAway();
|
||||
}
|
||||
}
|
||||
|
||||
Script.update.connect(maybeMoveOverlay);
|
||||
|
|
|
@ -21,7 +21,7 @@ var MINIMUM_DEPTH_ADJUST = 0.01;
|
|||
var NON_LINEAR_DIVISOR = 2;
|
||||
var MINIMUM_SEEK_DISTANCE = 0.01;
|
||||
|
||||
var lastMouseMove = Date.now();
|
||||
var lastMouseMoveOrClick = Date.now();
|
||||
var lastMouseX = Reticle.position.x;
|
||||
var lastMouseY = Reticle.position.y;
|
||||
var HIDE_STATIC_MOUSE_AFTER = 3000; // 3 seconds
|
||||
|
@ -32,6 +32,14 @@ var WEIGHTING = 1/20; // simple moving average over last 20 samples
|
|||
var ONE_MINUS_WEIGHTING = 1 - WEIGHTING;
|
||||
var AVERAGE_MOUSE_VELOCITY_FOR_SEEK_TO = 50;
|
||||
|
||||
function showReticleOnMouseClick() {
|
||||
Reticle.visible = true;
|
||||
lastMouseMoveOrClick = Date.now(); // move or click
|
||||
}
|
||||
|
||||
Controller.mousePressEvent.connect(showReticleOnMouseClick);
|
||||
Controller.mouseDoublePressEvent.connect(showReticleOnMouseClick);
|
||||
|
||||
Controller.mouseMoveEvent.connect(function(mouseEvent) {
|
||||
var now = Date.now();
|
||||
|
||||
|
@ -47,7 +55,7 @@ Controller.mouseMoveEvent.connect(function(mouseEvent) {
|
|||
if (HMD.active && !shouldSeekToLookAt && Reticle.allowMouseCapture) {
|
||||
var dx = Reticle.position.x - lastMouseX;
|
||||
var dy = Reticle.position.y - lastMouseY;
|
||||
var dt = Math.max(1, (now - lastMouseMove)); // mSecs since last mouse move
|
||||
var dt = Math.max(1, (now - lastMouseMoveOrClick)); // mSecs since last mouse move
|
||||
var mouseMoveDistance = Math.sqrt((dx*dx) + (dy*dy));
|
||||
var mouseVelocity = mouseMoveDistance / dt;
|
||||
averageMouseVelocity = (ONE_MINUS_WEIGHTING * averageMouseVelocity) + (WEIGHTING * mouseVelocity);
|
||||
|
@ -56,7 +64,7 @@ Controller.mouseMoveEvent.connect(function(mouseEvent) {
|
|||
}
|
||||
}
|
||||
}
|
||||
lastMouseMove = now;
|
||||
lastMouseMoveOrClick = now;
|
||||
lastMouseX = mouseEvent.x;
|
||||
lastMouseY = mouseEvent.y;
|
||||
});
|
||||
|
@ -94,7 +102,7 @@ function autoHideReticle() {
|
|||
// system overlay (like a window), then hide the reticle
|
||||
if (Reticle.visible && !Reticle.pointingAtSystemOverlay) {
|
||||
var now = Date.now();
|
||||
var timeSinceLastMouseMove = now - lastMouseMove;
|
||||
var timeSinceLastMouseMove = now - lastMouseMoveOrClick;
|
||||
if (timeSinceLastMouseMove > HIDE_STATIC_MOUSE_AFTER) {
|
||||
Reticle.visible = false;
|
||||
}
|
||||
|
|
|
@ -1237,7 +1237,7 @@
|
|||
|
||||
|
||||
<div class="section-header">
|
||||
<label>Spacial Properties</label>
|
||||
<label>Spatial Properties</label>
|
||||
</div>
|
||||
|
||||
<div class="property">
|
||||
|
|
96
examples/playTestSound.js
Normal file
96
examples/playTestSound.js
Normal file
|
@ -0,0 +1,96 @@
|
|||
//
|
||||
// playTestSound.js
|
||||
// examples
|
||||
//
|
||||
// Created by Philip Rosedale
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Creates an object in front of you that changes color and plays a light
|
||||
// at the start of a drum clip that loops. As you move away it will tell you in the
|
||||
// log how many meters you are from the source.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var sound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Drums/deepdrum1.wav");
|
||||
|
||||
var position = Vec3.sum(Vec3.sum(MyAvatar.position, { x: 0, y: 0.5, z: 0 }), Quat.getFront(MyAvatar.orientation));
|
||||
|
||||
var time;
|
||||
var soundPlaying = null;
|
||||
|
||||
var baseColor = { red: 100, green: 100, blue: 100 };
|
||||
var litColor = { red: 255, green: 100, blue: 0 };
|
||||
|
||||
var lightTime = 250;
|
||||
|
||||
var distance = 0.0;
|
||||
|
||||
// Create object for visual reference
|
||||
var box = Entities.addEntity({
|
||||
type: "Box",
|
||||
dimensions: { x: 0.25, y: 0.5, z: 0.25 },
|
||||
color: baseColor,
|
||||
position: position
|
||||
});
|
||||
|
||||
|
||||
function checkSound(deltaTime) {
|
||||
var started = false;
|
||||
if (!sound.downloaded) {
|
||||
return;
|
||||
}
|
||||
if (soundPlaying == null) {
|
||||
soundPlaying = Audio.playSound(sound, {
|
||||
position: position,
|
||||
volume: 1.0,
|
||||
loop: false } );
|
||||
started = true;
|
||||
} else if (!soundPlaying.isPlaying) {
|
||||
soundPlaying.restart();
|
||||
started = true;
|
||||
}
|
||||
if (started) {
|
||||
Entities.editEntity(box, { color: litColor });
|
||||
Entities.addEntity({
|
||||
type: "Light",
|
||||
intensity: 5.0,
|
||||
falloffRadius: 10.0,
|
||||
dimensions: {
|
||||
x: 40,
|
||||
y: 40,
|
||||
z: 40
|
||||
},
|
||||
position: Vec3.sum(position, { x: 0, y: 1, z: 0 }),
|
||||
color: litColor,
|
||||
lifetime: lightTime / 1000
|
||||
});
|
||||
Script.setTimeout(resetColor, lightTime);
|
||||
}
|
||||
var currentDistance = Vec3.distance(MyAvatar.position, position);
|
||||
if (Math.abs(currentDistance - distance) > 1.0) {
|
||||
print("Distance from source: " + currentDistance);
|
||||
distance = currentDistance;
|
||||
}
|
||||
}
|
||||
|
||||
function resetColor() {
|
||||
Entities.editEntity(box, { color: baseColor });
|
||||
}
|
||||
|
||||
|
||||
function scriptEnding() {
|
||||
Entities.deleteEntity(box);
|
||||
if (soundPlaying) {
|
||||
print("stop injector");
|
||||
soundPlaying.stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Connect a call back that happens every frame
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
Script.update.connect(checkSound);
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
// rapidProceduralChangeTest.js
|
||||
// examples/tests/rapidProceduralChange
|
||||
//
|
||||
// Created by Eric Levin on 3/9/2016.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// This test creates primitives with fragment shaders and rapidly updates its uniforms, as well as a skybox.
|
||||
// For the test to pass:
|
||||
// - The primitives (cube and sphere) should update at rate of update loop, cycling through red values.
|
||||
// - The skymap should do the same, although its periodicity may be different.
|
||||
//
|
||||
// Under the hood, the primitives are driven by a uniform, while the skymap is driven by a timer.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var orientation = Camera.getOrientation();
|
||||
orientation = Quat.safeEulerAngles(orientation);
|
||||
orientation.x = 0;
|
||||
orientation = Quat.fromVec3Degrees(orientation);
|
||||
|
||||
var centerUp = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(orientation)));
|
||||
centerUp.y += 0.5;
|
||||
var centerDown = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(orientation)));
|
||||
centerDown.y -= 0.5;
|
||||
|
||||
var ENTITY_SHADER_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/shaders/uniformTest.fs";
|
||||
var SKYBOX_SHADER_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/shaders/timerTest.fs";
|
||||
|
||||
var entityData = {
|
||||
ProceduralEntity: {
|
||||
shaderUrl: ENTITY_SHADER_URL,
|
||||
uniforms: { red: 0.0 }
|
||||
}
|
||||
};
|
||||
var skyboxData = {
|
||||
ProceduralEntity: {
|
||||
shaderUrl: SKYBOX_SHADER_URL,
|
||||
uniforms: { red: 0.0 }
|
||||
}
|
||||
};
|
||||
|
||||
var testBox = Entities.addEntity({
|
||||
type: "Box",
|
||||
dimensions: { x: 0.5, y: 0.5, z: 0.5 },
|
||||
position: centerUp,
|
||||
userData: JSON.stringify(entityData)
|
||||
});
|
||||
var testSphere = Entities.addEntity({
|
||||
type: "Sphere",
|
||||
dimensions: { x: 0.5, y: 0.5, z: 0.5 },
|
||||
position: centerDown,
|
||||
userData: JSON.stringify(entityData)
|
||||
});
|
||||
var testZone = Entities.addEntity({
|
||||
type: "Zone",
|
||||
dimensions: { x: 50, y: 50, z: 50 },
|
||||
position: MyAvatar.position,
|
||||
userData: JSON.stringify(skyboxData),
|
||||
backgroundMode: "skybox",
|
||||
skybox: { url: "http://kyoub.googlecode.com/svn/trunk/KYouB/textures/skybox_test.png" }
|
||||
});
|
||||
|
||||
|
||||
var currentTime = 0;
|
||||
|
||||
function update(deltaTime) {
|
||||
var red = (Math.sin(currentTime) + 1) / 2;
|
||||
entityData.ProceduralEntity.uniforms.red = red;
|
||||
skyboxData.ProceduralEntity.uniforms.red = red;
|
||||
entityEdit = { userData: JSON.stringify(entityData) };
|
||||
skyboxEdit = { userData: JSON.stringify(skyboxData) };
|
||||
|
||||
Entities.editEntity(testBox, entityEdit);
|
||||
Entities.editEntity(testSphere, entityEdit);
|
||||
Entities.editEntity(testZone, skyboxEdit);
|
||||
|
||||
currentTime += deltaTime;
|
||||
}
|
||||
|
||||
Script.update.connect(update);
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
|
||||
function cleanup() {
|
||||
Entities.deleteEntity(testBox);
|
||||
Entities.deleteEntity(testSphere);
|
||||
Entities.deleteEntity(testZone);
|
||||
}
|
||||
|
21
examples/tests/rapidProceduralChange/timerTest.fs
Normal file
21
examples/tests/rapidProceduralChange/timerTest.fs
Normal file
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// timerTest.fs
|
||||
// examples/tests/rapidProceduralChange
|
||||
//
|
||||
// Created by Eric Levin on 3/9/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// This fragment shader is designed to test the rapid changing of a uniform on the timer.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
|
||||
uniform float red;
|
||||
|
||||
vec3 getSkyboxColor() {
|
||||
float blue = red;
|
||||
blue = (cos(iGlobalTime) + 1) / 2;
|
||||
return vec3(1.0, 0.0, blue);
|
||||
}
|
||||
|
27
examples/tests/rapidProceduralChange/uniformTest.fs
Normal file
27
examples/tests/rapidProceduralChange/uniformTest.fs
Normal file
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// uniformTest.fs
|
||||
// examples/tests/rapidProceduralChange
|
||||
//
|
||||
// Created by Eric Levin on 3/9/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// This fragment shader is designed to test the rapid changing of a uniform.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
|
||||
uniform float red;
|
||||
|
||||
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||
fragColor = vec4(red, 0.0, 1.0, 1.0);
|
||||
}
|
||||
|
||||
vec4 getProceduralColor() {
|
||||
vec4 result;
|
||||
vec2 position = _position.xz;
|
||||
position += 0.5;
|
||||
mainImage(result, position * iWorldScale.xz);
|
||||
return result;
|
||||
}
|
||||
|
18
examples/tests/skybox/px.fs
Normal file
18
examples/tests/skybox/px.fs
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// px.fs
|
||||
// examples/tests/skybox
|
||||
//
|
||||
// Created by Zach Pomerantz on 3/10/2016
|
||||
// Copyright 2016 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
|
||||
|
||||
|
||||
vec3 getSkyboxColor() {
|
||||
float red = (cos(iGlobalTime) + 1) / 2;
|
||||
vec3 color = vec3(red, 1.0, 1.0);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
20
examples/tests/skybox/px_rgba.fs
Normal file
20
examples/tests/skybox/px_rgba.fs
Normal file
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// px_rgba.fs
|
||||
// examples/tests/skybox
|
||||
//
|
||||
// Created by Zach Pomerantz on 3/10/2016
|
||||
// Copyright 2016 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
|
||||
|
||||
|
||||
vec3 getSkyboxColor() {
|
||||
float red = (cos(iGlobalTime) + 1) / 2;
|
||||
vec3 color = vec3(red, 1.0, 1.0);
|
||||
|
||||
color *= skybox.color.rgb;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
22
examples/tests/skybox/px_tex.fs
Normal file
22
examples/tests/skybox/px_tex.fs
Normal file
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// px_rgba.fs
|
||||
// examples/tests/skybox
|
||||
//
|
||||
// Created by Zach Pomerantz on 3/10/2016
|
||||
// Copyright 2016 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
|
||||
|
||||
|
||||
vec3 getSkyboxColor() {
|
||||
float red = (cos(iGlobalTime) + 1) / 2;
|
||||
vec3 color = vec3(red, 1.0, 1.0);
|
||||
|
||||
vec3 coord = normalize(_normal);
|
||||
vec3 texel = texture(cubeMap, coord).rgb;
|
||||
color *= texel;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
24
examples/tests/skybox/px_tex_rgba.fs
Normal file
24
examples/tests/skybox/px_tex_rgba.fs
Normal file
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// px_rgba.fs
|
||||
// examples/tests/skybox
|
||||
//
|
||||
// Created by Zach Pomerantz on 3/10/2016
|
||||
// Copyright 2016 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
|
||||
|
||||
|
||||
vec3 getSkyboxColor() {
|
||||
float red = (cos(iGlobalTime) + 1) / 2;
|
||||
vec3 color = vec3(red, 1.0, 1.0);
|
||||
|
||||
vec3 coord = normalize(_normal);
|
||||
vec3 texel = texture(cubeMap, coord).rgb;
|
||||
color *= texel;
|
||||
|
||||
color *= skybox.color.rgb;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
83
examples/tests/skybox/skyboxTest.js
Normal file
83
examples/tests/skybox/skyboxTest.js
Normal file
|
@ -0,0 +1,83 @@
|
|||
// skyboxTest.js
|
||||
// examples/tests/skybox
|
||||
//
|
||||
// Created by Zach Pomerantz on 3/10/2016.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// This test cycles through different variations on the skybox with a mouseclick.
|
||||
// For the test to pass, you should observe the following cycle:
|
||||
// - Procedural skybox (no texture, no color)
|
||||
// - Procedural skybox (no texture, with color)
|
||||
// - Procedural skybox (with texture, no color)
|
||||
// - Procedural skybox (with texture, with color)
|
||||
// - Color skybox (no texture)
|
||||
// - Color skybox (with texture)
|
||||
// - Texture skybox (no color)
|
||||
//
|
||||
// As you run the test, descriptions of the expected rendered skybox will appear as overlays.
|
||||
//
|
||||
// NOTE: This does not test uniforms/textures applied to a procedural shader through userData.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var PX_URL = Script.resolvePath('px.fs');
|
||||
var PX_RGBA_URL = Script.resolvePath('px_rgba.fs');
|
||||
var PX_TEX_URL = Script.resolvePath('px_tex.fs');
|
||||
var PX_TEX_RGBA_URL = Script.resolvePath('px_tex_rgba.fs');
|
||||
|
||||
var TEX_URL = 'https://hifi-public.s3.amazonaws.com/alan/Playa/Skies/Test-Sky_out.png';
|
||||
var NO_TEX = '';
|
||||
|
||||
var COLOR = { red: 255, green: 0, blue: 255 };
|
||||
var NO_COLOR = { red: 0, green: 0, blue: 0 };
|
||||
|
||||
var data = { ProceduralEntity: { shaderUrl: PX_URL } };
|
||||
|
||||
var zone = Entities.addEntity({
|
||||
type: 'Zone',
|
||||
dimensions: { x: 50, y: 50, z: 50 },
|
||||
position: MyAvatar.position,
|
||||
backgroundMode: 'skybox'
|
||||
});
|
||||
var text = Overlays.addOverlay('text', {
|
||||
text: 'Click this box to advance tests; note that red value cycling means white->light blue',
|
||||
x: Window.innerWidth / 2 - 250, y: Window.innerHeight / 2 - 25,
|
||||
width: 500, height: 50
|
||||
});
|
||||
|
||||
print('Zone:', zone);
|
||||
print('Text:', text);
|
||||
|
||||
var edits = [
|
||||
['Red value should cycle', getEdit(PX_URL, NO_TEX, NO_COLOR)],
|
||||
['Red value should cycle, no green', getEdit(PX_RGBA_URL, NO_TEX, COLOR)],
|
||||
['Red value should cycle, each face tinted differently', getEdit(PX_TEX_URL, TEX_URL, NO_COLOR)],
|
||||
['Red value should cycle, each face tinted differently, no green', getEdit(PX_TEX_RGBA_URL, TEX_URL, COLOR)],
|
||||
['No green', getEdit(null, NO_TEX, COLOR)],
|
||||
['Each face colored differently, no green', getEdit(null, TEX_URL, COLOR)],
|
||||
['Each face colored differently', getEdit(null, TEX_URL, NO_COLOR)],
|
||||
];
|
||||
|
||||
Controller.mousePressEvent.connect(function(e) { if (Overlays.getOverlayAtPoint(e) === text) next(); });
|
||||
|
||||
Script.scriptEnding.connect(function() {
|
||||
Overlays.deleteOverlay(text);
|
||||
Entities.deleteEntity(zone);
|
||||
});
|
||||
|
||||
var i = 0;
|
||||
function next() {
|
||||
var edit = edits[i];
|
||||
Overlays.editOverlay(text, { text: edit[0] });
|
||||
Entities.editEntity(zone, edit[1]);
|
||||
i++;
|
||||
i %= edits.length;
|
||||
}
|
||||
|
||||
function getEdit(px, url, color) {
|
||||
return { userData: px ? getUserData(px) : '', backgroundMode: 'skybox', skybox: { url: url, color: color } }
|
||||
}
|
||||
function getUserData(px) { return JSON.stringify({ ProceduralEntity: { shaderUrl: px } }); }
|
||||
|
|
@ -1,3 +1,13 @@
|
|||
//
|
||||
// MessageDialog.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 18 Jan 2016
|
||||
// Copyright 2016 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
|
||||
|
@ -94,8 +104,8 @@ Item {
|
|||
|
||||
function buildMenu(items, targetPosition) {
|
||||
var model = toModel(items);
|
||||
// Menu's must be childed to desktop for Z-ordering
|
||||
var newMenu = menuViewMaker.createObject(desktop, { model: model, z: topMenu ? topMenu.z + 1 : desktop.zLevels.menu });
|
||||
// Menus must be childed to desktop for Z-ordering
|
||||
var newMenu = menuViewMaker.createObject(desktop, { model: model, z: topMenu ? topMenu.z + 1 : desktop.zLevels.menu, isSubMenu: topMenu !== null });
|
||||
if (targetPosition) {
|
||||
newMenu.x = targetPosition.x
|
||||
newMenu.y = targetPosition.y - newMenu.height / 3 * 1
|
||||
|
|
|
@ -1,9 +1,19 @@
|
|||
import QtQuick 2.4
|
||||
import QtQuick.Controls 1.3
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
//
|
||||
// VrMenuItem.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 29 Apr 2015
|
||||
// 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
|
||||
//
|
||||
|
||||
import "../controls"
|
||||
import "../styles"
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
import "../controls-uit"
|
||||
import "../styles-uit"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
@ -11,54 +21,93 @@ Item {
|
|||
property alias text: label.text
|
||||
property var source
|
||||
|
||||
implicitHeight: source.visible ? label.implicitHeight * 1.5 : 0
|
||||
implicitWidth: label.width + label.height * 2.5
|
||||
implicitHeight: source.visible ? 2 * label.implicitHeight : 0
|
||||
implicitWidth: 2 * hifi.dimensions.menuPadding.x + check.width + label.width + tail.width
|
||||
visible: source.visible
|
||||
width: parent.width
|
||||
|
||||
FontAwesome {
|
||||
clip: true
|
||||
CheckBox {
|
||||
id: check
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: label.color
|
||||
text: checkText()
|
||||
size: label.height
|
||||
visible: source.visible
|
||||
font.pixelSize: size
|
||||
function checkText() {
|
||||
if (!source || source.type != 1 || !source.checkable) {
|
||||
return ""
|
||||
// FIXME: Should use radio buttons if source.exclusiveGroup.
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: hifi.dimensions.menuPadding.x
|
||||
top: label.top
|
||||
topMargin: 0
|
||||
}
|
||||
width: 20
|
||||
visible: source.visible && source.type === 1 && source.checkable
|
||||
checked: setChecked()
|
||||
function setChecked() {
|
||||
if (!source || source.type !== 1 || !source.checkable) {
|
||||
return false;
|
||||
}
|
||||
// FIXME this works for native QML menus but I don't think it will
|
||||
// for proxied QML menus
|
||||
if (source.exclusiveGroup) {
|
||||
return source.checked ? "\uF05D" : "\uF10C"
|
||||
}
|
||||
return source.checked ? "\uF046" : "\uF096"
|
||||
return source.checked;
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
RalewaySemiBold {
|
||||
id: label
|
||||
size: hifi.fontSizes.rootMenu
|
||||
font.capitalization: isSubMenu ? Font.MixedCase : Font.AllUppercase
|
||||
anchors.left: check.right
|
||||
anchors.leftMargin: 4
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: source.enabled ? hifi.colors.text : hifi.colors.disabledText
|
||||
color: source.enabled ? hifi.colors.baseGrayShadow : hifi.colors.baseGrayShadow50
|
||||
enabled: source.visible && (source.type !== 0 ? source.enabled : false)
|
||||
visible: source.visible
|
||||
}
|
||||
|
||||
FontAwesome {
|
||||
id: tag
|
||||
x: root.parent.width - width
|
||||
size: label.height
|
||||
width: implicitWidth
|
||||
visible: source.visible && (source.type == 2)
|
||||
text: "\uF0DA"
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: label.color
|
||||
Item {
|
||||
id: separator
|
||||
anchors {
|
||||
fill: parent
|
||||
leftMargin: hifi.dimensions.menuPadding.x + check.width
|
||||
rightMargin: hifi.dimensions.menuPadding.x + tail.width
|
||||
}
|
||||
visible: source.type === MenuItemType.Separator
|
||||
|
||||
Rectangle {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
height: 1
|
||||
color: hifi.colors.lightGray50
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: tail
|
||||
width: 48 + (shortcut.visible ? shortcut.width : 0)
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
right: parent.right
|
||||
rightMargin: hifi.dimensions.menuPadding.x
|
||||
}
|
||||
|
||||
RalewayLight {
|
||||
id: shortcut
|
||||
text: source.shortcut ? source.shortcut : ""
|
||||
size: hifi.fontSizes.shortcutText
|
||||
color: hifi.colors.baseGrayShadow
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 15
|
||||
visible: source.visible && text != ""
|
||||
}
|
||||
|
||||
HiFiGlyphs {
|
||||
text: hifi.glyphs.disclosureExpand
|
||||
color: source.enabled ? hifi.colors.baseGrayShadow : hifi.colors.baseGrayShadow25
|
||||
size: 2 * hifi.fontSizes.rootMenuDisclosure
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
horizontalAlignment: Text.AlignRight
|
||||
visible: source.visible && (source.type === 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,44 +1,59 @@
|
|||
import QtQuick 2.4
|
||||
import QtQuick.Controls 1.3
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
//
|
||||
// VrMenuView.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 18 Jan 2016
|
||||
// Copyright 2016 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
|
||||
//
|
||||
|
||||
import "../styles"
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
import "../styles-uit"
|
||||
|
||||
FocusScope {
|
||||
id: root
|
||||
implicitHeight: border.height
|
||||
implicitWidth: border.width
|
||||
implicitHeight: background.height
|
||||
implicitWidth: background.width
|
||||
|
||||
property alias currentItem: listView.currentItem
|
||||
property alias model: listView.model
|
||||
property bool isSubMenu: false
|
||||
signal selected(var item)
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
Border {
|
||||
id: border
|
||||
Rectangle {
|
||||
id: background
|
||||
anchors.fill: listView
|
||||
anchors.margins: -8
|
||||
border.color: hifi.colors.hifiBlue
|
||||
color: hifi.colors.window
|
||||
// color: "#7f7f7f7f"
|
||||
radius: hifi.dimensions.borderRadius
|
||||
border.width: hifi.dimensions.borderWidth
|
||||
border.color: hifi.colors.lightGrayText80
|
||||
color: isSubMenu ? hifi.colors.faintGray : hifi.colors.faintGray80
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
x: 8; y: 8
|
||||
HifiConstants { id: hifi }
|
||||
width: 128
|
||||
height: count * 32
|
||||
topMargin: hifi.dimensions.menuPadding.y
|
||||
onEnabledChanged: recalcSize();
|
||||
onVisibleChanged: recalcSize();
|
||||
onCountChanged: recalcSize();
|
||||
focus: true
|
||||
|
||||
highlight: Rectangle {
|
||||
width: listView.currentItem ? listView.currentItem.width : 0
|
||||
height: listView.currentItem ? listView.currentItem.height : 0
|
||||
color: "lightsteelblue"; radius: 3
|
||||
anchors {
|
||||
left: parent ? parent.left : undefined
|
||||
right: parent ? parent.right : undefined
|
||||
leftMargin: hifi.dimensions.borderWidth
|
||||
rightMargin: hifi.dimensions.borderWidth
|
||||
}
|
||||
color: hifi.colors.white
|
||||
}
|
||||
|
||||
delegate: VrMenuItem {
|
||||
|
@ -75,6 +90,7 @@ FocusScope {
|
|||
newHeight += currentItem.implicitHeight
|
||||
}
|
||||
}
|
||||
newHeight += 2 * hifi.dimensions.menuPadding.y; // White space at top and bottom.
|
||||
if (maxWidth > width) {
|
||||
width = maxWidth;
|
||||
}
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
//
|
||||
// FontAwesome.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 24 Apr 2015
|
||||
// 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
Text {
|
||||
id: root
|
||||
FontLoader { id: iconFont; source: "../../fonts/fontawesome-webfont.ttf"; }
|
||||
property int size: 32
|
||||
width: size
|
||||
height: size
|
||||
font.pixelSize: size
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
font.family: iconFont.name
|
||||
}
|
||||
|
|
@ -67,9 +67,13 @@ Item {
|
|||
readonly property color darkGray30: "#4d121212"
|
||||
readonly property color darkGray0: "#00121212"
|
||||
readonly property color baseGrayShadow60: "#99252525"
|
||||
readonly property color baseGrayShadow50: "#80252525"
|
||||
readonly property color baseGrayShadow25: "#40252525"
|
||||
readonly property color baseGrayHighlight40: "#66575757"
|
||||
readonly property color baseGrayHighlight15: "#26575757"
|
||||
readonly property color lightGray50: "#806a6a6a"
|
||||
readonly property color lightGrayText80: "#ccafafaf"
|
||||
readonly property color faintGray80: "#cce3e3e3"
|
||||
readonly property color faintGray50: "#80e3e3e3"
|
||||
|
||||
// Other colors
|
||||
|
@ -135,6 +139,7 @@ Item {
|
|||
readonly property real modalDialogTitleHeight: 40
|
||||
readonly property real controlLineHeight: 29 // Height of spinbox control on 1920 x 1080 monitor
|
||||
readonly property real controlInterlineHeight: 22 // 75% of controlLineHeight
|
||||
readonly property vector2d menuPadding: Qt.vector2d(14, 12)
|
||||
}
|
||||
|
||||
Item {
|
||||
|
@ -152,6 +157,7 @@ Item {
|
|||
readonly property real logs: dimensions.largeScreen ? 16 : 12
|
||||
readonly property real code: dimensions.largeScreen ? 16 : 12
|
||||
readonly property real rootMenu: dimensions.largeScreen ? 15 : 11
|
||||
readonly property real rootMenuDisclosure: dimensions.largeScreen ? 20 : 16
|
||||
readonly property real menuItem: dimensions.largeScreen ? 15 : 11
|
||||
readonly property real shortcutText: dimensions.largeScreen ? 13 : 9
|
||||
readonly property real carat: dimensions.largeScreen ? 38 : 30
|
||||
|
|
|
@ -3179,7 +3179,6 @@ void Application::update(float deltaTime) {
|
|||
|
||||
auto myAvatar = getMyAvatar();
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
userInputMapper->update(deltaTime);
|
||||
|
||||
controller::InputCalibrationData calibrationData = {
|
||||
myAvatar->getSensorToWorldMatrix(),
|
||||
|
@ -3187,9 +3186,12 @@ void Application::update(float deltaTime) {
|
|||
myAvatar->getHMDSensorMatrix()
|
||||
};
|
||||
|
||||
InputPluginPointer keyboardMousePlugin;
|
||||
bool jointsCaptured = false;
|
||||
for (auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) {
|
||||
if (inputPlugin->isActive()) {
|
||||
if (inputPlugin->getName() == KeyboardMouseDevice::NAME) {
|
||||
keyboardMousePlugin = inputPlugin;
|
||||
} else if (inputPlugin->isActive()) {
|
||||
inputPlugin->pluginUpdate(deltaTime, calibrationData, jointsCaptured);
|
||||
if (inputPlugin->isJointController()) {
|
||||
jointsCaptured = true;
|
||||
|
@ -3197,6 +3199,12 @@ void Application::update(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
userInputMapper->update(deltaTime);
|
||||
|
||||
if (keyboardMousePlugin && keyboardMousePlugin->isActive()) {
|
||||
keyboardMousePlugin->pluginUpdate(deltaTime, calibrationData, jointsCaptured);
|
||||
}
|
||||
|
||||
_controllerScriptingInterface->updateInputControllers();
|
||||
|
||||
// Transfer the user inputs to the driveKeys
|
||||
|
@ -3216,16 +3224,14 @@ void Application::update(float deltaTime) {
|
|||
myAvatar->setDriveKeys(ZOOM, userInputMapper->getActionState(controller::Action::TRANSLATE_CAMERA_Z));
|
||||
}
|
||||
|
||||
controller::Pose leftHand = userInputMapper->getPoseState(controller::Action::LEFT_HAND);
|
||||
controller::Pose rightHand = userInputMapper->getPoseState(controller::Action::RIGHT_HAND);
|
||||
Hand* hand = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHand();
|
||||
setPalmData(hand, leftHand, deltaTime, HandData::LeftHand, userInputMapper->getActionState(controller::Action::LEFT_HAND_CLICK));
|
||||
setPalmData(hand, rightHand, deltaTime, HandData::RightHand, userInputMapper->getActionState(controller::Action::RIGHT_HAND_CLICK));
|
||||
controller::Pose leftHandPose = userInputMapper->getPoseState(controller::Action::LEFT_HAND);
|
||||
controller::Pose rightHandPose = userInputMapper->getPoseState(controller::Action::RIGHT_HAND);
|
||||
auto myAvatarMatrix = createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition());
|
||||
myAvatar->setHandControllerPosesInWorldFrame(leftHandPose.transform(myAvatarMatrix), rightHandPose.transform(myAvatarMatrix));
|
||||
|
||||
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
|
||||
updateDialogs(deltaTime); // update various stats dialogs if present
|
||||
|
||||
_avatarUpdate->synchronousProcess();
|
||||
|
||||
if (_physicsEnabled) {
|
||||
PerformanceTimer perfTimer("physics");
|
||||
AvatarManager* avatarManager = DependencyManager::get<AvatarManager>().data();
|
||||
|
@ -3297,6 +3303,8 @@ void Application::update(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
_avatarUpdate->synchronousProcess();
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("overlays");
|
||||
_overlays.update(deltaTime);
|
||||
|
@ -3757,19 +3765,19 @@ namespace render {
|
|||
switch (backgroundMode) {
|
||||
case model::SunSkyStage::SKY_BOX: {
|
||||
auto skybox = skyStage->getSkybox();
|
||||
if (skybox && skybox->getCubemap() && skybox->getCubemap()->isDefined()) {
|
||||
if (skybox) {
|
||||
PerformanceTimer perfTimer("skybox");
|
||||
skybox->render(batch, *(args->_viewFrustum));
|
||||
break;
|
||||
}
|
||||
// If no skybox texture is available, render the SKY_DOME while it loads
|
||||
}
|
||||
// fall through to next case
|
||||
|
||||
// Fall through: if no skybox is available, render the SKY_DOME
|
||||
case model::SunSkyStage::SKY_DOME: {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Stars)) {
|
||||
PerformanceTimer perfTimer("stars");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::payloadRender<BackgroundRenderData>() ... stars...");
|
||||
"Application::payloadRender<BackgroundRenderData>() ... My god, it's full of stars...");
|
||||
// should be the first rendering pass - w/o depth buffer / lighting
|
||||
|
||||
static const float alpha = 1.0f;
|
||||
|
@ -3777,6 +3785,7 @@ namespace render {
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case model::SunSkyStage::NO_BACKGROUND:
|
||||
default:
|
||||
// this line intentionally left blank
|
||||
|
@ -4982,49 +4991,6 @@ mat4 Application::getHMDSensorPose() const {
|
|||
return mat4();
|
||||
}
|
||||
|
||||
void Application::setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, HandData::Hand whichHand, float triggerValue) {
|
||||
|
||||
// NOTE: the Hand::modifyPalm() will allow the lambda to modify the palm data while ensuring some other user isn't
|
||||
// reading or writing to the Palms. This is definitely not the best way of handling this, and I'd like to see more
|
||||
// of this palm manipulation in the Hand class itself. But unfortunately the Hand and Palm don't knbow about
|
||||
// controller::Pose. More work is needed to clean this up.
|
||||
hand->modifyPalm(whichHand, [&](PalmData& palm) {
|
||||
palm.setActive(pose.isValid());
|
||||
|
||||
// controller pose is in Avatar frame.
|
||||
glm::vec3 position = pose.getTranslation();
|
||||
glm::quat rotation = pose.getRotation();
|
||||
glm::vec3 rawVelocity = pose.getVelocity();
|
||||
glm::vec3 angularVelocity = pose.getAngularVelocity();
|
||||
|
||||
palm.setRawVelocity(rawVelocity);
|
||||
palm.setRawAngularVelocity(angularVelocity);
|
||||
|
||||
if (controller::InputDevice::getLowVelocityFilter()) {
|
||||
// Use a velocity sensitive filter to damp small motions and preserve large ones with
|
||||
// no latency.
|
||||
float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f);
|
||||
position = palm.getRawPosition() * velocityFilter + position * (1.0f - velocityFilter);
|
||||
rotation = safeMix(palm.getRawRotation(), rotation, 1.0f - velocityFilter);
|
||||
}
|
||||
palm.setRawPosition(position);
|
||||
palm.setRawRotation(rotation);
|
||||
|
||||
// Store the one fingertip in the palm structure so we can track velocity
|
||||
const float FINGER_LENGTH = 0.3f; // meters
|
||||
const glm::vec3 FINGER_VECTOR(0.0f, FINGER_LENGTH, 0.0f);
|
||||
const glm::vec3 newTipPosition = position + rotation * FINGER_VECTOR;
|
||||
glm::vec3 oldTipPosition = palm.getTipRawPosition();
|
||||
if (deltaTime > 0.0f) {
|
||||
palm.setTipVelocity((newTipPosition - oldTipPosition) / deltaTime);
|
||||
} else {
|
||||
palm.setTipVelocity(glm::vec3(0.0f));
|
||||
}
|
||||
palm.setTipPosition(newTipPosition);
|
||||
palm.setTrigger(triggerValue); // FIXME - we want to get rid of this idea of PalmData having a trigger
|
||||
});
|
||||
}
|
||||
|
||||
void Application::crashApplication() {
|
||||
qCDebug(interfaceapp) << "Intentionally crashed Interface";
|
||||
QObject* object = nullptr;
|
||||
|
|
|
@ -299,7 +299,7 @@ private slots:
|
|||
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
|
||||
|
||||
bool acceptSnapshot(const QString& urlString);
|
||||
bool askToSetAvatarUrl(const QString& url);
|
||||
bool askToLoadScript(const QString& scriptFilenameOrURL);
|
||||
|
@ -327,8 +327,6 @@ private:
|
|||
|
||||
void update(float deltaTime);
|
||||
|
||||
void setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, HandData::Hand whichHand, float triggerValue);
|
||||
|
||||
// Various helper functions called during update()
|
||||
void updateLOD();
|
||||
void updateThreads(float deltaTime);
|
||||
|
|
|
@ -481,7 +481,8 @@ Menu::Menu() {
|
|||
|
||||
// Developer > Hands >>>
|
||||
MenuWrapper* handOptionsMenu = developerMenu->addMenu("Hands");
|
||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false,
|
||||
avatar, SLOT(setEnableDebugDrawHandControllers(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::LowVelocityFilter, 0, true,
|
||||
qApp, SLOT(setLowVelocityFilter(bool)));
|
||||
|
||||
|
|
|
@ -22,11 +22,11 @@
|
|||
#include <RenderArgs.h>
|
||||
#include <ViewFrustum.h>
|
||||
|
||||
#include <stars_vert.h>
|
||||
#include <stars_frag.h>
|
||||
#include <render-utils/stars_vert.h>
|
||||
#include <render-utils/stars_frag.h>
|
||||
|
||||
#include <standardTransformPNTC_vert.h>
|
||||
#include <starsGrid_frag.h>
|
||||
#include <render-utils/standardTransformPNTC_vert.h>
|
||||
#include <render-utils/starsGrid_frag.h>
|
||||
|
||||
//static const float TILT = 0.23f;
|
||||
static const float TILT = 0.0f;
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include "Avatar.h"
|
||||
#include "AvatarManager.h"
|
||||
#include "AvatarMotionState.h"
|
||||
#include "Hand.h"
|
||||
#include "Head.h"
|
||||
#include "Menu.h"
|
||||
#include "Physics.h"
|
||||
|
@ -101,7 +100,6 @@ Avatar::Avatar(RigPointer rig) :
|
|||
|
||||
// give the pointer to our head to inherited _headData variable from AvatarData
|
||||
_headData = static_cast<HeadData*>(new Head(this));
|
||||
_handData = static_cast<HandData*>(new Hand(this));
|
||||
}
|
||||
|
||||
Avatar::~Avatar() {
|
||||
|
@ -190,11 +188,6 @@ void Avatar::simulate(float deltaTime) {
|
|||
float boundingRadius = getBoundingRadius();
|
||||
bool inView = qApp->getViewFrustum()->sphereIntersectsFrustum(getPosition(), boundingRadius);
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("hand");
|
||||
getHand()->simulate(deltaTime, false);
|
||||
}
|
||||
|
||||
if (_shouldAnimate && !_shouldSkipRender && inView) {
|
||||
{
|
||||
PerformanceTimer perfTimer("skeleton");
|
||||
|
@ -578,11 +571,6 @@ void Avatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, floa
|
|||
if (_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable()) {
|
||||
getHead()->render(renderArgs, 1.0f, renderFrustum);
|
||||
}
|
||||
|
||||
if (renderArgs->_renderMode != RenderArgs::SHADOW_RENDER_MODE &&
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::DisplayHandTargets)) {
|
||||
getHand()->renderHandTargets(renderArgs, false);
|
||||
}
|
||||
}
|
||||
getHead()->renderLookAts(renderArgs);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
|
||||
#include <render/Scene.h>
|
||||
|
||||
#include "Hand.h"
|
||||
#include "Head.h"
|
||||
#include "SkeletonModel.h"
|
||||
#include "world.h"
|
||||
|
@ -91,7 +90,7 @@ public:
|
|||
float getUniformScale() const { return getScale().y; }
|
||||
const Head* getHead() const { return static_cast<const Head*>(_headData); }
|
||||
Head* getHead() { return static_cast<Head*>(_headData); }
|
||||
Hand* getHand() { return static_cast<Hand*>(_handData); }
|
||||
|
||||
glm::quat getWorldAlignedOrientation() const;
|
||||
|
||||
AABox getBounds() const;
|
||||
|
|
|
@ -104,48 +104,57 @@ std::shared_ptr<Avatar> AvatarActionHold::getTarget(float deltaTimeStep, glm::qu
|
|||
|
||||
withReadLock([&]{
|
||||
bool isRightHand = (_hand == "right");
|
||||
|
||||
glm::vec3 palmPosition;
|
||||
glm::quat palmRotation;
|
||||
|
||||
PalmData palmData = holdingAvatar->getHand()->getCopyOfPalmData(isRightHand ? HandData::RightHand : HandData::LeftHand);
|
||||
|
||||
if (palmData.isValid()) {
|
||||
// TODO: adjust according to _relativePosition and _relativeRotation?
|
||||
linearVelocity = palmData.getVelocity();
|
||||
angularVelocity = palmData.getAngularVelocity();
|
||||
}
|
||||
|
||||
if (_ignoreIK && holdingAvatar->isMyAvatar() && palmData.isValid()) {
|
||||
// We cannot ignore other avatars IK and this is not the point of this option
|
||||
// This is meant to make the grabbing behavior more reactive.
|
||||
palmPosition = palmData.getPosition();
|
||||
palmRotation = palmData.getRotation();
|
||||
} else if (holdingAvatar->isMyAvatar()) {
|
||||
glm::vec3 avatarRigidBodyPosition;
|
||||
glm::quat avatarRigidBodyRotation;
|
||||
getAvatarRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation);
|
||||
|
||||
// the offset and rotation between the avatar's rigid body and the palm were determined earlier
|
||||
// in prepareForPhysicsSimulation. At this point, the avatar's rigid body has been moved by bullet
|
||||
// and the data in the Avatar class is stale. This means that the result of get*PalmPosition will
|
||||
// be stale. Instead, determine the current palm position with the current avatar's rigid body
|
||||
// location and the saved offsets.
|
||||
|
||||
// this line is more correct but breaks for the current way avatar data is updated.
|
||||
// palmPosition = avatarRigidBodyPosition + avatarRigidBodyRotation * _palmOffsetFromRigidBody;
|
||||
// instead, use this for now:
|
||||
palmPosition = avatarRigidBodyPosition + _palmOffsetFromRigidBody;
|
||||
|
||||
// the item jitters the least by getting the rotation based on the opinion of Avatar.h rather
|
||||
// than that of the rigid body. leaving this next line here for future reference:
|
||||
// palmRotation = avatarRigidBodyRotation * _palmRotationFromRigidBody;
|
||||
if (holdingAvatar->isMyAvatar()) {
|
||||
|
||||
// fetch the hand controller pose
|
||||
controller::Pose pose;
|
||||
if (isRightHand) {
|
||||
palmRotation = holdingAvatar->getRightPalmRotation();
|
||||
pose = avatarManager->getMyAvatar()->getRightHandControllerPoseInWorldFrame();
|
||||
} else {
|
||||
palmRotation = holdingAvatar->getLeftPalmRotation();
|
||||
pose = avatarManager->getMyAvatar()->getLeftHandControllerPoseInWorldFrame();
|
||||
}
|
||||
} else {
|
||||
|
||||
if (pose.isValid()) {
|
||||
linearVelocity = pose.getVelocity();
|
||||
angularVelocity = pose.getAngularVelocity();
|
||||
}
|
||||
|
||||
if (_ignoreIK && pose.isValid()) {
|
||||
// We cannot ignore other avatars IK and this is not the point of this option
|
||||
// This is meant to make the grabbing behavior more reactive.
|
||||
palmPosition = pose.getTranslation();
|
||||
palmRotation = pose.getRotation();
|
||||
} else {
|
||||
glm::vec3 avatarRigidBodyPosition;
|
||||
glm::quat avatarRigidBodyRotation;
|
||||
getAvatarRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation);
|
||||
|
||||
// the offset and rotation between the avatar's rigid body and the palm were determined earlier
|
||||
// in prepareForPhysicsSimulation. At this point, the avatar's rigid body has been moved by bullet
|
||||
// and the data in the Avatar class is stale. This means that the result of get*PalmPosition will
|
||||
// be stale. Instead, determine the current palm position with the current avatar's rigid body
|
||||
// location and the saved offsets.
|
||||
|
||||
// this line is more correct but breaks for the current way avatar data is updated.
|
||||
// palmPosition = avatarRigidBodyPosition + avatarRigidBodyRotation * _palmOffsetFromRigidBody;
|
||||
// instead, use this for now:
|
||||
palmPosition = avatarRigidBodyPosition + _palmOffsetFromRigidBody;
|
||||
|
||||
// the item jitters the least by getting the rotation based on the opinion of Avatar.h rather
|
||||
// than that of the rigid body. leaving this next line here for future reference:
|
||||
// palmRotation = avatarRigidBodyRotation * _palmRotationFromRigidBody;
|
||||
|
||||
if (isRightHand) {
|
||||
palmRotation = holdingAvatar->getRightPalmRotation();
|
||||
} else {
|
||||
palmRotation = holdingAvatar->getLeftPalmRotation();
|
||||
}
|
||||
}
|
||||
} else { // regular avatar
|
||||
if (isRightHand) {
|
||||
palmPosition = holdingAvatar->getRightPalmPosition();
|
||||
palmRotation = holdingAvatar->getRightPalmRotation();
|
||||
|
|
|
@ -1,101 +0,0 @@
|
|||
//
|
||||
// Hand.cpp
|
||||
// interface/src/avatar
|
||||
//
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Hand.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <GeometryUtil.h>
|
||||
#include <RenderArgs.h>
|
||||
|
||||
#include "Avatar.h"
|
||||
#include "AvatarManager.h"
|
||||
#include "MyAvatar.h"
|
||||
#include "Util.h"
|
||||
#include "world.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
Hand::Hand(Avatar* owningAvatar) :
|
||||
HandData((AvatarData*)owningAvatar),
|
||||
_owningAvatar(owningAvatar)
|
||||
{
|
||||
}
|
||||
|
||||
void Hand::simulate(float deltaTime, bool isMine) {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) {
|
||||
float avatarScale = 1.0f;
|
||||
if (_owningAvatar) {
|
||||
avatarScale = _owningAvatar->getUniformScale();
|
||||
}
|
||||
|
||||
const float alpha = 1.0f;
|
||||
const glm::vec3 redColor(1.0f, 0.0f, 0.0f); // Color the hand targets red to be different than skin
|
||||
const glm::vec3 greenColor(0.0f, 1.0f, 0.0f); // Color the hand targets red to be different than skin
|
||||
const glm::vec3 blueColor(0.0f, 0.0f, 1.0f); // Color the hand targets red to be different than skin
|
||||
const glm::vec3 grayColor(0.5f);
|
||||
const float SPHERE_RADIUS = 0.03f * avatarScale;
|
||||
|
||||
auto palms = getCopyOfPalms();
|
||||
|
||||
gpu::Batch& batch = *renderArgs->_batch;
|
||||
if (isMine) {
|
||||
for (const auto& palm : palms) {
|
||||
if (!palm.isActive()) {
|
||||
continue;
|
||||
}
|
||||
// draw a gray sphere at the target position of the "Hand" joint
|
||||
glm::vec3 position = palm.getPosition();
|
||||
Transform transform = Transform();
|
||||
transform.setTranslation(position);
|
||||
transform.setRotation(palm.getRotation());
|
||||
transform.postScale(SPHERE_RADIUS);
|
||||
batch.setModelTransform(transform);
|
||||
DependencyManager::get<GeometryCache>()->renderSolidSphereInstance(batch, grayColor);
|
||||
|
||||
// draw a green sphere at the old "finger tip"
|
||||
transform = Transform();
|
||||
position = palm.getTipPosition();
|
||||
transform.setTranslation(position);
|
||||
transform.setRotation(palm.getRotation());
|
||||
transform.postScale(SPHERE_RADIUS);
|
||||
batch.setModelTransform(transform);
|
||||
DependencyManager::get<GeometryCache>()->renderSolidSphereInstance(batch, greenColor);
|
||||
}
|
||||
}
|
||||
|
||||
const float AXIS_RADIUS = 0.1f * SPHERE_RADIUS;
|
||||
const float AXIS_LENGTH = 10.0f * SPHERE_RADIUS;
|
||||
|
||||
// Draw the coordinate frames of the hand targets
|
||||
for (const auto& palm : palms) {
|
||||
if (palm.isActive()) {
|
||||
glm::vec3 root = palm.getPosition();
|
||||
|
||||
const glm::vec3 yAxis(0.0f, 1.0f, 0.0f);
|
||||
glm::quat palmRotation = palm.getRotation();
|
||||
Transform transform = Transform();
|
||||
transform.setTranslation(glm::vec3());
|
||||
batch.setModelTransform(transform);
|
||||
glm::vec3 tip = root + palmRotation * glm::vec3(AXIS_LENGTH, 0.0f, 0.0f);
|
||||
Avatar::renderJointConnectingCone(batch, root, tip, AXIS_RADIUS, AXIS_RADIUS, glm::vec4(redColor.r, redColor.g, redColor.b, alpha));
|
||||
|
||||
tip = root + palmRotation * glm::vec3(0.0f, AXIS_LENGTH, 0.0f);
|
||||
Avatar::renderJointConnectingCone(batch, root, tip, AXIS_RADIUS, AXIS_RADIUS, glm::vec4(greenColor.r, greenColor.g, greenColor.b, alpha));
|
||||
|
||||
tip = root + palmRotation * glm::vec3(0.0f, 0.0f, AXIS_LENGTH);
|
||||
Avatar::renderJointConnectingCone(batch, root, tip, AXIS_RADIUS, AXIS_RADIUS, glm::vec4(blueColor.r, blueColor.g, blueColor.b, alpha));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
//
|
||||
// Hand.h
|
||||
// interface/src/avatar
|
||||
//
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_Hand_h
|
||||
#define hifi_Hand_h
|
||||
|
||||
#include <HandData.h>
|
||||
|
||||
class Avatar;
|
||||
class RenderArgs;
|
||||
|
||||
class Hand : public HandData {
|
||||
public:
|
||||
Hand(Avatar* owningAvatar);
|
||||
|
||||
void simulate(float deltaTime, bool isMine);
|
||||
void renderHandTargets(RenderArgs* renderArgs, bool isMine);
|
||||
|
||||
private:
|
||||
// disallow copies of the Hand, copy of owning Avatar is disallowed too
|
||||
Hand(const Hand&);
|
||||
Hand& operator= (const Hand&);
|
||||
|
||||
int _controllerButtons; /// Button states read from hand-held controllers
|
||||
|
||||
Avatar* _owningAvatar;
|
||||
};
|
||||
|
||||
#endif // hifi_Hand_h
|
|
@ -341,12 +341,6 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
updatePosition(deltaTime);
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("hand");
|
||||
// update avatar skeleton and simulate hand and head
|
||||
getHand()->simulate(deltaTime, true);
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("skeleton");
|
||||
_skeletonModel.simulate(deltaTime);
|
||||
|
@ -522,49 +516,50 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
|
|||
-MAX_LEAN, MAX_LEAN));
|
||||
}
|
||||
|
||||
|
||||
glm::vec3 MyAvatar::getLeftHandPosition() const {
|
||||
auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand);
|
||||
return palmData.isValid() ? palmData.getPosition() : glm::vec3(0.0f);
|
||||
auto pose = getLeftHandControllerPoseInAvatarFrame();
|
||||
return pose.isValid() ? pose.getTranslation() : glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
glm::vec3 MyAvatar::getRightHandPosition() const {
|
||||
auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand);
|
||||
return palmData.isValid() ? palmData.getPosition() : glm::vec3(0.0f);
|
||||
auto pose = getRightHandControllerPoseInAvatarFrame();
|
||||
return pose.isValid() ? pose.getTranslation() : glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
glm::vec3 MyAvatar::getLeftHandTipPosition() const {
|
||||
auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand);
|
||||
return palmData.isValid() ? palmData.getTipPosition() : glm::vec3(0.0f);
|
||||
const float TIP_LENGTH = 0.3f;
|
||||
auto pose = getLeftHandControllerPoseInAvatarFrame();
|
||||
return pose.isValid() ? pose.getTranslation() * pose.getRotation() + glm::vec3(0.0f, TIP_LENGTH, 0.0f) : glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
glm::vec3 MyAvatar::getRightHandTipPosition() const {
|
||||
auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand);
|
||||
return palmData.isValid() ? palmData.getTipPosition() : glm::vec3(0.0f);
|
||||
const float TIP_LENGTH = 0.3f;
|
||||
auto pose = getRightHandControllerPoseInAvatarFrame();
|
||||
return pose.isValid() ? pose.getTranslation() * pose.getRotation() + glm::vec3(0.0f, TIP_LENGTH, 0.0f) : glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
controller::Pose MyAvatar::getLeftHandPose() const {
|
||||
auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand);
|
||||
return palmData.isValid() ? controller::Pose(palmData.getPosition(), palmData.getRotation(),
|
||||
palmData.getVelocity(), palmData.getRawAngularVelocity()) : controller::Pose();
|
||||
return getLeftHandControllerPoseInAvatarFrame();
|
||||
}
|
||||
|
||||
controller::Pose MyAvatar::getRightHandPose() const {
|
||||
auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand);
|
||||
return palmData.isValid() ? controller::Pose(palmData.getPosition(), palmData.getRotation(),
|
||||
palmData.getVelocity(), palmData.getRawAngularVelocity()) : controller::Pose();
|
||||
return getRightHandControllerPoseInAvatarFrame();
|
||||
}
|
||||
|
||||
controller::Pose MyAvatar::getLeftHandTipPose() const {
|
||||
auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand);
|
||||
return palmData.isValid() ? controller::Pose(palmData.getTipPosition(), palmData.getRotation(),
|
||||
palmData.getTipVelocity(), palmData.getRawAngularVelocity()) : controller::Pose();
|
||||
auto pose = getLeftHandControllerPoseInAvatarFrame();
|
||||
glm::vec3 tipTrans = getLeftHandTipPosition();
|
||||
pose.velocity += glm::cross(pose.getAngularVelocity(), pose.getTranslation() - tipTrans);
|
||||
pose.translation = tipTrans;
|
||||
return pose;
|
||||
}
|
||||
|
||||
controller::Pose MyAvatar::getRightHandTipPose() const {
|
||||
auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand);
|
||||
return palmData.isValid() ? controller::Pose(palmData.getTipPosition(), palmData.getRotation(),
|
||||
palmData.getTipVelocity(), palmData.getRawAngularVelocity()) : controller::Pose();
|
||||
auto pose = getRightHandControllerPoseInAvatarFrame();
|
||||
glm::vec3 tipTrans = getRightHandTipPosition();
|
||||
pose.velocity += glm::cross(pose.getAngularVelocity(), pose.getTranslation() - tipTrans);
|
||||
pose.translation = tipTrans;
|
||||
return pose;
|
||||
}
|
||||
|
||||
// virtual
|
||||
|
@ -702,6 +697,15 @@ void MyAvatar::setEnableDebugDrawPosition(bool isEnabled) {
|
|||
}
|
||||
}
|
||||
|
||||
void MyAvatar::setEnableDebugDrawHandControllers(bool isEnabled) {
|
||||
_enableDebugDrawHandControllers = isEnabled;
|
||||
|
||||
if (!isEnabled) {
|
||||
DebugDraw::getInstance().removeMarker("leftHandController");
|
||||
DebugDraw::getInstance().removeMarker("rightHandController");
|
||||
}
|
||||
}
|
||||
|
||||
void MyAvatar::setEnableDebugDrawSensorToWorldMatrix(bool isEnabled) {
|
||||
_enableDebugDrawSensorToWorldMatrix = isEnabled;
|
||||
|
||||
|
@ -1092,6 +1096,48 @@ void MyAvatar::rebuildCollisionShape() {
|
|||
_characterController.setLocalBoundingBox(corner, diagonal);
|
||||
}
|
||||
|
||||
static controller::Pose applyLowVelocityFilter(const controller::Pose& oldPose, const controller::Pose& newPose) {
|
||||
controller::Pose finalPose = newPose;
|
||||
if (newPose.isValid()) {
|
||||
// Use a velocity sensitive filter to damp small motions and preserve large ones with
|
||||
// no latency.
|
||||
float velocityFilter = glm::clamp(1.0f - glm::length(oldPose.getVelocity()), 0.0f, 1.0f);
|
||||
finalPose.translation = oldPose.getTranslation() * velocityFilter + newPose.getTranslation() * (1.0f - velocityFilter);
|
||||
finalPose.rotation = safeMix(oldPose.getRotation(), newPose.getRotation(), 1.0f - velocityFilter);
|
||||
}
|
||||
return finalPose;
|
||||
}
|
||||
|
||||
void MyAvatar::setHandControllerPosesInWorldFrame(const controller::Pose& left, const controller::Pose& right) {
|
||||
if (controller::InputDevice::getLowVelocityFilter()) {
|
||||
auto oldLeftPose = getLeftHandControllerPoseInWorldFrame();
|
||||
auto oldRightPose = getRightHandControllerPoseInWorldFrame();
|
||||
_leftHandControllerPoseInWorldFrameCache.set(applyLowVelocityFilter(oldLeftPose, left));
|
||||
_rightHandControllerPoseInWorldFrameCache.set(applyLowVelocityFilter(oldRightPose, right));
|
||||
} else {
|
||||
_leftHandControllerPoseInWorldFrameCache.set(left);
|
||||
_rightHandControllerPoseInWorldFrameCache.set(right);
|
||||
}
|
||||
}
|
||||
|
||||
controller::Pose MyAvatar::getLeftHandControllerPoseInWorldFrame() const {
|
||||
return _leftHandControllerPoseInWorldFrameCache.get();
|
||||
}
|
||||
|
||||
controller::Pose MyAvatar::getRightHandControllerPoseInWorldFrame() const {
|
||||
return _rightHandControllerPoseInWorldFrameCache.get();
|
||||
}
|
||||
|
||||
controller::Pose MyAvatar::getLeftHandControllerPoseInAvatarFrame() const {
|
||||
glm::mat4 invAvatarMatrix = glm::inverse(createMatFromQuatAndPos(getOrientation(), getPosition()));
|
||||
return getLeftHandControllerPoseInWorldFrame().transform(invAvatarMatrix);
|
||||
}
|
||||
|
||||
controller::Pose MyAvatar::getRightHandControllerPoseInAvatarFrame() const {
|
||||
glm::mat4 invAvatarMatrix = glm::inverse(createMatFromQuatAndPos(getOrientation(), getPosition()));
|
||||
return getRightHandControllerPoseInWorldFrame().transform(invAvatarMatrix);
|
||||
}
|
||||
|
||||
void MyAvatar::prepareForPhysicsSimulation() {
|
||||
relayDriveKeysToCharacterController();
|
||||
|
||||
|
@ -1227,11 +1273,6 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, fl
|
|||
} else {
|
||||
getHead()->renderLookAts(renderArgs);
|
||||
}
|
||||
|
||||
if (renderArgs->_renderMode != RenderArgs::SHADOW_RENDER_MODE &&
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::DisplayHandTargets)) {
|
||||
getHand()->renderHandTargets(renderArgs, true);
|
||||
}
|
||||
}
|
||||
|
||||
void MyAvatar::setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visible) {
|
||||
|
@ -1340,6 +1381,23 @@ void MyAvatar::preRender(RenderArgs* renderArgs) {
|
|||
}
|
||||
}
|
||||
|
||||
if (_enableDebugDrawHandControllers) {
|
||||
auto leftHandPose = getLeftHandControllerPoseInWorldFrame();
|
||||
auto rightHandPose = getRightHandControllerPoseInWorldFrame();
|
||||
|
||||
if (leftHandPose.isValid()) {
|
||||
DebugDraw::getInstance().addMarker("leftHandController", leftHandPose.getRotation(), leftHandPose.getTranslation(), glm::vec4(1));
|
||||
} else {
|
||||
DebugDraw::getInstance().removeMarker("leftHandController");
|
||||
}
|
||||
|
||||
if (rightHandPose.isValid()) {
|
||||
DebugDraw::getInstance().addMarker("rightHandController", rightHandPose.getRotation(), rightHandPose.getTranslation(), glm::vec4(1));
|
||||
} else {
|
||||
DebugDraw::getInstance().removeMarker("rightHandController");
|
||||
}
|
||||
}
|
||||
|
||||
DebugDraw::getInstance().updateMyAvatarPos(getPosition());
|
||||
DebugDraw::getInstance().updateMyAvatarRot(getOrientation());
|
||||
|
||||
|
|
|
@ -249,6 +249,12 @@ public:
|
|||
|
||||
virtual void rebuildCollisionShape() override;
|
||||
|
||||
void setHandControllerPosesInWorldFrame(const controller::Pose& left, const controller::Pose& right);
|
||||
controller::Pose getLeftHandControllerPoseInWorldFrame() const;
|
||||
controller::Pose getRightHandControllerPoseInWorldFrame() const;
|
||||
controller::Pose getLeftHandControllerPoseInAvatarFrame() const;
|
||||
controller::Pose getRightHandControllerPoseInAvatarFrame() const;
|
||||
|
||||
public slots:
|
||||
void increaseSize();
|
||||
void decreaseSize();
|
||||
|
@ -271,6 +277,7 @@ public slots:
|
|||
void setEnableDebugDrawDefaultPose(bool isEnabled);
|
||||
void setEnableDebugDrawAnimPose(bool isEnabled);
|
||||
void setEnableDebugDrawPosition(bool isEnabled);
|
||||
void setEnableDebugDrawHandControllers(bool isEnabled);
|
||||
void setEnableDebugDrawSensorToWorldMatrix(bool isEnabled);
|
||||
bool getEnableMeshVisible() const { return _skeletonModel.isVisible(); }
|
||||
void setEnableMeshVisible(bool isEnabled);
|
||||
|
@ -435,6 +442,7 @@ private:
|
|||
|
||||
bool _enableDebugDrawDefaultPose { false };
|
||||
bool _enableDebugDrawAnimPose { false };
|
||||
bool _enableDebugDrawHandControllers { false };
|
||||
bool _enableDebugDrawSensorToWorldMatrix { false };
|
||||
|
||||
AudioListenerMode _audioListenerMode;
|
||||
|
@ -446,6 +454,10 @@ private:
|
|||
bool _hoverReferenceCameraFacingIsCaptured { false };
|
||||
glm::vec3 _hoverReferenceCameraFacing { 0.0f, 0.0f, -1.0f }; // hmd sensor space
|
||||
|
||||
// These are stored in WORLD frame
|
||||
ThreadSafeValueCache<controller::Pose> _leftHandControllerPoseInWorldFrameCache { controller::Pose() };
|
||||
ThreadSafeValueCache<controller::Pose> _rightHandControllerPoseInWorldFrameCache { controller::Pose() };
|
||||
|
||||
float AVATAR_MOVEMENT_ENERGY_CONSTANT { 0.001f };
|
||||
float AUDIO_ENERGY_CONSTANT { 0.000001f };
|
||||
float MAX_AVATAR_MOVEMENT_PER_FRAME { 30.0f };
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
#include "Application.h"
|
||||
#include "Avatar.h"
|
||||
#include "Hand.h"
|
||||
#include "Menu.h"
|
||||
#include "SkeletonModel.h"
|
||||
#include "Util.h"
|
||||
|
@ -127,20 +126,20 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
|
||||
Rig::HandParameters handParams;
|
||||
|
||||
auto leftPalm = myAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand);
|
||||
if (leftPalm.isValid() && leftPalm.isActive()) {
|
||||
auto leftPose = myAvatar->getLeftHandControllerPoseInAvatarFrame();
|
||||
if (leftPose.isValid()) {
|
||||
handParams.isLeftEnabled = true;
|
||||
handParams.leftPosition = Quaternions::Y_180 * leftPalm.getRawPosition();
|
||||
handParams.leftOrientation = Quaternions::Y_180 * leftPalm.getRawRotation();
|
||||
handParams.leftPosition = Quaternions::Y_180 * leftPose.getTranslation();
|
||||
handParams.leftOrientation = Quaternions::Y_180 * leftPose.getRotation();
|
||||
} else {
|
||||
handParams.isLeftEnabled = false;
|
||||
}
|
||||
|
||||
auto rightPalm = myAvatar->getHand()->getCopyOfPalmData(HandData::RightHand);
|
||||
if (rightPalm.isValid() && rightPalm.isActive()) {
|
||||
auto rightPose = myAvatar->getRightHandControllerPoseInAvatarFrame();
|
||||
if (rightPose.isValid()) {
|
||||
handParams.isRightEnabled = true;
|
||||
handParams.rightPosition = Quaternions::Y_180 * rightPalm.getRawPosition();
|
||||
handParams.rightOrientation = Quaternions::Y_180 * rightPalm.getRawRotation();
|
||||
handParams.rightPosition = Quaternions::Y_180 * rightPose.getTranslation();
|
||||
handParams.rightOrientation = Quaternions::Y_180 * rightPose.getRotation();
|
||||
} else {
|
||||
handParams.isRightEnabled = false;
|
||||
}
|
||||
|
@ -247,17 +246,6 @@ bool operator<(const IndexValue& firstIndex, const IndexValue& secondIndex) {
|
|||
return firstIndex.value < secondIndex.value;
|
||||
}
|
||||
|
||||
void SkeletonModel::applyPalmData(int jointIndex, const PalmData& palm) {
|
||||
if (jointIndex == -1 || jointIndex >= _rig->getJointStateCount()) {
|
||||
return;
|
||||
}
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
int parentJointIndex = geometry.joints.at(jointIndex).parentIndex;
|
||||
if (parentJointIndex == -1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool SkeletonModel::getLeftGrabPosition(glm::vec3& position) const {
|
||||
int knuckleIndex = _rig->indexOfJoint("LeftHandMiddle1");
|
||||
int handIndex = _rig->indexOfJoint("LeftHand");
|
||||
|
|
|
@ -111,7 +111,6 @@ protected:
|
|||
|
||||
void computeBoundingShape();
|
||||
|
||||
void applyPalmData(int jointIndex, const PalmData& palm);
|
||||
private:
|
||||
|
||||
bool getEyeModelPositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const;
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
#include <avatar/AvatarManager.h>
|
||||
#include <avatar/MyAvatar.h>
|
||||
#include <HandData.h>
|
||||
#include <HFBackEvent.h>
|
||||
#include <plugins/PluginManager.h>
|
||||
|
||||
|
|
|
@ -92,3 +92,8 @@ glm::quat HMDScriptingInterface::getOrientation() const {
|
|||
}
|
||||
return glm::quat();
|
||||
}
|
||||
|
||||
bool HMDScriptingInterface::isMounted() const{
|
||||
auto displayPlugin = qApp->getActiveDisplayPlugin();
|
||||
return (displayPlugin->isHmd() && displayPlugin->isDisplayVisible());
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Depen
|
|||
Q_OBJECT
|
||||
Q_PROPERTY(glm::vec3 position READ getPosition)
|
||||
Q_PROPERTY(glm::quat orientation READ getOrientation)
|
||||
Q_PROPERTY(bool mounted READ isMounted)
|
||||
|
||||
public:
|
||||
Q_INVOKABLE glm::vec3 calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction) const;
|
||||
|
@ -39,6 +40,7 @@ public:
|
|||
static QScriptValue getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine);
|
||||
static QScriptValue getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine);
|
||||
|
||||
bool isMounted() const;
|
||||
|
||||
private:
|
||||
// Get the position of the HMD
|
||||
|
|
|
@ -164,7 +164,7 @@ void Stats::updateStats(bool force) {
|
|||
MyAvatar* myAvatar = avatarManager->getMyAvatar();
|
||||
glm::vec3 avatarPos = myAvatar->getPosition();
|
||||
STAT_UPDATE(position, QVector3D(avatarPos.x, avatarPos.y, avatarPos.z));
|
||||
STAT_UPDATE_FLOAT(speed, glm::length(myAvatar->getVelocity()), 0.1f);
|
||||
STAT_UPDATE_FLOAT(speed, glm::length(myAvatar->getVelocity()), 0.01f);
|
||||
STAT_UPDATE_FLOAT(yaw, myAvatar->getBodyYaw(), 0.1f);
|
||||
if (_expanded || force) {
|
||||
SharedNodePointer avatarMixer = nodeList->soloNodeOfType(NodeType::AvatarMixer);
|
||||
|
|
|
@ -51,27 +51,24 @@ void QmlOverlay::buildQmlElement(const QUrl& url) {
|
|||
}
|
||||
|
||||
QmlOverlay::~QmlOverlay() {
|
||||
if (_qmlElement) {
|
||||
_qmlElement->deleteLater();
|
||||
_qmlElement = nullptr;
|
||||
}
|
||||
_qmlElement.reset();
|
||||
}
|
||||
|
||||
void QmlOverlay::setProperties(const QVariantMap& properties) {
|
||||
Overlay2D::setProperties(properties);
|
||||
auto bounds = _bounds;
|
||||
std::weak_ptr<QQuickItem> weakQmlElement;
|
||||
DependencyManager::get<OffscreenUi>()->executeOnUiThread([=] {
|
||||
std::weak_ptr<QQuickItem> weakQmlElement = _qmlElement;
|
||||
DependencyManager::get<OffscreenUi>()->executeOnUiThread([weakQmlElement, bounds, properties] {
|
||||
// check to see if qmlElement still exists
|
||||
auto qmlElement = weakQmlElement.lock();
|
||||
if (qmlElement) {
|
||||
_qmlElement->setX(bounds.left());
|
||||
_qmlElement->setY(bounds.top());
|
||||
_qmlElement->setWidth(bounds.width());
|
||||
_qmlElement->setHeight(bounds.height());
|
||||
qmlElement->setX(bounds.left());
|
||||
qmlElement->setY(bounds.top());
|
||||
qmlElement->setWidth(bounds.width());
|
||||
qmlElement->setHeight(bounds.height());
|
||||
QMetaObject::invokeMethod(qmlElement.get(), "updatePropertiesFromScript", Qt::DirectConnection, Q_ARG(QVariant, properties));
|
||||
}
|
||||
});
|
||||
QMetaObject::invokeMethod(_qmlElement.get(), "updatePropertiesFromScript", Q_ARG(QVariant, properties));
|
||||
}
|
||||
|
||||
void QmlOverlay::render(RenderArgs* args) {
|
||||
|
|
|
@ -57,7 +57,6 @@ AvatarData::AvatarData() :
|
|||
_hasNewJointRotations(true),
|
||||
_hasNewJointTranslations(true),
|
||||
_headData(NULL),
|
||||
_handData(NULL),
|
||||
_faceModelURL("http://invalid.com"),
|
||||
_displayNameTargetAlpha(1.0f),
|
||||
_displayNameAlpha(1.0f),
|
||||
|
@ -74,7 +73,6 @@ AvatarData::AvatarData() :
|
|||
|
||||
AvatarData::~AvatarData() {
|
||||
delete _headData;
|
||||
delete _handData;
|
||||
}
|
||||
|
||||
// We cannot have a file-level variable (const or otherwise) in the header if it uses PathUtils, because that references Application, which will not yet initialized.
|
||||
|
@ -418,11 +416,6 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
|||
_headData = new HeadData(this);
|
||||
}
|
||||
|
||||
// lazily allocate memory for HandData in case we're not an Avatar instance
|
||||
if (!_handData) {
|
||||
_handData = new HandData(this);
|
||||
}
|
||||
|
||||
const unsigned char* startPosition = reinterpret_cast<const unsigned char*>(buffer.data());
|
||||
const unsigned char* sourceBuffer = startPosition;
|
||||
quint64 now = usecTimestampNow();
|
||||
|
|
|
@ -52,9 +52,9 @@ typedef unsigned long long quint64;
|
|||
#include <RegisteredMetaTypes.h>
|
||||
#include <SimpleMovingAverage.h>
|
||||
#include <SpatiallyNestable.h>
|
||||
#include <NumericalConstants.h>
|
||||
|
||||
#include "AABox.h"
|
||||
#include "HandData.h"
|
||||
#include "HeadData.h"
|
||||
#include "PathUtils.h"
|
||||
|
||||
|
@ -290,7 +290,6 @@ public:
|
|||
KeyState keyState() const { return _keyState; }
|
||||
|
||||
const HeadData* getHeadData() const { return _headData; }
|
||||
const HandData* getHandData() const { return _handData; }
|
||||
|
||||
bool hasIdentityChangedAfterParsing(const QByteArray& data);
|
||||
QByteArray identityByteArray();
|
||||
|
@ -383,7 +382,6 @@ protected:
|
|||
bool _hasNewJointTranslations; // set in AvatarData, cleared in Avatar
|
||||
|
||||
HeadData* _headData;
|
||||
HandData* _handData;
|
||||
|
||||
QUrl _faceModelURL; // These need to be empty so that on first time setting them they will not short circuit
|
||||
QUrl _skeletonModelURL; // These need to be empty so that on first time setting them they will not short circuit
|
||||
|
|
|
@ -1,110 +0,0 @@
|
|||
//
|
||||
// HandData.cpp
|
||||
// libraries/avatars/src
|
||||
//
|
||||
// Created by Stephen Birarda on 5/20/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QtCore/QDataStream>
|
||||
|
||||
#include <GeometryUtil.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "AvatarData.h"
|
||||
#include "HandData.h"
|
||||
|
||||
|
||||
HandData::HandData(AvatarData* owningAvatar) :
|
||||
_owningAvatarData(owningAvatar)
|
||||
{
|
||||
addNewPalm(LeftHand);
|
||||
addNewPalm(RightHand);
|
||||
}
|
||||
|
||||
glm::vec3 HandData::worldToLocalVector(const glm::vec3& worldVector) const {
|
||||
return glm::inverse(getBaseOrientation()) * worldVector / getBaseScale();
|
||||
}
|
||||
|
||||
PalmData& HandData::addNewPalm(Hand whichHand) {
|
||||
QWriteLocker locker(&_palmsLock);
|
||||
_palms.push_back(PalmData(this, whichHand));
|
||||
return _palms.back();
|
||||
}
|
||||
|
||||
PalmData HandData::getCopyOfPalmData(Hand hand) const {
|
||||
QReadLocker locker(&_palmsLock);
|
||||
|
||||
// the palms are not necessarily added in left-right order,
|
||||
// so we have to search for the correct hand
|
||||
for (const auto& palm : _palms) {
|
||||
if (palm.whichHand() == hand && palm.isActive()) {
|
||||
return palm;
|
||||
}
|
||||
}
|
||||
return PalmData(); // invalid hand
|
||||
}
|
||||
|
||||
PalmData::PalmData(HandData* owningHandData, HandData::Hand hand) :
|
||||
_rawRotation(0.0f, 0.0f, 0.0f, 1.0f),
|
||||
_rawPosition(0.0f),
|
||||
_rawVelocity(0.0f),
|
||||
_rawAngularVelocity(0.0f),
|
||||
_totalPenetration(0.0f),
|
||||
_isActive(false),
|
||||
_numFramesWithoutData(0),
|
||||
_owningHandData(owningHandData),
|
||||
_hand(hand) {
|
||||
}
|
||||
|
||||
void PalmData::addToPosition(const glm::vec3& delta) {
|
||||
_rawPosition += _owningHandData->worldToLocalVector(delta);
|
||||
}
|
||||
|
||||
bool HandData::findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, glm::vec3& penetration,
|
||||
const PalmData*& collidingPalm) const {
|
||||
QReadLocker locker(&_palmsLock);
|
||||
|
||||
for (const auto& palm : _palms) {
|
||||
if (!palm.isActive()) {
|
||||
continue;
|
||||
}
|
||||
glm::vec3 palmPosition = palm.getPosition();
|
||||
const float PALM_RADIUS = 0.05f; // in world (not voxel) coordinates
|
||||
if (findSphereSpherePenetration(penetratorCenter, penetratorRadius, palmPosition, PALM_RADIUS, penetration)) {
|
||||
collidingPalm = &palm;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
glm::quat HandData::getBaseOrientation() const {
|
||||
return _owningAvatarData->getOrientation();
|
||||
}
|
||||
|
||||
glm::vec3 HandData::getBasePosition() const {
|
||||
return _owningAvatarData->getPosition();
|
||||
}
|
||||
|
||||
float HandData::getBaseScale() const {
|
||||
return _owningAvatarData->getTargetScale();
|
||||
}
|
||||
|
||||
glm::vec3 PalmData::getFingerDirection() const {
|
||||
// finger points along yAxis in hand-frame
|
||||
const glm::vec3 LOCAL_FINGER_DIRECTION(0.0f, 1.0f, 0.0f);
|
||||
return glm::normalize(_owningHandData->localToWorldDirection(_rawRotation * LOCAL_FINGER_DIRECTION));
|
||||
}
|
||||
|
||||
glm::vec3 PalmData::getNormal() const {
|
||||
// palm normal points along zAxis in hand-frame
|
||||
const glm::vec3 LOCAL_PALM_DIRECTION(0.0f, 0.0f, 1.0f);
|
||||
return glm::normalize(_owningHandData->localToWorldDirection(_rawRotation * LOCAL_PALM_DIRECTION));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,174 +0,0 @@
|
|||
//
|
||||
// HandData.h
|
||||
// libraries/avatars/src
|
||||
//
|
||||
// Created by Eric Johnston on 6/26/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_HandData_h
|
||||
#define hifi_HandData_h
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include <QReadWriteLock>
|
||||
|
||||
#include <NumericalConstants.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
class AvatarData;
|
||||
class PalmData;
|
||||
|
||||
class HandData {
|
||||
public:
|
||||
enum Hand {
|
||||
LeftHand,
|
||||
RightHand,
|
||||
UnknownHand,
|
||||
NUMBER_OF_HANDS
|
||||
};
|
||||
|
||||
HandData(AvatarData* owningAvatar);
|
||||
virtual ~HandData() {}
|
||||
|
||||
// position conversion
|
||||
glm::vec3 localToWorldPosition(const glm::vec3& localPosition) {
|
||||
return getBasePosition() + getBaseOrientation() * localPosition * getBaseScale();
|
||||
}
|
||||
|
||||
glm::vec3 localToWorldDirection(const glm::vec3& localVector) {
|
||||
return getBaseOrientation() * localVector * getBaseScale();
|
||||
}
|
||||
|
||||
glm::vec3 worldToLocalVector(const glm::vec3& worldVector) const;
|
||||
|
||||
PalmData getCopyOfPalmData(Hand hand) const;
|
||||
|
||||
std::vector<PalmData> getCopyOfPalms() const { QReadLocker locker(&_palmsLock); return _palms; }
|
||||
|
||||
/// Checks for penetration between the described sphere and the hand.
|
||||
/// \param penetratorCenter the center of the penetration test sphere
|
||||
/// \param penetratorRadius the radius of the penetration test sphere
|
||||
/// \param penetration[out] the vector in which to store the penetration
|
||||
/// \param collidingPalm[out] a const PalmData* to the palm that was collided with
|
||||
/// \return whether or not the sphere penetrated
|
||||
bool findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, glm::vec3& penetration,
|
||||
const PalmData*& collidingPalm) const;
|
||||
|
||||
glm::quat getBaseOrientation() const;
|
||||
|
||||
/// Allows a lamda function write access to the specific palm for this Hand, this might
|
||||
/// modify the _palms vector
|
||||
template<typename PalmModifierFunction> void modifyPalm(Hand whichHand, PalmModifierFunction callback);
|
||||
|
||||
friend class AvatarData;
|
||||
protected:
|
||||
AvatarData* _owningAvatarData;
|
||||
std::vector<PalmData> _palms;
|
||||
mutable QReadWriteLock _palmsLock{ QReadWriteLock::Recursive };
|
||||
|
||||
glm::vec3 getBasePosition() const;
|
||||
float getBaseScale() const;
|
||||
|
||||
PalmData& addNewPalm(Hand whichHand);
|
||||
PalmData& getPalmData(Hand hand);
|
||||
|
||||
private:
|
||||
// privatize copy ctor and assignment operator so copies of this object cannot be made
|
||||
HandData(const HandData&);
|
||||
HandData& operator= (const HandData&);
|
||||
};
|
||||
|
||||
|
||||
class PalmData {
|
||||
public:
|
||||
PalmData(HandData* owningHandData = nullptr, HandData::Hand hand = HandData::UnknownHand);
|
||||
glm::vec3 getPosition() const { return _owningHandData->localToWorldPosition(_rawPosition); }
|
||||
glm::vec3 getVelocity() const { return _owningHandData->localToWorldDirection(_rawVelocity); }
|
||||
glm::vec3 getAngularVelocity() const { return _owningHandData->localToWorldDirection(_rawAngularVelocity); }
|
||||
|
||||
const glm::vec3& getRawPosition() const { return _rawPosition; }
|
||||
bool isActive() const { return _isActive; }
|
||||
bool isValid() const { return _owningHandData; }
|
||||
|
||||
void setActive(bool active) { _isActive = active; }
|
||||
|
||||
HandData::Hand whichHand() const { return _hand; }
|
||||
void setHand(HandData::Hand hand) { _hand = hand; }
|
||||
|
||||
void setRawRotation(const glm::quat& rawRotation) { _rawRotation = rawRotation; };
|
||||
glm::quat getRawRotation() const { return _rawRotation; }
|
||||
glm::quat getRotation() const { return _owningHandData->getBaseOrientation() * _rawRotation; }
|
||||
void setRawPosition(const glm::vec3& pos) { _rawPosition = pos; }
|
||||
void setRawVelocity(const glm::vec3& velocity) { _rawVelocity = velocity; }
|
||||
const glm::vec3& getRawVelocity() const { return _rawVelocity; }
|
||||
|
||||
void setRawAngularVelocity(const glm::vec3& angularVelocity) { _rawAngularVelocity = angularVelocity; }
|
||||
const glm::vec3& getRawAngularVelocity() const { return _rawAngularVelocity; }
|
||||
|
||||
void addToPosition(const glm::vec3& delta);
|
||||
|
||||
void addToPenetration(const glm::vec3& penetration) { _totalPenetration += penetration; }
|
||||
void resolvePenetrations() { addToPosition(-_totalPenetration); _totalPenetration = glm::vec3(0.0f); }
|
||||
|
||||
void setTipPosition(const glm::vec3& position) { _tipPosition = position; }
|
||||
const glm::vec3 getTipPosition() const { return _owningHandData->localToWorldPosition(_tipPosition); }
|
||||
const glm::vec3& getTipRawPosition() const { return _tipPosition; }
|
||||
|
||||
void setTipVelocity(const glm::vec3& velocity) { _tipVelocity = velocity; }
|
||||
const glm::vec3 getTipVelocity() const { return _owningHandData->localToWorldDirection(_tipVelocity); }
|
||||
const glm::vec3& getTipRawVelocity() const { return _tipVelocity; }
|
||||
|
||||
void incrementFramesWithoutData() { _numFramesWithoutData++; }
|
||||
void resetFramesWithoutData() { _numFramesWithoutData = 0; }
|
||||
int getFramesWithoutData() const { return _numFramesWithoutData; }
|
||||
|
||||
// FIXME - these are used in SkeletonModel::updateRig() the skeleton/rig should probably get this information
|
||||
// from an action and/or the UserInputMapper instead of piping it through here.
|
||||
void setTrigger(float trigger) { _trigger = trigger; }
|
||||
float getTrigger() const { return _trigger; }
|
||||
|
||||
// return world-frame:
|
||||
glm::vec3 getFingerDirection() const;
|
||||
glm::vec3 getNormal() const;
|
||||
|
||||
private:
|
||||
// unless marked otherwise, these are all in the model-frame
|
||||
glm::quat _rawRotation;
|
||||
glm::vec3 _rawPosition;
|
||||
glm::vec3 _rawVelocity;
|
||||
glm::vec3 _rawAngularVelocity;
|
||||
glm::quat _rawDeltaRotation;
|
||||
glm::quat _lastRotation;
|
||||
|
||||
glm::vec3 _tipPosition;
|
||||
glm::vec3 _tipVelocity;
|
||||
glm::vec3 _totalPenetration; /// accumulator for per-frame penetrations
|
||||
|
||||
float _trigger;
|
||||
|
||||
bool _isActive; /// This has current valid data
|
||||
int _numFramesWithoutData; /// after too many frames without data, this tracked object assumed lost.
|
||||
HandData* _owningHandData;
|
||||
HandData::Hand _hand;
|
||||
};
|
||||
|
||||
template<typename PalmModifierFunction> void HandData::modifyPalm(Hand whichHand, PalmModifierFunction callback) {
|
||||
QReadLocker locker(&_palmsLock);
|
||||
for (auto& palm : _palms) {
|
||||
if (palm.whichHand() == whichHand && palm.isValid()) {
|
||||
callback(palm);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // hifi_HandData_h
|
|
@ -11,6 +11,7 @@
|
|||
#include <memory>
|
||||
#include <math.h>
|
||||
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QDesktopWidget>
|
||||
|
@ -414,13 +415,39 @@ void CompositorHelper::updateTooltips() {
|
|||
}
|
||||
|
||||
static const float FADE_DURATION = 500.0f;
|
||||
static const float FADE_IN_ALPHA = 1.0f;
|
||||
static const float FADE_OUT_ALPHA = 0.0f;
|
||||
|
||||
void CompositorHelper::startFadeFailsafe(float endValue) {
|
||||
_fadeStarted = usecTimestampNow();
|
||||
_fadeFailsafeEndValue = endValue;
|
||||
|
||||
const int SLIGHT_DELAY = 10;
|
||||
QTimer::singleShot(FADE_DURATION + SLIGHT_DELAY, [this]{
|
||||
checkFadeFailsafe();
|
||||
});
|
||||
}
|
||||
|
||||
void CompositorHelper::checkFadeFailsafe() {
|
||||
auto elapsedInFade = usecTimestampNow() - _fadeStarted;
|
||||
if (elapsedInFade > FADE_DURATION) {
|
||||
setAlpha(_fadeFailsafeEndValue);
|
||||
}
|
||||
}
|
||||
|
||||
void CompositorHelper::fadeIn() {
|
||||
_fadeInAlpha = true;
|
||||
|
||||
_alphaPropertyAnimation->setDuration(FADE_DURATION);
|
||||
_alphaPropertyAnimation->setStartValue(_alpha);
|
||||
_alphaPropertyAnimation->setEndValue(1.0f);
|
||||
_alphaPropertyAnimation->setEndValue(FADE_IN_ALPHA);
|
||||
_alphaPropertyAnimation->start();
|
||||
|
||||
// Sometimes, this "QPropertyAnimation" fails to complete the animation, and we end up with a partially faded
|
||||
// state. So we will also have this fail-safe, where we record the timestamp of the fadeRequest, and the target
|
||||
// value of the fade, and if after that time we still haven't faded all the way, we will kick it to the final
|
||||
// fade value
|
||||
startFadeFailsafe(FADE_IN_ALPHA);
|
||||
}
|
||||
|
||||
void CompositorHelper::fadeOut() {
|
||||
|
@ -428,8 +455,9 @@ void CompositorHelper::fadeOut() {
|
|||
|
||||
_alphaPropertyAnimation->setDuration(FADE_DURATION);
|
||||
_alphaPropertyAnimation->setStartValue(_alpha);
|
||||
_alphaPropertyAnimation->setEndValue(0.0f);
|
||||
_alphaPropertyAnimation->setEndValue(FADE_OUT_ALPHA);
|
||||
_alphaPropertyAnimation->start();
|
||||
startFadeFailsafe(FADE_OUT_ALPHA);
|
||||
}
|
||||
|
||||
void CompositorHelper::toggle() {
|
||||
|
|
|
@ -145,6 +145,11 @@ private:
|
|||
float _fadeInAlpha { true };
|
||||
float _oculusUIRadius { 1.0f };
|
||||
|
||||
quint64 _fadeStarted { 0 };
|
||||
float _fadeFailsafeEndValue { 1.0f };
|
||||
void checkFadeFailsafe();
|
||||
void startFadeFailsafe(float endValue);
|
||||
|
||||
int _reticleQuad;
|
||||
|
||||
int _previousBorderWidth { -1 };
|
||||
|
|
|
@ -296,6 +296,9 @@ void OpenGLDisplayPlugin::customizeContext() {
|
|||
if (uniform.Name() == "mvp") {
|
||||
_mvpUniform = uniform.Index();
|
||||
}
|
||||
if (uniform.Name() == "alpha") {
|
||||
_alphaUniform = uniform.Index();
|
||||
}
|
||||
uniforms.Next();
|
||||
}
|
||||
|
||||
|
@ -406,33 +409,53 @@ void OpenGLDisplayPlugin::updateFramerate() {
|
|||
|
||||
void OpenGLDisplayPlugin::compositeOverlay() {
|
||||
using namespace oglplus;
|
||||
// Overlay draw
|
||||
if (isStereo()) {
|
||||
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mat4());
|
||||
for_each_eye([&](Eye eye) {
|
||||
eyeViewport(eye);
|
||||
drawUnitQuad();
|
||||
});
|
||||
} else {
|
||||
|
||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
|
||||
// check the alpha
|
||||
auto overlayAlpha = compositorHelper->getAlpha();
|
||||
if (overlayAlpha > 0.0f) {
|
||||
// set the alpha
|
||||
Uniform<float>(*_program, _alphaUniform).Set(overlayAlpha);
|
||||
|
||||
// Overlay draw
|
||||
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mat4());
|
||||
drawUnitQuad();
|
||||
if (isStereo()) {
|
||||
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mat4());
|
||||
for_each_eye([&](Eye eye) {
|
||||
eyeViewport(eye);
|
||||
drawUnitQuad();
|
||||
});
|
||||
} else {
|
||||
// Overlay draw
|
||||
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mat4());
|
||||
drawUnitQuad();
|
||||
}
|
||||
}
|
||||
Uniform<float>(*_program, _alphaUniform).Set(1.0);
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::compositePointer() {
|
||||
using namespace oglplus;
|
||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
Uniform<glm::mat4>(*_program, _mvpUniform).Set(compositorHelper->getReticleTransform(glm::mat4()));
|
||||
if (isStereo()) {
|
||||
for_each_eye([&](Eye eye) {
|
||||
eyeViewport(eye);
|
||||
|
||||
// check the alpha
|
||||
auto overlayAlpha = compositorHelper->getAlpha();
|
||||
if (overlayAlpha > 0.0f) {
|
||||
// set the alpha
|
||||
Uniform<float>(*_program, _alphaUniform).Set(overlayAlpha);
|
||||
|
||||
Uniform<glm::mat4>(*_program, _mvpUniform).Set(compositorHelper->getReticleTransform(glm::mat4()));
|
||||
if (isStereo()) {
|
||||
for_each_eye([&](Eye eye) {
|
||||
eyeViewport(eye);
|
||||
drawUnitQuad();
|
||||
});
|
||||
} else {
|
||||
drawUnitQuad();
|
||||
});
|
||||
} else {
|
||||
drawUnitQuad();
|
||||
}
|
||||
}
|
||||
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mat4());
|
||||
Uniform<float>(*_program, _alphaUniform).Set(1.0);
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::compositeLayers() {
|
||||
|
|
|
@ -29,24 +29,26 @@ protected:
|
|||
using TextureEscrow = GLEscrow<gpu::TexturePointer>;
|
||||
public:
|
||||
OpenGLDisplayPlugin();
|
||||
virtual void activate() override;
|
||||
virtual void deactivate() override;
|
||||
virtual void stop() override;
|
||||
virtual bool eventFilter(QObject* receiver, QEvent* event) override;
|
||||
void activate() override;
|
||||
void deactivate() override;
|
||||
void stop() override;
|
||||
bool eventFilter(QObject* receiver, QEvent* event) override;
|
||||
bool isDisplayVisible() const override { return true; }
|
||||
|
||||
virtual void submitSceneTexture(uint32_t frameIndex, const gpu::TexturePointer& sceneTexture) override;
|
||||
virtual void submitOverlayTexture(const gpu::TexturePointer& overlayTexture) override;
|
||||
virtual float presentRate() override;
|
||||
|
||||
virtual glm::uvec2 getRecommendedRenderSize() const override {
|
||||
void submitSceneTexture(uint32_t frameIndex, const gpu::TexturePointer& sceneTexture) override;
|
||||
void submitOverlayTexture(const gpu::TexturePointer& overlayTexture) override;
|
||||
float presentRate() override;
|
||||
|
||||
glm::uvec2 getRecommendedRenderSize() const override {
|
||||
return getSurfacePixels();
|
||||
}
|
||||
|
||||
virtual glm::uvec2 getRecommendedUiSize() const override {
|
||||
glm::uvec2 getRecommendedUiSize() const override {
|
||||
return getSurfaceSize();
|
||||
}
|
||||
|
||||
virtual QImage getScreenshot() const override;
|
||||
QImage getScreenshot() const override;
|
||||
|
||||
protected:
|
||||
#if THREADED_PRESENT
|
||||
|
@ -86,6 +88,7 @@ protected:
|
|||
|
||||
ProgramPtr _program;
|
||||
int32_t _mvpUniform { -1 };
|
||||
int32_t _alphaUniform { -1 };
|
||||
ShapeWrapperPtr _plane;
|
||||
|
||||
mutable Mutex _mutex;
|
||||
|
|
|
@ -62,30 +62,50 @@ void HmdDisplayPlugin::uncustomizeContext() {
|
|||
|
||||
void HmdDisplayPlugin::compositeOverlay() {
|
||||
using namespace oglplus;
|
||||
_sphereSection->Use();
|
||||
for_each_eye([&](Eye eye) {
|
||||
eyeViewport(eye);
|
||||
auto modelView = glm::inverse(_currentRenderEyePoses[eye]); // *glm::translate(mat4(), vec3(0, 0, -1));
|
||||
auto mvp = _eyeProjections[eye] * modelView;
|
||||
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mvp);
|
||||
_sphereSection->Draw();
|
||||
});
|
||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
|
||||
// check the alpha
|
||||
auto overlayAlpha = compositorHelper->getAlpha();
|
||||
if (overlayAlpha > 0.0f) {
|
||||
// set the alpha
|
||||
Uniform<float>(*_program, _alphaUniform).Set(overlayAlpha);
|
||||
|
||||
_sphereSection->Use();
|
||||
for_each_eye([&](Eye eye) {
|
||||
eyeViewport(eye);
|
||||
auto modelView = glm::inverse(_currentRenderEyePoses[eye]); // *glm::translate(mat4(), vec3(0, 0, -1));
|
||||
auto mvp = _eyeProjections[eye] * modelView;
|
||||
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mvp);
|
||||
_sphereSection->Draw();
|
||||
});
|
||||
}
|
||||
Uniform<float>(*_program, _alphaUniform).Set(1.0);
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::compositePointer() {
|
||||
//Mouse Pointer
|
||||
using namespace oglplus;
|
||||
|
||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
_plane->Use();
|
||||
// Reconstruct the headpose from the eye poses
|
||||
auto headPosition = (vec3(_currentRenderEyePoses[Left][3]) + vec3(_currentRenderEyePoses[Right][3])) / 2.0f;
|
||||
for_each_eye([&](Eye eye) {
|
||||
using namespace oglplus;
|
||||
eyeViewport(eye);
|
||||
auto reticleTransform = compositorHelper->getReticleTransform(_currentRenderEyePoses[eye], headPosition);
|
||||
auto mvp = _eyeProjections[eye] * reticleTransform;
|
||||
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mvp);
|
||||
_plane->Draw();
|
||||
});
|
||||
|
||||
// check the alpha
|
||||
auto overlayAlpha = compositorHelper->getAlpha();
|
||||
if (overlayAlpha > 0.0f) {
|
||||
// set the alpha
|
||||
Uniform<float>(*_program, _alphaUniform).Set(overlayAlpha);
|
||||
|
||||
// Mouse pointer
|
||||
_plane->Use();
|
||||
// Reconstruct the headpose from the eye poses
|
||||
auto headPosition = (vec3(_currentRenderEyePoses[Left][3]) + vec3(_currentRenderEyePoses[Right][3])) / 2.0f;
|
||||
for_each_eye([&](Eye eye) {
|
||||
eyeViewport(eye);
|
||||
auto reticleTransform = compositorHelper->getReticleTransform(_currentRenderEyePoses[eye], headPosition);
|
||||
auto mvp = _eyeProjections[eye] * reticleTransform;
|
||||
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mvp);
|
||||
_plane->Draw();
|
||||
});
|
||||
}
|
||||
Uniform<float>(*_program, _alphaUniform).Set(1.0);
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::internalPresent() {
|
||||
|
|
|
@ -22,12 +22,16 @@ public:
|
|||
glm::uvec2 getRecommendedUiSize() const override final;
|
||||
glm::uvec2 getRecommendedRenderSize() const override final { return _renderTargetSize; }
|
||||
void setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) override final;
|
||||
bool isDisplayVisible() const override { return isHmdMounted(); }
|
||||
|
||||
|
||||
void activate() override;
|
||||
void deactivate() override;
|
||||
|
||||
protected:
|
||||
virtual void hmdPresent() = 0;
|
||||
virtual bool isHmdMounted() const = 0;
|
||||
|
||||
void compositeOverlay() override;
|
||||
void compositePointer() override;
|
||||
void internalPresent() override;
|
||||
|
|
|
@ -140,8 +140,8 @@ void EntityTreeRenderer::update() {
|
|||
// If we haven't already updated and previously attempted to load a texture,
|
||||
// check if the texture loaded and apply it
|
||||
if (!updated && (
|
||||
(_pendingSkyboxTexture && _skyboxTexture && _skyboxTexture->isLoaded()) ||
|
||||
(_pendingAmbientTexture && _ambientTexture && _ambientTexture->isLoaded()))) {
|
||||
(_pendingSkyboxTexture && (!_skyboxTexture || _skyboxTexture->isLoaded())) ||
|
||||
(_pendingAmbientTexture && (!_ambientTexture || _ambientTexture->isLoaded())))) {
|
||||
applyZonePropertiesToScene(_bestZone);
|
||||
}
|
||||
|
||||
|
@ -158,6 +158,8 @@ void EntityTreeRenderer::update() {
|
|||
}
|
||||
|
||||
bool EntityTreeRenderer::checkEnterLeaveEntities() {
|
||||
bool didUpdate = false;
|
||||
|
||||
if (_tree && !_shuttingDown) {
|
||||
glm::vec3 avatarPosition = _viewState->getAvatarPosition();
|
||||
|
||||
|
@ -172,6 +174,7 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() {
|
|||
std::static_pointer_cast<EntityTree>(_tree)->findEntities(avatarPosition, radius, foundEntities);
|
||||
|
||||
// Whenever you're in an intersection between zones, we will always choose the smallest zone.
|
||||
auto oldBestZone = _bestZone;
|
||||
_bestZone = nullptr; // NOTE: Is this what we want?
|
||||
_bestZoneVolume = std::numeric_limits<float>::max();
|
||||
|
||||
|
@ -204,7 +207,10 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() {
|
|||
}
|
||||
}
|
||||
|
||||
applyZonePropertiesToScene(_bestZone);
|
||||
if (_bestZone != oldBestZone) {
|
||||
applyZonePropertiesToScene(_bestZone);
|
||||
didUpdate = true;
|
||||
}
|
||||
});
|
||||
|
||||
// Note: at this point we don't need to worry about the tree being locked, because we only deal with
|
||||
|
@ -228,11 +234,9 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() {
|
|||
}
|
||||
_currentEntitiesInside = entitiesContainingAvatar;
|
||||
_lastAvatarPosition = avatarPosition;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return didUpdate;
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::leaveAllEntities() {
|
||||
|
@ -322,15 +326,19 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
|||
_ambientTexture.clear();
|
||||
} else {
|
||||
_ambientTexture = textureCache->getTexture(zone->getKeyLightProperties().getAmbientURL(), CUBE_TEXTURE);
|
||||
if (_ambientTexture && _ambientTexture->isLoaded() && _ambientTexture->getGPUTexture()) {
|
||||
_pendingAmbientTexture = true;
|
||||
|
||||
if (_ambientTexture && _ambientTexture->isLoaded()) {
|
||||
_pendingAmbientTexture = false;
|
||||
if (_ambientTexture->getGPUTexture()->getIrradiance()) {
|
||||
sceneKeyLight->setAmbientSphere(_ambientTexture->getGPUTexture()->getIrradiance());
|
||||
sceneKeyLight->setAmbientMap(_ambientTexture->getGPUTexture());
|
||||
|
||||
auto texture = _ambientTexture->getGPUTexture();
|
||||
if (texture) {
|
||||
sceneKeyLight->setAmbientSphere(texture->getIrradiance());
|
||||
sceneKeyLight->setAmbientMap(texture);
|
||||
isAmbientTextureSet = true;
|
||||
} else {
|
||||
qCDebug(entitiesrenderer) << "Failed to load ambient texture:" << zone->getKeyLightProperties().getAmbientURL();
|
||||
}
|
||||
} else {
|
||||
_pendingAmbientTexture = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -344,24 +352,27 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
|||
skybox->parse(userData);
|
||||
}
|
||||
if (zone->getSkyboxProperties().getURL().isEmpty()) {
|
||||
skybox->setCubemap(gpu::TexturePointer());
|
||||
skybox->setCubemap(nullptr);
|
||||
_pendingSkyboxTexture = false;
|
||||
_skyboxTexture.clear();
|
||||
} else {
|
||||
// Update the Texture of the Skybox with the one pointed by this zone
|
||||
_skyboxTexture = textureCache->getTexture(zone->getSkyboxProperties().getURL(), CUBE_TEXTURE);
|
||||
_pendingSkyboxTexture = true;
|
||||
|
||||
if (_skyboxTexture && _skyboxTexture->isLoaded()) {
|
||||
_pendingSkyboxTexture = false;
|
||||
|
||||
if (_skyboxTexture && _skyboxTexture->isLoaded() && _skyboxTexture->getGPUTexture()) {
|
||||
auto texture = _skyboxTexture->getGPUTexture();
|
||||
skybox->setCubemap(texture);
|
||||
_pendingSkyboxTexture = false;
|
||||
if (!isAmbientTextureSet && texture->getIrradiance()) {
|
||||
if (!isAmbientTextureSet) {
|
||||
sceneKeyLight->setAmbientSphere(texture->getIrradiance());
|
||||
sceneKeyLight->setAmbientMap(texture);
|
||||
isAmbientTextureSet = true;
|
||||
}
|
||||
} else {
|
||||
_pendingSkyboxTexture = true;
|
||||
skybox->setCubemap(nullptr);
|
||||
qCDebug(entitiesrenderer) << "Failed to load skybox:" << zone->getSkyboxProperties().getURL();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
#include <ObjectMotionState.h>
|
||||
#include <PerfStat.h>
|
||||
|
||||
#include "../render-utils/simple_vert.h"
|
||||
#include "../render-utils/simple_frag.h"
|
||||
#include <render-utils/simple_vert.h>
|
||||
#include <render-utils/simple_frag.h>
|
||||
|
||||
EntityItemPointer RenderableBoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
EntityItemPointer entity{ new RenderableBoxEntityItem(entityID) };
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
#include <GeometryCache.h>
|
||||
#include <PerfStat.h>
|
||||
|
||||
#include "../render-utils/simple_vert.h"
|
||||
#include "../render-utils/simple_frag.h"
|
||||
#include <render-utils/simple_vert.h>
|
||||
#include <render-utils/simple_frag.h>
|
||||
|
||||
// Sphere entities should fit inside a cube entity of the same size, so a sphere that has dimensions 1x1x1
|
||||
// is a half unit sphere. However, the geometry cache renders a UNIT sphere, so we need to scale down.
|
||||
|
|
|
@ -86,6 +86,11 @@ void EntityTree::postAddEntity(EntityItemPointer entity) {
|
|||
if (_simulation) {
|
||||
_simulation->addEntity(entity);
|
||||
}
|
||||
|
||||
if (!entity->isParentIDValid()) {
|
||||
_missingParent.append(entity);
|
||||
}
|
||||
|
||||
_isDirty = true;
|
||||
maybeNotifyNewCollisionSoundURL("", entity->getCollisionSoundURL());
|
||||
emit addingEntity(entity->getEntityItemID());
|
||||
|
@ -252,6 +257,9 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
|
|||
_missingParent.append(childEntity);
|
||||
continue;
|
||||
}
|
||||
if (!childEntity->isParentIDValid()) {
|
||||
_missingParent.append(childEntity);
|
||||
}
|
||||
|
||||
UpdateEntityOperator theChildOperator(getThisPointer(), containingElement, childEntity, queryCube);
|
||||
recurseTreeWithOperator(&theChildOperator);
|
||||
|
@ -448,6 +456,17 @@ void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator)
|
|||
const RemovedEntities& entities = theOperator.getEntities();
|
||||
foreach(const EntityToDeleteDetails& details, entities) {
|
||||
EntityItemPointer theEntity = details.entity;
|
||||
|
||||
if (getIsServer()) {
|
||||
QSet<EntityItemID> childrenIDs;
|
||||
theEntity->forEachChild([&](SpatiallyNestablePointer child) {
|
||||
if (child->getNestableType() == NestableType::Entity) {
|
||||
childrenIDs += child->getID();
|
||||
}
|
||||
});
|
||||
deleteEntities(childrenIDs, true, true);
|
||||
}
|
||||
|
||||
theEntity->die();
|
||||
|
||||
if (getIsServer()) {
|
||||
|
@ -992,21 +1011,37 @@ void EntityTree::fixupMissingParents() {
|
|||
EntityItemWeakPointer entityWP = iter.next();
|
||||
EntityItemPointer entity = entityWP.lock();
|
||||
if (entity) {
|
||||
bool maxAACubeSuccess;
|
||||
AACube maxAACube = entity->getMaximumAACube(maxAACubeSuccess);
|
||||
bool queryAACubeSuccess;
|
||||
AACube newCube = entity->getQueryAACube(queryAACubeSuccess);
|
||||
if (!maxAACubeSuccess || !queryAACubeSuccess) {
|
||||
continue;
|
||||
if (queryAACubeSuccess) {
|
||||
// make sure queryAACube encompasses maxAACube
|
||||
bool maxAACubeSuccess;
|
||||
AACube maxAACube = entity->getMaximumAACube(maxAACubeSuccess);
|
||||
if (maxAACubeSuccess && !newCube.contains(maxAACube)) {
|
||||
newCube = maxAACube;
|
||||
}
|
||||
}
|
||||
if (!newCube.contains(maxAACube)) {
|
||||
newCube = maxAACube;
|
||||
|
||||
bool doMove = false;
|
||||
if (entity->isParentIDValid()) {
|
||||
// this entity's parent was previously not known, and now is. Update its location in the EntityTree...
|
||||
iter.remove();
|
||||
doMove = true;
|
||||
} else if (getIsServer() && _avatarIDs.contains(entity->getParentID())) {
|
||||
// this is a child of an avatar, which the entity server will never have
|
||||
// a SpatiallyNestable object for. Add it to a list for cleanup when the avatar leaves.
|
||||
if (!_childrenOfAvatars.contains(entity->getParentID())) {
|
||||
_childrenOfAvatars[entity->getParentID()] = QSet<EntityItemID>();
|
||||
}
|
||||
_childrenOfAvatars[entity->getParentID()] += entity->getEntityItemID();
|
||||
doMove = true;
|
||||
}
|
||||
|
||||
if (queryAACubeSuccess && doMove) {
|
||||
moveOperator.addEntityToMoveList(entity, newCube);
|
||||
iter.remove();
|
||||
entity->markAncestorMissing(false);
|
||||
}
|
||||
// this entity's parent (or ancestry) was previously not fully known, and now is. Update its
|
||||
// location in the EntityTree.
|
||||
moveOperator.addEntityToMoveList(entity, newCube);
|
||||
iter.remove();
|
||||
entity->markAncestorMissing(false);
|
||||
} else {
|
||||
// entity was deleted before we found its parent.
|
||||
iter.remove();
|
||||
|
@ -1017,7 +1052,13 @@ void EntityTree::fixupMissingParents() {
|
|||
PerformanceTimer perfTimer("recurseTreeWithOperator");
|
||||
recurseTreeWithOperator(&moveOperator);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityTree::deleteDescendantsOfAvatar(QUuid avatarID) {
|
||||
if (_childrenOfAvatars.contains(avatarID)) {
|
||||
deleteEntities(_childrenOfAvatars[avatarID]);
|
||||
_childrenOfAvatars.remove(avatarID);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityTree::update() {
|
||||
|
|
|
@ -241,6 +241,10 @@ public:
|
|||
Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name) const;
|
||||
Q_INVOKABLE QStringList getJointNames(const QUuid& entityID) const;
|
||||
|
||||
void knowAvatarID(QUuid avatarID) { _avatarIDs += avatarID; }
|
||||
void forgetAvatarID(QUuid avatarID) { _avatarIDs -= avatarID; }
|
||||
void deleteDescendantsOfAvatar(QUuid avatarID);
|
||||
|
||||
public slots:
|
||||
void callLoader(EntityItemID entityID);
|
||||
|
||||
|
@ -313,8 +317,11 @@ protected:
|
|||
quint64 _maxEditDelta = 0;
|
||||
quint64 _treeResetTime = 0;
|
||||
|
||||
void fixupMissingParents();
|
||||
QVector<EntityItemWeakPointer> _missingParent;
|
||||
void fixupMissingParents(); // try to hook members of _missingParent to parent instances
|
||||
QVector<EntityItemWeakPointer> _missingParent; // entites with a parentID but no (yet) known parent instance
|
||||
// we maintain a list of avatarIDs to notice when an entity is a child of one.
|
||||
QSet<QUuid> _avatarIDs; // IDs of avatars connected to entity server
|
||||
QHash<QUuid, QSet<EntityItemID>> _childrenOfAvatars; // which entities are children of which avatars
|
||||
};
|
||||
|
||||
#endif // hifi_EntityTree_h
|
||||
|
|
|
@ -33,6 +33,7 @@ static const char * SIMPLE_TEXTURED_FS = R"FS(#version 410 core
|
|||
#pragma line __LINE__
|
||||
|
||||
uniform sampler2D sampler;
|
||||
uniform float alpha = 1.0;
|
||||
|
||||
in vec2 vTexCoord;
|
||||
out vec4 FragColor;
|
||||
|
@ -40,6 +41,7 @@ out vec4 FragColor;
|
|||
void main() {
|
||||
|
||||
FragColor = texture(sampler, vTexCoord);
|
||||
FragColor.a *= alpha;
|
||||
}
|
||||
|
||||
)FS";
|
||||
|
|
|
@ -146,7 +146,7 @@ public:
|
|||
|
||||
NetworkTexturePointer TextureCache::getTexture(const QUrl& url, TextureType type, const QByteArray& content) {
|
||||
TextureExtra extra = { type, content };
|
||||
return ResourceCache::getResource(url, QUrl(), false, &extra).staticCast<NetworkTexture>();
|
||||
return ResourceCache::getResource(url, QUrl(), content.isEmpty(), &extra).staticCast<NetworkTexture>();
|
||||
}
|
||||
|
||||
/// Returns a texture version of an image file
|
||||
|
|
|
@ -101,8 +101,6 @@ private:
|
|||
/// A simple object wrapper for an OpenGL texture.
|
||||
class Texture {
|
||||
public:
|
||||
friend class TextureCache;
|
||||
|
||||
gpu::TexturePointer getGPUTexture() const { return _textureSource->getGPUTexture(); }
|
||||
gpu::TextureSourcePointer _textureSource;
|
||||
};
|
||||
|
|
|
@ -15,71 +15,68 @@
|
|||
#include <gpu/Context.h>
|
||||
#include <ViewFrustum.h>
|
||||
|
||||
#include "Skybox_vert.h"
|
||||
#include "Skybox_frag.h"
|
||||
#include "skybox_vert.h"
|
||||
#include "skybox_frag.h"
|
||||
|
||||
using namespace model;
|
||||
|
||||
Skybox::Skybox() {
|
||||
Data data;
|
||||
_dataBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Data), (const gpu::Byte*) &data));
|
||||
|
||||
/* // PLease create a default engineer skybox
|
||||
_cubemap.reset( gpu::Texture::createCube(gpu::Element::COLOR_RGBA_32, 1));
|
||||
unsigned char texels[] = {
|
||||
255, 0, 0, 255,
|
||||
0, 255, 255, 255,
|
||||
0, 0, 255, 255,
|
||||
255, 255, 0, 255,
|
||||
0, 255, 0, 255,
|
||||
255, 0, 255, 255,
|
||||
};
|
||||
_cubemap->assignStoredMip(0, gpu::Element::COLOR_RGBA_32, sizeof(texels), texels);*/
|
||||
Schema schema;
|
||||
_schemaBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema));
|
||||
}
|
||||
|
||||
void Skybox::setColor(const Color& color) {
|
||||
_dataBuffer.edit<Data>()._color = color;
|
||||
_schemaBuffer.edit<Schema>().color = color;
|
||||
}
|
||||
|
||||
void Skybox::setCubemap(const gpu::TexturePointer& cubemap) {
|
||||
_cubemap = cubemap;
|
||||
}
|
||||
|
||||
|
||||
void Skybox::updateDataBuffer() const {
|
||||
void Skybox::updateSchemaBuffer() const {
|
||||
auto blend = 0.0f;
|
||||
if (getCubemap() && getCubemap()->isDefined()) {
|
||||
blend = 1.0f;
|
||||
blend = 0.5f;
|
||||
|
||||
// If pitch black neutralize the color
|
||||
if (glm::all(glm::equal(getColor(), glm::vec3(0.0f)))) {
|
||||
blend = 2.0f;
|
||||
blend = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (blend != _dataBuffer.get<Data>()._blend) {
|
||||
_dataBuffer.edit<Data>()._blend = blend;
|
||||
if (blend != _schemaBuffer.get<Schema>().blend) {
|
||||
_schemaBuffer.edit<Schema>().blend = blend;
|
||||
}
|
||||
}
|
||||
|
||||
void Skybox::prepare(gpu::Batch& batch, int textureSlot, int bufferSlot) const {
|
||||
if (bufferSlot > -1) {
|
||||
batch.setUniformBuffer(bufferSlot, _schemaBuffer);
|
||||
}
|
||||
|
||||
|
||||
void Skybox::render(gpu::Batch& batch, const ViewFrustum& frustum) const {
|
||||
updateDataBuffer();
|
||||
Skybox::render(batch, frustum, (*this));
|
||||
if (textureSlot > -1) {
|
||||
gpu::TexturePointer skymap = getCubemap();
|
||||
// FIXME: skymap->isDefined may not be threadsafe
|
||||
if (skymap && skymap->isDefined()) {
|
||||
batch.setResourceTexture(textureSlot, skymap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Skybox::render(gpu::Batch& batch, const ViewFrustum& frustum) const {
|
||||
updateSchemaBuffer();
|
||||
Skybox::render(batch, frustum, (*this));
|
||||
}
|
||||
|
||||
void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Skybox& skybox) {
|
||||
// Create the static shared elements used to render the skybox
|
||||
static gpu::BufferPointer theConstants;
|
||||
static gpu::PipelinePointer thePipeline;
|
||||
const int SKYBOX_SKYMAP_SLOT = 0;
|
||||
const int SKYBOX_CONSTANTS_SLOT = 0;
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&] {
|
||||
{
|
||||
auto skyVS = gpu::Shader::createVertex(std::string(Skybox_vert));
|
||||
auto skyFS = gpu::Shader::createPixel(std::string(Skybox_frag));
|
||||
auto skyVS = gpu::Shader::createVertex(std::string(skybox_vert));
|
||||
auto skyFS = gpu::Shader::createPixel(std::string(skybox_frag));
|
||||
auto skyShader = gpu::Shader::createProgram(skyVS, skyFS);
|
||||
|
||||
gpu::Shader::BindingSet bindings;
|
||||
|
@ -98,10 +95,6 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
|
|||
|
||||
|
||||
// Render
|
||||
gpu::TexturePointer skymap = skybox.getCubemap();
|
||||
// FIXME: skymap->isDefined may not be threadsafe
|
||||
assert(skymap && skymap->isDefined());
|
||||
|
||||
glm::mat4 projMat;
|
||||
viewFrustum.evalProjectionMatrix(projMat);
|
||||
|
||||
|
@ -112,11 +105,8 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
|
|||
batch.setModelTransform(Transform()); // only for Mac
|
||||
|
||||
batch.setPipeline(thePipeline);
|
||||
batch.setUniformBuffer(SKYBOX_CONSTANTS_SLOT, skybox._dataBuffer);
|
||||
batch.setResourceTexture(SKYBOX_SKYMAP_SLOT, skymap);
|
||||
|
||||
skybox.prepare(batch);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
|
||||
batch.setResourceTexture(SKYBOX_SKYMAP_SLOT, nullptr);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,30 +30,33 @@ public:
|
|||
virtual ~Skybox() {};
|
||||
|
||||
void setColor(const Color& color);
|
||||
const Color getColor() const { return _dataBuffer.get<Data>()._color; }
|
||||
const Color getColor() const { return _schemaBuffer.get<Schema>().color; }
|
||||
|
||||
void setCubemap(const gpu::TexturePointer& cubemap);
|
||||
const gpu::TexturePointer& getCubemap() const { return _cubemap; }
|
||||
|
||||
void prepare(gpu::Batch& batch, int textureSlot = SKYBOX_SKYMAP_SLOT, int bufferSlot = SKYBOX_CONSTANTS_SLOT) const;
|
||||
virtual void render(gpu::Batch& batch, const ViewFrustum& frustum) const;
|
||||
|
||||
|
||||
static void render(gpu::Batch& batch, const ViewFrustum& frustum, const Skybox& skybox);
|
||||
|
||||
protected:
|
||||
static const int SKYBOX_SKYMAP_SLOT { 0 };
|
||||
static const int SKYBOX_CONSTANTS_SLOT { 0 };
|
||||
|
||||
gpu::TexturePointer _cubemap;
|
||||
|
||||
class Data {
|
||||
class Schema {
|
||||
public:
|
||||
glm::vec3 _color{ 1.0f, 1.0f, 1.0f };
|
||||
float _blend = 1.0f;
|
||||
glm::vec3 color { 1.0f, 1.0f, 1.0f };
|
||||
float blend { 0.0f };
|
||||
};
|
||||
|
||||
mutable gpu::BufferView _dataBuffer;
|
||||
mutable gpu::BufferView _schemaBuffer;
|
||||
|
||||
void updateDataBuffer() const;
|
||||
void updateSchemaBuffer() const;
|
||||
};
|
||||
typedef std::shared_ptr< Skybox > SkyboxPointer;
|
||||
typedef std::shared_ptr<Skybox> SkyboxPointer;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
// skybox.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Sam Gateau on 5/5/2015.
|
||||
// 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
|
||||
//
|
||||
|
||||
uniform samplerCube cubeMap;
|
||||
|
||||
struct Skybox {
|
||||
vec4 _color;
|
||||
};
|
||||
|
||||
uniform skyboxBuffer {
|
||||
Skybox _skybox;
|
||||
};
|
||||
|
||||
in vec3 _normal;
|
||||
out vec4 _fragColor;
|
||||
|
||||
//PROCEDURAL_COMMON_BLOCK
|
||||
|
||||
#line 1001
|
||||
//PROCEDURAL_BLOCK
|
||||
|
||||
#line 2033
|
||||
void main(void) {
|
||||
|
||||
#ifdef PROCEDURAL
|
||||
|
||||
vec3 color = getSkyboxColor();
|
||||
_fragColor = vec4(color, 0.0);
|
||||
|
||||
#else
|
||||
|
||||
vec3 coord = normalize(_normal);
|
||||
|
||||
// Skybox color or blend with skymap
|
||||
vec3 color = _skybox._color.rgb;
|
||||
if (_skybox._color.a > 0.0) {
|
||||
vec3 texel = texture(cubeMap, coord).rgb;
|
||||
if (_skybox._color.a < 2.0) {
|
||||
color *= texel;
|
||||
} else {
|
||||
color = texel;
|
||||
}
|
||||
}
|
||||
|
||||
_fragColor = vec4(color, 0.0);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
19
libraries/procedural/src/procedural/ProceduralSkybox.slf → libraries/model/src/model/skybox.slf
Normal file → Executable file
19
libraries/procedural/src/procedural/ProceduralSkybox.slf → libraries/model/src/model/skybox.slf
Normal file → Executable file
|
@ -14,11 +14,11 @@
|
|||
uniform samplerCube cubeMap;
|
||||
|
||||
struct Skybox {
|
||||
vec4 _color;
|
||||
vec4 color;
|
||||
};
|
||||
|
||||
uniform skyboxBuffer {
|
||||
Skybox _skybox;
|
||||
Skybox skybox;
|
||||
};
|
||||
|
||||
in vec3 _normal;
|
||||
|
@ -39,11 +39,20 @@ void main(void) {
|
|||
color = pow(color, vec3(2.2));
|
||||
_fragColor = vec4(color, 0.0);
|
||||
|
||||
#else
|
||||
// FIXME: scribe does not yet scrub out else statements
|
||||
return;
|
||||
|
||||
#else
|
||||
vec3 coord = normalize(_normal);
|
||||
vec3 texel = texture(cubeMap, coord).rgb;
|
||||
vec3 color = texel * _skybox._color.rgb;
|
||||
vec3 color = skybox.color.rgb;
|
||||
|
||||
// blend is only set if there is a cubemap
|
||||
if (skybox.color.a > 0.0) {
|
||||
color = texture(cubeMap, coord).rgb;
|
||||
if (skybox.color.a < 1.0) {
|
||||
color *= skybox.color.rgb;
|
||||
}
|
||||
}
|
||||
_fragColor = vec4(color, 0.0);
|
||||
|
||||
#endif
|
|
@ -65,6 +65,12 @@ public:
|
|||
virtual bool isThrottled() const { return false; }
|
||||
virtual float getTargetFrameRate() { return 0.0f; }
|
||||
|
||||
/// Returns a boolean value indicating whether the display is currently visible
|
||||
/// to the user. For monitor displays, false might indicate that a screensaver,
|
||||
/// or power-save mode is active. For HMDs it may reflect a sensor indicating
|
||||
/// whether the HMD is being worn
|
||||
virtual bool isDisplayVisible() const { return false; }
|
||||
|
||||
// Rendering support
|
||||
|
||||
// Stop requesting renders, but don't do full deactivation
|
||||
|
|
|
@ -101,6 +101,7 @@ bool Procedural::parseUrl(const QUrl& shaderUrl) {
|
|||
}
|
||||
|
||||
_shaderUrl = shaderUrl;
|
||||
_shaderDirty = true;
|
||||
|
||||
if (_shaderUrl.isLocalFile()) {
|
||||
_shaderPath = _shaderUrl.toLocalFile();
|
||||
|
@ -230,7 +231,10 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm
|
|||
if (replaceIndex != std::string::npos) {
|
||||
fragmentShaderSource.replace(replaceIndex, PROCEDURAL_BLOCK.size(), _shaderSource.toLocal8Bit().data());
|
||||
}
|
||||
//qDebug() << "FragmentShader:\n" << fragmentShaderSource.c_str();
|
||||
|
||||
// Leave this here for debugging
|
||||
// qDebug() << "FragmentShader:\n" << fragmentShaderSource.c_str();
|
||||
|
||||
_fragmentShader = gpu::Shader::createPixel(fragmentShaderSource);
|
||||
_shader = gpu::Shader::createProgram(_vertexShader, _fragmentShader);
|
||||
|
||||
|
@ -370,7 +374,8 @@ void Procedural::setupUniforms() {
|
|||
v.y = date.month() - 1;
|
||||
// But not the day... go figure
|
||||
v.z = date.day();
|
||||
v.w = (time.hour() * 3600) + (time.minute() * 60) + time.second();
|
||||
float fractSeconds = (time.msec() / 1000.0f);
|
||||
v.w = (time.hour() * 3600) + (time.minute() * 60) + time.second() + fractSeconds;
|
||||
batch._glUniform(_standardUniformSlots[DATE], v);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ public:
|
|||
|
||||
bool ready();
|
||||
void prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size);
|
||||
const gpu::ShaderPointer& getShader() const { return _shader; }
|
||||
|
||||
glm::vec4 getColor(const glm::vec4& entityColor);
|
||||
|
||||
|
|
|
@ -15,40 +15,39 @@
|
|||
#include <gpu/Context.h>
|
||||
#include <ViewFrustum.h>
|
||||
|
||||
#include "ProceduralSkybox_vert.h"
|
||||
#include "ProceduralSkybox_frag.h"
|
||||
#include <model/skybox_vert.h>
|
||||
#include <model/skybox_frag.h>
|
||||
|
||||
ProceduralSkybox::ProceduralSkybox() : model::Skybox() {
|
||||
_procedural._vertexSource = ProceduralSkybox_vert;
|
||||
_procedural._fragmentSource = ProceduralSkybox_frag;
|
||||
_procedural._vertexSource = skybox_vert;
|
||||
_procedural._fragmentSource = skybox_frag;
|
||||
// Adjust the pipeline state for background using the stencil test
|
||||
_procedural._state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
}
|
||||
|
||||
void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& frustum) const {
|
||||
ProceduralSkybox::render(batch, frustum, (*this));
|
||||
if (_procedural.ready()) {
|
||||
ProceduralSkybox::render(batch, frustum, (*this));
|
||||
} else {
|
||||
Skybox::render(batch, frustum);
|
||||
}
|
||||
}
|
||||
|
||||
void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const ProceduralSkybox& skybox) {
|
||||
if (!(skybox._procedural.ready())) {
|
||||
skybox.updateDataBuffer();
|
||||
Skybox::render(batch, viewFrustum, skybox);
|
||||
} else {
|
||||
gpu::TexturePointer skymap = skybox.getCubemap();
|
||||
// FIXME: skymap->isDefined may not be threadsafe
|
||||
assert(skymap && skymap->isDefined());
|
||||
glm::mat4 projMat;
|
||||
viewFrustum.evalProjectionMatrix(projMat);
|
||||
|
||||
glm::mat4 projMat;
|
||||
viewFrustum.evalProjectionMatrix(projMat);
|
||||
Transform viewTransform;
|
||||
viewFrustum.evalViewTransform(viewTransform);
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewTransform);
|
||||
batch.setModelTransform(Transform()); // only for Mac
|
||||
|
||||
Transform viewTransform;
|
||||
viewFrustum.evalViewTransform(viewTransform);
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewTransform);
|
||||
batch.setModelTransform(Transform()); // only for Mac
|
||||
batch.setResourceTexture(0, skybox.getCubemap());
|
||||
|
||||
skybox._procedural.prepare(batch, glm::vec3(0), glm::vec3(1));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
}
|
||||
auto& procedural = skybox._procedural;
|
||||
procedural.prepare(batch, glm::vec3(0), glm::vec3(1));
|
||||
auto textureSlot = procedural.getShader()->getTextures().findLocation("cubeMap");
|
||||
auto bufferSlot = procedural.getShader()->getBuffers().findLocation("skyboxBuffer");
|
||||
skybox.prepare(batch, textureSlot, bufferSlot);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
// skybox.vert
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Sam Gateau on 5/5/2015.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
out vec3 _normal;
|
||||
|
||||
void main(void) {
|
||||
const float depth = 0.0;
|
||||
const vec4 UNIT_QUAD[4] = vec4[4](
|
||||
vec4(-1.0, -1.0, depth, 1.0),
|
||||
vec4(1.0, -1.0, depth, 1.0),
|
||||
vec4(-1.0, 1.0, depth, 1.0),
|
||||
vec4(1.0, 1.0, depth, 1.0)
|
||||
);
|
||||
vec4 inPosition = UNIT_QUAD[gl_VertexID];
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
vec3 clipDir = vec3(inPosition.xy, 0.0);
|
||||
vec3 eyeDir;
|
||||
<$transformClipToEyeDir(cam, clipDir, eyeDir)$>
|
||||
<$transformEyeToWorldDir(cam, eyeDir, _normal)$>
|
||||
|
||||
// Position is supposed to come in clip space
|
||||
gl_Position = vec4(inPosition.xy, 0.0, 1.0);
|
||||
}
|
|
@ -392,13 +392,20 @@ void AnimDebugDraw::update() {
|
|||
|
||||
assert(numVerts == (v - verts));
|
||||
|
||||
// The RenderItem culling is not working correctly
|
||||
// Workaround this issue by using the default constructed
|
||||
// item._bound which is a 16 km cube.
|
||||
/*
|
||||
render::Item::Bound theBound;
|
||||
for (int i = 0; i < numVerts; i++) {
|
||||
theBound += verts[i].pos;
|
||||
}
|
||||
data._bound = theBound;
|
||||
*/
|
||||
|
||||
data._isVisible = (numVerts > 0);
|
||||
data._bound = theBound;
|
||||
|
||||
|
||||
data._indexBuffer->resize(sizeof(uint16_t) * numVerts);
|
||||
uint16_t* indices = (uint16_t*)data._indexBuffer->editData();
|
||||
for (int i = 0; i < numVerts; i++) {
|
||||
|
|
|
@ -96,6 +96,9 @@ void Scene::processPendingChangesQueue() {
|
|||
// removes
|
||||
removeItems(consolidatedPendingChanges._removedItems);
|
||||
|
||||
// Update the numItemsAtomic counter AFTER the pending changes went through
|
||||
_numAllocatedItems.exchange(maxID);
|
||||
|
||||
// ready to go back to rendering activities
|
||||
_itemsMutex.unlock();
|
||||
}
|
||||
|
|
|
@ -264,12 +264,33 @@ Octree::Index Octree::accessCellBrick(Index cellID, const CellBrickAccessor& acc
|
|||
return brickID;
|
||||
}
|
||||
|
||||
Octree::Location ItemSpatialTree::evalLocation(const AABox& bound, Coord3f& minCoordf, Coord3f& maxCoordf) const {
|
||||
minCoordf = evalCoordf(bound.getMinimumPoint());
|
||||
maxCoordf = evalCoordf(bound.getMaximumPoint());
|
||||
|
||||
// If the bound crosses any of the octree volume limit, then return root cell
|
||||
if ( (minCoordf.x < 0.0f)
|
||||
|| (minCoordf.y < 0.0f)
|
||||
|| (minCoordf.z < 0.0f)
|
||||
|| (maxCoordf.x >= _size)
|
||||
|| (maxCoordf.y >= _size)
|
||||
|| (maxCoordf.z >= _size)) {
|
||||
return Location();
|
||||
}
|
||||
|
||||
Coord3 minCoord(minCoordf);
|
||||
Coord3 maxCoord(maxCoordf);
|
||||
return Location::evalFromRange(minCoord, maxCoord);
|
||||
}
|
||||
|
||||
Octree::Locations ItemSpatialTree::evalLocations(const ItemBounds& bounds) const {
|
||||
Locations locations;
|
||||
Coord3f minCoordf, maxCoordf;
|
||||
|
||||
locations.reserve(bounds.size());
|
||||
for (auto& bound : bounds) {
|
||||
if (!bound.bound.isNull()) {
|
||||
locations.emplace_back(evalLocation(bound.bound));
|
||||
locations.emplace_back(evalLocation(bound.bound, minCoordf, maxCoordf));
|
||||
} else {
|
||||
locations.emplace_back(Location());
|
||||
}
|
||||
|
@ -344,11 +365,8 @@ bool ItemSpatialTree::removeItem(Index cellIdx, const ItemKey& key, const ItemID
|
|||
ItemSpatialTree::Index ItemSpatialTree::resetItem(Index oldCell, const ItemKey& oldKey, const AABox& bound, const ItemID& item, ItemKey& newKey) {
|
||||
auto newCell = INVALID_CELL;
|
||||
if (!newKey.isViewSpace()) {
|
||||
auto minCoordf = evalCoordf(bound.getMinimumPoint());
|
||||
auto maxCoordf = evalCoordf(bound.getMaximumPoint());
|
||||
Coord3 minCoord(minCoordf);
|
||||
Coord3 maxCoord(maxCoordf);
|
||||
auto location = Location::evalFromRange(minCoord, maxCoord);
|
||||
Coord3f minCoordf, maxCoordf;
|
||||
auto location = evalLocation(bound, minCoordf, maxCoordf);
|
||||
|
||||
// Compare range size vs cell location size and tag itemKey accordingly
|
||||
// If Item bound fits in sub cell then tag as small
|
||||
|
@ -403,7 +421,21 @@ ItemSpatialTree::Index ItemSpatialTree::resetItem(Index oldCell, const ItemKey&
|
|||
int Octree::select(CellSelection& selection, const FrustumSelector& selector) const {
|
||||
|
||||
Index cellID = ROOT_CELL;
|
||||
return selectTraverse(cellID, selection, selector);
|
||||
auto cell = getConcreteCell(cellID);
|
||||
int numSelectedsIn = (int)selection.size();
|
||||
|
||||
// Always include the root cell partially containing potentially outer objects
|
||||
selectCellBrick(cellID, selection, false);
|
||||
|
||||
// then traverse deeper
|
||||
for (int i = 0; i < NUM_OCTANTS; i++) {
|
||||
Index subCellID = cell.child((Link)i);
|
||||
if (subCellID != INVALID_CELL) {
|
||||
selectTraverse(subCellID, selection, selector);
|
||||
}
|
||||
}
|
||||
|
||||
return (int)selection.size() - numSelectedsIn;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -117,7 +117,6 @@ namespace render {
|
|||
return depth;
|
||||
}
|
||||
|
||||
|
||||
class Location {
|
||||
void assertValid() {
|
||||
assert((pos.x >= 0) && (pos.y >= 0) && (pos.z >= 0));
|
||||
|
@ -157,6 +156,7 @@ namespace render {
|
|||
// Eval the location best fitting the specified range
|
||||
static Location evalFromRange(const Coord3& minCoord, const Coord3& maxCoord, Depth rangeDepth = MAX_DEPTH);
|
||||
|
||||
|
||||
// Eval the intersection test against a frustum
|
||||
enum Intersection {
|
||||
Outside = 0,
|
||||
|
@ -367,7 +367,7 @@ namespace render {
|
|||
// An octree of Items organizing them efficiently for culling
|
||||
// The octree only cares about the bound & the key of an item to store it a the right cell location
|
||||
class ItemSpatialTree : public Octree {
|
||||
float _size { 32768.0f };
|
||||
float _size{ 32768.0f };
|
||||
float _invSize { 1.0f / _size };
|
||||
glm::vec3 _origin { -16384.0f };
|
||||
|
||||
|
@ -398,10 +398,26 @@ namespace render {
|
|||
return getOrigin() + glm::vec3(coord) * cellWidth;
|
||||
}
|
||||
|
||||
|
||||
// Clamp a 3D relative position to make sure it is in the valid range space of the octree
|
||||
glm::vec3 clampRelPosToTreeRange(const glm::vec3& pos) const {
|
||||
const float EPSILON = 0.0001f;
|
||||
return glm::vec3(
|
||||
std::min(std::max(pos.x, 0.0f), _size - EPSILON),
|
||||
std::min(std::max(pos.y, 0.0f), _size - EPSILON),
|
||||
std::min(std::max(pos.z, 0.0f), _size - EPSILON));
|
||||
}
|
||||
|
||||
// Eval an integer cell coordinate (at the specified deepth) from a given 3d position
|
||||
// If the 3D position is out of the octree volume, then the position is clamped
|
||||
// so the integer coordinate is meaningfull
|
||||
Coord3 evalCoord(const glm::vec3& pos, Depth depth = Octree::METRIC_COORD_DEPTH) const {
|
||||
auto npos = (pos - getOrigin());
|
||||
auto npos = clampRelPosToTreeRange((pos - getOrigin()));
|
||||
return Coord3(npos * getInvCellWidth(depth)); // Truncate fractional part
|
||||
}
|
||||
|
||||
// Eval a real cell coordinate (at the specified deepth) from a given 3d position
|
||||
// Position is NOT clamped to the boundaries of the octree so beware of conversion to a Coord3!
|
||||
Coord3f evalCoordf(const glm::vec3& pos, Depth depth = Octree::METRIC_COORD_DEPTH) const {
|
||||
auto npos = (pos - getOrigin());
|
||||
return Coord3f(npos * getInvCellWidth(depth));
|
||||
|
@ -412,9 +428,10 @@ namespace render {
|
|||
float cellWidth = getCellWidth(loc.depth);
|
||||
return AABox(evalPos(loc.pos, cellWidth), cellWidth);
|
||||
}
|
||||
Location evalLocation(const AABox& bound) const {
|
||||
return Location::evalFromRange(evalCoord(bound.getMinimumPoint()), evalCoord(bound.getMaximumPoint()));
|
||||
}
|
||||
|
||||
// Eval the cell location for a given arbitrary Bound,
|
||||
// if the Bound crosses any of the Octree planes then the root cell is returned
|
||||
Location evalLocation(const AABox& bound, Coord3f& minCoordf, Coord3f& maxCoordf) const;
|
||||
Locations evalLocations(const ItemBounds& bounds) const;
|
||||
|
||||
// Managing itemsInserting items in cells
|
||||
|
|
|
@ -115,9 +115,6 @@ void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailable
|
|||
auto scriptContent = _scriptCache[url];
|
||||
lock.unlock();
|
||||
qCDebug(scriptengine) << "Found script in cache:" << url.toString();
|
||||
#if 1 // def THREAD_DEBUGGING
|
||||
qCDebug(scriptengine) << "ScriptCache::getScriptContents() about to call contentAvailable() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
|
||||
#endif
|
||||
contentAvailable(url.toString(), scriptContent, true, true);
|
||||
} else {
|
||||
bool alreadyWaiting = _contentCallbacks.contains(url);
|
||||
|
|
|
@ -471,3 +471,11 @@ bool isNaN(glm::quat value) {
|
|||
return isNaN(value.w) || isNaN(value.x) || isNaN(value.y) || isNaN(value.z);
|
||||
}
|
||||
|
||||
glm::mat4 orthoInverse(const glm::mat4& m) {
|
||||
glm::mat4 r = m;
|
||||
r[3] = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
r = glm::transpose(r);
|
||||
r[3] = -(r * m[3]);
|
||||
r[3][3] = 1.0f;
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -232,4 +232,6 @@ glm::vec2 getFacingDir2D(const glm::mat4& m);
|
|||
bool isNaN(glm::vec3 value);
|
||||
bool isNaN(glm::quat value);
|
||||
|
||||
glm::mat4 orthoInverse(const glm::mat4& m);
|
||||
|
||||
#endif // hifi_GLMHelpers_h
|
||||
|
|
|
@ -104,6 +104,7 @@ void updateQmlItemFromAction(QObject* target, QAction* source) {
|
|||
target->setProperty("checkable", source->isCheckable());
|
||||
target->setProperty("enabled", source->isEnabled());
|
||||
target->setProperty("text", source->text());
|
||||
target->setProperty("shortcut", source->shortcut().toString());
|
||||
target->setProperty("checked", source->isChecked());
|
||||
target->setProperty("visible", source->isVisible());
|
||||
}
|
||||
|
@ -190,6 +191,20 @@ void VrMenu::addAction(QMenu* menu, QAction* action) {
|
|||
bindActionToQmlAction(result, action);
|
||||
}
|
||||
|
||||
void VrMenu::addSeparator(QMenu* menu) {
|
||||
Q_ASSERT(MenuUserData::forObject(menu));
|
||||
MenuUserData* userData = MenuUserData::forObject(menu);
|
||||
if (!userData) {
|
||||
return;
|
||||
}
|
||||
QObject* menuQml = findMenuObject(userData->uuid.toString());
|
||||
Q_ASSERT(menuQml);
|
||||
|
||||
bool invokeResult = QMetaObject::invokeMethod(menuQml, "addSeparator", Qt::DirectConnection);
|
||||
Q_ASSERT(invokeResult);
|
||||
Q_UNUSED(invokeResult); // FIXME - apparently we haven't upgraded the Qt on our unix Jenkins environments to 5.5.x
|
||||
}
|
||||
|
||||
void VrMenu::insertAction(QAction* before, QAction* action) {
|
||||
QObject* beforeQml{ nullptr };
|
||||
{
|
||||
|
|
|
@ -28,6 +28,7 @@ public:
|
|||
VrMenu(QObject* parent = nullptr);
|
||||
void addMenu(QMenu* menu);
|
||||
void addAction(QMenu* parent, QAction* action);
|
||||
void addSeparator(QMenu* parent);
|
||||
void insertAction(QAction* before, QAction* action);
|
||||
void removeAction(QAction* action);
|
||||
|
||||
|
|
|
@ -222,8 +222,11 @@ void Menu::setIsOptionChecked(const QString& menuOption, bool isChecked) {
|
|||
return;
|
||||
}
|
||||
QAction* menu = _actionHash.value(menuOption);
|
||||
if (menu) {
|
||||
menu->setChecked(isChecked);
|
||||
if (menu && menu->isCheckable()) {
|
||||
auto wasChecked = menu->isChecked();
|
||||
if (wasChecked != isChecked) {
|
||||
menu->trigger();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -511,7 +514,11 @@ void MenuWrapper::setEnabled(bool enabled) {
|
|||
}
|
||||
|
||||
QAction* MenuWrapper::addSeparator() {
|
||||
return _realMenu->addSeparator();
|
||||
QAction* action = _realMenu->addSeparator();
|
||||
VrMenu::executeOrQueue([=](VrMenu* vrMenu) {
|
||||
vrMenu->addSeparator(_realMenu);
|
||||
});
|
||||
return action;
|
||||
}
|
||||
|
||||
void MenuWrapper::addAction(QAction* action) {
|
||||
|
|
|
@ -17,6 +17,7 @@ public:
|
|||
|
||||
protected:
|
||||
void hmdPresent() override {}
|
||||
bool isHmdMounted() const override { return true; }
|
||||
|
||||
private:
|
||||
static const QString NAME;
|
||||
|
|
|
@ -24,6 +24,8 @@ public:
|
|||
|
||||
protected:
|
||||
void hmdPresent() override;
|
||||
// FIXME update with Oculus API call once it's available in the SDK
|
||||
bool isHmdMounted() const override { return true; }
|
||||
void customizeContext() override;
|
||||
void uncustomizeContext() override;
|
||||
void updateFrameData() override;
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
# See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
if (NOT WIN32)
|
||||
# Windows doesn't need this, and building it currently make Linux unstable.
|
||||
# if (NOT WIN32)
|
||||
if (APPLE)
|
||||
|
||||
set(TARGET_NAME oculusLegacy)
|
||||
setup_hifi_plugin()
|
||||
|
@ -19,4 +21,4 @@ if (NOT WIN32)
|
|||
target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES})
|
||||
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
@ -35,6 +35,7 @@ public:
|
|||
protected:
|
||||
virtual void customizeContext() override;
|
||||
void hmdPresent() override {}
|
||||
bool isHmdMounted() const override { return true; }
|
||||
#if 0
|
||||
virtual void uncustomizeContext() override;
|
||||
virtual void internalPresent() override;
|
||||
|
|
|
@ -86,13 +86,16 @@ void OpenVrDisplayPlugin::activate() {
|
|||
}
|
||||
|
||||
void OpenVrDisplayPlugin::deactivate() {
|
||||
// Base class deactivate must come before our local deactivate
|
||||
// because the OpenGL base class handles the wait for the present
|
||||
// thread before continuing
|
||||
HmdDisplayPlugin::deactivate();
|
||||
_container->setIsOptionChecked(StandingHMDSensorMode, false);
|
||||
if (_system) {
|
||||
releaseOpenVrSystem();
|
||||
_system = nullptr;
|
||||
}
|
||||
_compositor = nullptr;
|
||||
HmdDisplayPlugin::deactivate();
|
||||
}
|
||||
|
||||
void OpenVrDisplayPlugin::customizeContext() {
|
||||
|
@ -154,4 +157,10 @@ void OpenVrDisplayPlugin::hmdPresent() {
|
|||
|
||||
vr::TrackedDevicePose_t currentTrackedDevicePose[vr::k_unMaxTrackedDeviceCount];
|
||||
_compositor->WaitGetPoses(currentTrackedDevicePose, vr::k_unMaxTrackedDeviceCount, nullptr, 0);
|
||||
_hmdActivityLevel = _system->GetTrackedDeviceActivityLevel(vr::k_unTrackedDeviceIndex_Hmd);
|
||||
}
|
||||
|
||||
bool OpenVrDisplayPlugin::isHmdMounted() const {
|
||||
return _hmdActivityLevel == vr::k_EDeviceActivityLevel_UserInteraction;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,9 +33,11 @@ public:
|
|||
|
||||
protected:
|
||||
void hmdPresent() override;
|
||||
bool isHmdMounted() const override;
|
||||
|
||||
private:
|
||||
vr::IVRSystem* _system { nullptr };
|
||||
std::atomic<vr::EDeviceActivityLevel> _hmdActivityLevel { vr::k_EDeviceActivityLevel_Unknown };
|
||||
static const QString NAME;
|
||||
mutable Mutex _poseMutex;
|
||||
};
|
||||
|
|
|
@ -477,118 +477,130 @@ function performContentMigration() {
|
|||
|
||||
var logWindow = null;
|
||||
|
||||
var labels = {
|
||||
serverState: {
|
||||
label: 'Server - Stopped',
|
||||
enabled: false
|
||||
},
|
||||
version: {
|
||||
label: 'Version - ' + buildInfo.buildIdentifier,
|
||||
enabled: false
|
||||
},
|
||||
restart: {
|
||||
label: 'Start Server',
|
||||
click: function() {
|
||||
homeServer.restart();
|
||||
}
|
||||
},
|
||||
stopServer: {
|
||||
label: 'Stop Server',
|
||||
visible: false,
|
||||
click: function() {
|
||||
homeServer.stop();
|
||||
}
|
||||
},
|
||||
goHome: {
|
||||
label: 'Go Home',
|
||||
click: goHomeClicked,
|
||||
enabled: false
|
||||
},
|
||||
quit: {
|
||||
label: 'Quit',
|
||||
accelerator: 'Command+Q',
|
||||
click: function() {
|
||||
shutdown();
|
||||
}
|
||||
},
|
||||
settings: {
|
||||
label: 'Settings',
|
||||
click: function() {
|
||||
shell.openExternal('http://localhost:40100/settings');
|
||||
},
|
||||
enabled: false
|
||||
},
|
||||
viewLogs: {
|
||||
label: 'View Logs',
|
||||
click: function() {
|
||||
logWindow.open();
|
||||
}
|
||||
},
|
||||
share: {
|
||||
label: 'Share',
|
||||
click: function() {
|
||||
shell.openExternal('http://localhost:40100/settings/?action=share')
|
||||
}
|
||||
},
|
||||
migrateContent: {
|
||||
label: 'Migrate Stack Manager Content',
|
||||
click: function() {
|
||||
promptToMigrateContent();
|
||||
}
|
||||
},
|
||||
shuttingDown: {
|
||||
label: "Shutting down...",
|
||||
enabled: false
|
||||
},
|
||||
}
|
||||
|
||||
var separator = {
|
||||
type: 'separator'
|
||||
};
|
||||
|
||||
|
||||
function buildMenuArray(serverState) {
|
||||
var menuArray = null;
|
||||
|
||||
updateLabels(serverState);
|
||||
|
||||
var menuArray = [];
|
||||
|
||||
if (isShuttingDown) {
|
||||
menuArray = [
|
||||
{
|
||||
label: "Shutting down...",
|
||||
enabled: false
|
||||
}
|
||||
];
|
||||
menuArray.push(labels.shuttingDown);
|
||||
} else {
|
||||
menuArray = [
|
||||
{
|
||||
label: 'Server - Stopped',
|
||||
enabled: false
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Go Home',
|
||||
click: goHomeClicked,
|
||||
enabled: false
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Start Server',
|
||||
click: function() { homeServer.restart(); }
|
||||
},
|
||||
{
|
||||
label: 'Stop Server',
|
||||
visible: false,
|
||||
click: function() { homeServer.stop(); }
|
||||
},
|
||||
{
|
||||
label: 'Settings',
|
||||
click: function() { shell.openExternal('http://localhost:40100/settings'); },
|
||||
enabled: false
|
||||
},
|
||||
{
|
||||
label: 'View Logs',
|
||||
click: function() { logWindow.open(); }
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Share',
|
||||
click: function() { shell.openExternal('http://localhost:40100/settings/?action=share') }
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Quit',
|
||||
accelerator: 'Command+Q',
|
||||
click: function() { shutdown(); }
|
||||
}
|
||||
];
|
||||
menuArray.push(labels.serverState);
|
||||
menuArray.push(labels.version);
|
||||
menuArray.push(separator);
|
||||
menuArray.push(labels.goHome);
|
||||
menuArray.push(separator);
|
||||
menuArray.push(labels.restart);
|
||||
menuArray.push(labels.stopServer);
|
||||
menuArray.push(labels.settings);
|
||||
menuArray.push(labels.viewLogs);
|
||||
menuArray.push(separator);
|
||||
menuArray.push(labels.share);
|
||||
menuArray.push(separator);
|
||||
menuArray.push(labels.quit);
|
||||
|
||||
var foundStackManagerContent = isStackManagerContentPresent();
|
||||
if (foundStackManagerContent) {
|
||||
// add a separator and the stack manager content migration option
|
||||
menuArray.splice(menuArray.length - 1, 0, {
|
||||
label: 'Migrate Stack Manager Content',
|
||||
click: function() { promptToMigrateContent(); }
|
||||
}, {
|
||||
type: 'separator'
|
||||
});
|
||||
menuArray.splice(menuArray.length - 1, 0, labels.migrateContent, separator);
|
||||
}
|
||||
|
||||
updateMenuArray(menuArray, serverState);
|
||||
}
|
||||
|
||||
|
||||
return menuArray;
|
||||
|
||||
}
|
||||
|
||||
const GO_HOME_INDEX = 2;
|
||||
const SERVER_LABEL_INDEX = 0;
|
||||
const RESTART_INDEX = 4;
|
||||
const STOP_INDEX = 5;
|
||||
const SETTINGS_INDEX = 6;
|
||||
function updateLabels(serverState) {
|
||||
|
||||
function updateMenuArray(menuArray, serverState) {
|
||||
// update the tray menu state
|
||||
var running = serverState == ProcessGroupStates.STARTED;
|
||||
|
||||
var serverLabelItem = menuArray[SERVER_LABEL_INDEX];
|
||||
var restartItem = menuArray[RESTART_INDEX];
|
||||
|
||||
// Go Home is only enabled if running
|
||||
menuArray[GO_HOME_INDEX].enabled = running;
|
||||
|
||||
// Stop is only visible if running
|
||||
menuArray[STOP_INDEX].visible = running;
|
||||
|
||||
// Settings is only visible if running
|
||||
menuArray[SETTINGS_INDEX].enabled = running;
|
||||
|
||||
labels.goHome.enabled = running;
|
||||
labels.stopServer.visible = running;
|
||||
labels.settings.enabled = running;
|
||||
if (serverState == ProcessGroupStates.STARTED) {
|
||||
serverLabelItem.label = "Server - Started";
|
||||
restartItem.label = "Restart Server";
|
||||
labels.serverState.label = "Server - Started";
|
||||
labels.restart.label = "Restart Server";
|
||||
} else if (serverState == ProcessGroupStates.STOPPED) {
|
||||
serverLabelItem.label = "Server - Stopped";
|
||||
restartItem.label = "Start Server";
|
||||
labels.serverState.label = "Server - Stopped";
|
||||
labels.restart.label = "Start Server";
|
||||
labels.restart.enabled = true;
|
||||
} else if (serverState == ProcessGroupStates.STOPPING) {
|
||||
serverLabelItem.label = "Server - Stopping";
|
||||
|
||||
restartItem.label = "Restart Server";
|
||||
restartItem.enabled = false;
|
||||
labels.serverState.label = "Server - Stopping";
|
||||
labels.restart.label = "Restart Server";
|
||||
labels.restart.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,83 +23,77 @@
|
|||
#include <gl/QOpenGLDebugLoggerWrapper.h>
|
||||
#include <gl/QOpenGLContextWrapper.h>
|
||||
|
||||
#include "../model/Skybox_vert.h"
|
||||
#include "../model/Skybox_frag.h"
|
||||
#include <render-utils/simple_vert.h>
|
||||
#include <render-utils/simple_frag.h>
|
||||
#include <render-utils/simple_textured_frag.h>
|
||||
#include <render-utils/simple_textured_emisive_frag.h>
|
||||
|
||||
#include "simple_vert.h"
|
||||
#include "simple_frag.h"
|
||||
#include "simple_textured_frag.h"
|
||||
#include "simple_textured_emisive_frag.h"
|
||||
#include <render-utils/deferred_light_vert.h>
|
||||
#include <render-utils/deferred_light_limited_vert.h>
|
||||
|
||||
#include "deferred_light_vert.h"
|
||||
#include "deferred_light_limited_vert.h"
|
||||
#include <render-utils/directional_light_frag.h>
|
||||
#include <render-utils/directional_ambient_light_frag.h>
|
||||
#include <render-utils/directional_skybox_light_frag.h>
|
||||
|
||||
#include "directional_light_frag.h"
|
||||
#include <render-utils/point_light_frag.h>
|
||||
#include <render-utils/spot_light_frag.h>
|
||||
|
||||
#include "directional_ambient_light_frag.h"
|
||||
#include <render-utils/standardTransformPNTC_vert.h>
|
||||
#include <render-utils/standardDrawTexture_frag.h>
|
||||
|
||||
#include "directional_skybox_light_frag.h"
|
||||
#include <render-utils/model_vert.h>
|
||||
#include <render-utils/model_shadow_vert.h>
|
||||
#include <render-utils/model_normal_map_vert.h>
|
||||
#include <render-utils/model_lightmap_vert.h>
|
||||
#include <render-utils/model_lightmap_normal_map_vert.h>
|
||||
#include <render-utils/skin_model_vert.h>
|
||||
#include <render-utils/skin_model_shadow_vert.h>
|
||||
#include <render-utils/skin_model_normal_map_vert.h>
|
||||
|
||||
#include "point_light_frag.h"
|
||||
#include "spot_light_frag.h"
|
||||
#include <render-utils/model_frag.h>
|
||||
#include <render-utils/model_shadow_frag.h>
|
||||
#include <render-utils/model_normal_map_frag.h>
|
||||
#include <render-utils/model_normal_specular_map_frag.h>
|
||||
#include <render-utils/model_specular_map_frag.h>
|
||||
#include <render-utils/model_lightmap_frag.h>
|
||||
#include <render-utils/model_lightmap_normal_map_frag.h>
|
||||
#include <render-utils/model_lightmap_normal_specular_map_frag.h>
|
||||
#include <render-utils/model_lightmap_specular_map_frag.h>
|
||||
#include <render-utils/model_translucent_frag.h>
|
||||
|
||||
#include "standardTransformPNTC_vert.h"
|
||||
#include "standardDrawTexture_frag.h"
|
||||
#include <entities-renderer/untextured_particle_frag.h>
|
||||
#include <entities-renderer/untextured_particle_vert.h>
|
||||
#include <entities-renderer/textured_particle_frag.h>
|
||||
#include <entities-renderer/textured_particle_vert.h>
|
||||
|
||||
#include "model_vert.h"
|
||||
#include "model_shadow_vert.h"
|
||||
#include "model_normal_map_vert.h"
|
||||
#include "model_lightmap_vert.h"
|
||||
#include "model_lightmap_normal_map_vert.h"
|
||||
#include "skin_model_vert.h"
|
||||
#include "skin_model_shadow_vert.h"
|
||||
#include "skin_model_normal_map_vert.h"
|
||||
#include <render-utils/hit_effect_vert.h>
|
||||
#include <render-utils/hit_effect_frag.h>
|
||||
|
||||
#include "model_frag.h"
|
||||
#include "model_shadow_frag.h"
|
||||
#include "model_normal_map_frag.h"
|
||||
#include "model_normal_specular_map_frag.h"
|
||||
#include "model_specular_map_frag.h"
|
||||
#include "model_lightmap_frag.h"
|
||||
#include "model_lightmap_normal_map_frag.h"
|
||||
#include "model_lightmap_normal_specular_map_frag.h"
|
||||
#include "model_lightmap_specular_map_frag.h"
|
||||
#include "model_translucent_frag.h"
|
||||
#include <render-utils/overlay3D_vert.h>
|
||||
#include <render-utils/overlay3D_frag.h>
|
||||
|
||||
#include "untextured_particle_frag.h"
|
||||
#include "untextured_particle_vert.h"
|
||||
#include "textured_particle_frag.h"
|
||||
#include "textured_particle_vert.h"
|
||||
#include <model/skybox_vert.h>
|
||||
#include <model/skybox_frag.h>
|
||||
|
||||
#include <render-utils/stars_vert.h>
|
||||
#include <render-utils/stars_frag.h>
|
||||
#include <render-utils/starsGrid_frag.h>
|
||||
|
||||
#include "hit_effect_vert.h"
|
||||
#include "hit_effect_frag.h"
|
||||
#include <gpu/DrawTransformUnitQuad_vert.h>
|
||||
#include <gpu/DrawTexcoordRectTransformUnitQuad_vert.h>
|
||||
#include <gpu/DrawViewportQuadTransformTexcoord_vert.h>
|
||||
#include <gpu/DrawTexture_frag.h>
|
||||
#include <gpu/DrawTextureOpaque_frag.h>
|
||||
#include <gpu/DrawColoredTexture_frag.h>
|
||||
|
||||
#include "overlay3D_vert.h"
|
||||
#include "overlay3D_frag.h"
|
||||
#include <render-utils/sdf_text3D_vert.h>
|
||||
#include <render-utils/sdf_text3D_frag.h>
|
||||
|
||||
#include "Skybox_vert.h"
|
||||
#include "Skybox_frag.h"
|
||||
#include <entities-renderer/paintStroke_vert.h>
|
||||
#include <entities-renderer/paintStroke_frag.h>
|
||||
|
||||
#include "stars_vert.h"
|
||||
#include "stars_frag.h"
|
||||
#include "starsGrid_frag.h"
|
||||
|
||||
#include "DrawTransformUnitQuad_vert.h"
|
||||
#include "DrawTexcoordRectTransformUnitQuad_vert.h"
|
||||
#include "DrawViewportQuadTransformTexcoord_vert.h"
|
||||
#include "DrawTexture_frag.h"
|
||||
#include "DrawTextureOpaque_frag.h"
|
||||
#include "DrawColoredTexture_frag.h"
|
||||
|
||||
#include "sdf_text3D_vert.h"
|
||||
#include "sdf_text3D_frag.h"
|
||||
|
||||
#include "paintStroke_vert.h"
|
||||
#include "paintStroke_frag.h"
|
||||
|
||||
#include "polyvox_vert.h"
|
||||
#include "polyvox_frag.h"
|
||||
#include <entities-renderer/polyvox_vert.h>
|
||||
#include <entities-renderer/polyvox_frag.h>
|
||||
|
||||
// Create a simple OpenGL window that renders text in various ways
|
||||
class QTestWindow : public QWindow {
|
||||
|
@ -163,7 +157,7 @@ void QTestWindow::draw() {
|
|||
testShaderBuild(DrawTransformUnitQuad_vert, DrawTextureOpaque_frag);
|
||||
testShaderBuild(DrawTransformUnitQuad_vert, DrawColoredTexture_frag);
|
||||
|
||||
testShaderBuild(Skybox_vert, Skybox_frag);
|
||||
testShaderBuild(skybox_vert, skybox_frag);
|
||||
testShaderBuild(simple_vert, simple_frag);
|
||||
testShaderBuild(simple_vert, simple_textured_frag);
|
||||
testShaderBuild(simple_vert, simple_textured_emisive_frag);
|
||||
|
@ -209,8 +203,6 @@ void QTestWindow::draw() {
|
|||
|
||||
testShaderBuild(overlay3D_vert, overlay3D_frag);
|
||||
|
||||
testShaderBuild(Skybox_vert, Skybox_frag);
|
||||
|
||||
testShaderBuild(paintStroke_vert,paintStroke_frag);
|
||||
testShaderBuild(polyvox_vert, polyvox_frag);
|
||||
|
||||
|
|
Loading…
Reference in a new issue