mirror of
https://github.com/overte-org/overte.git
synced 2025-04-17 05:30:41 +02:00
Merge branch 'atp' of github.com:birarda/hifi into atp-upload
This commit is contained in:
commit
4b6dd4636f
75 changed files with 1121 additions and 861 deletions
|
@ -58,16 +58,46 @@ void UploadAssetTask::run() {
|
|||
<< "is: (" << hexHash << ") ";
|
||||
|
||||
QFile file { _resourcesDir.filePath(QString(hexHash)) };
|
||||
|
||||
bool existingCorrectFile = false;
|
||||
|
||||
if (file.exists()) {
|
||||
qDebug() << "[WARNING] This file already exists: " << hexHash;
|
||||
} else {
|
||||
file.open(QIODevice::WriteOnly);
|
||||
file.write(fileData);
|
||||
file.close();
|
||||
// check if the local file has the correct contents, otherwise we overwrite
|
||||
if (file.open(QIODevice::ReadOnly) && hashData(file.readAll()) == hash) {
|
||||
qDebug() << "Not overwriting existing verified file: " << hexHash;
|
||||
|
||||
existingCorrectFile = true;
|
||||
|
||||
replyPacket->writePrimitive(AssetServerError::NoError);
|
||||
replyPacket->write(hash);
|
||||
} else {
|
||||
qDebug() << "Overwriting an existing file whose contents did not match the expected hash: " << hexHash;
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
replyPacket->writePrimitive(AssetServerError::NoError);
|
||||
replyPacket->write(hash);
|
||||
|
||||
if (!existingCorrectFile) {
|
||||
if (file.open(QIODevice::WriteOnly) && file.write(fileData) == qint64(fileSize)) {
|
||||
qDebug() << "Wrote file" << hexHash << "to disk. Upload complete";
|
||||
file.close();
|
||||
|
||||
replyPacket->writePrimitive(AssetServerError::NoError);
|
||||
replyPacket->write(hash);
|
||||
} else {
|
||||
qWarning() << "Failed to upload or write to file" << hexHash << " - upload failed.";
|
||||
|
||||
// upload has failed - remove the file and return an error
|
||||
auto removed = file.remove();
|
||||
|
||||
if (!removed) {
|
||||
qWarning() << "Removal of failed upload file" << hexHash << "failed.";
|
||||
}
|
||||
|
||||
replyPacket->writePrimitive(AssetServerError::FileOperationFailed);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -13,7 +13,6 @@ Script.load("progress.js");
|
|||
Script.load("edit.js");
|
||||
Script.load("marketplace.js");
|
||||
Script.load("selectAudioDevice.js");
|
||||
Script.load("inspect.js");
|
||||
Script.load("notifications.js");
|
||||
Script.load("users.js");
|
||||
Script.load("controllers/handControllerGrab.js");
|
||||
|
|
|
@ -1,285 +0,0 @@
|
|||
//
|
||||
// hmdControls.js
|
||||
// examples
|
||||
//
|
||||
// Created by Sam Gondelman on 6/17/15
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var MOVE_DISTANCE = 2.0;
|
||||
var PITCH_INCREMENT = 0.5; // degrees
|
||||
var pitchChange = 0; // degrees
|
||||
var YAW_INCREMENT = 0.5; // degrees
|
||||
var VR_YAW_INCREMENT = 15.0; // degrees
|
||||
var yawChange = 0;
|
||||
var BOOM_SPEED = 0.5;
|
||||
var THRESHOLD = 0.2;
|
||||
|
||||
var CAMERA_UPDATE_TIME = 0.5;
|
||||
var yawTimer = CAMERA_UPDATE_TIME;
|
||||
|
||||
var shifted = false;
|
||||
var SHIFT_UPDATE_TIME = 0.5;
|
||||
var shiftTimer = SHIFT_UPDATE_TIME;
|
||||
var SHIFT_MAG = 4.0;
|
||||
|
||||
var warpActive = false;
|
||||
var WARP_UPDATE_TIME = .5;
|
||||
var warpTimer = WARP_UPDATE_TIME;
|
||||
|
||||
var warpPosition = { x: 0, y: 0, z: 0 };
|
||||
|
||||
var WARP_SPHERE_SIZE = 1;
|
||||
var warpSphere = Overlays.addOverlay("sphere", {
|
||||
position: { x: 0, y: 0, z: 0 },
|
||||
size: WARP_SPHERE_SIZE,
|
||||
color: { red: 0, green: 255, blue: 0 },
|
||||
alpha: 1.0,
|
||||
solid: true,
|
||||
visible: false,
|
||||
});
|
||||
|
||||
var WARP_LINE_HEIGHT = 10;
|
||||
var warpLine = Overlays.addOverlay("line3d", {
|
||||
start: { x: 0, y: 0, z:0 },
|
||||
end: { x: 0, y: 0, z: 0 },
|
||||
color: { red: 0, green: 255, blue: 255},
|
||||
alpha: 1,
|
||||
lineWidth: 5,
|
||||
visible: false,
|
||||
});
|
||||
|
||||
var velocity = { x: 0, y: 0, z: 0 };
|
||||
var VERY_LONG_TIME = 1000000.0;
|
||||
|
||||
var active = HMD.active;
|
||||
var prevVRMode = HMD.active;
|
||||
|
||||
var hmdControls = (function () {
|
||||
|
||||
function onKeyPressEvent(event) {
|
||||
if (event.text == 'g' && event.isMeta) {
|
||||
active = !active;
|
||||
}
|
||||
}
|
||||
|
||||
function findAction(name) {
|
||||
var actions = Controller.getAllActions();
|
||||
for (var i = 0; i < actions.length; i++) {
|
||||
if (actions[i].actionName == name) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// If the action isn't found, it will default to the first available action
|
||||
return 0;
|
||||
}
|
||||
|
||||
function onActionEvent(action, state) {
|
||||
if (!active) {
|
||||
return;
|
||||
}
|
||||
if (state < THRESHOLD) {
|
||||
if (action == findAction("YAW_LEFT") || action == findAction("YAW_RIGHT")) {
|
||||
yawTimer = CAMERA_UPDATE_TIME;
|
||||
} else if (action == findAction("PITCH_UP") || action == findAction("PITCH_DOWN")) {
|
||||
pitchTimer = CAMERA_UPDATE_TIME;
|
||||
}
|
||||
return;
|
||||
}
|
||||
switch (action) {
|
||||
case findAction("LONGITUDINAL_BACKWARD"):
|
||||
var direction = {x: 0.0, y: 0.0, z:1.0};
|
||||
direction = Vec3.multiply(Vec3.normalize(direction), shifted ? SHIFT_MAG * MOVE_DISTANCE : MOVE_DISTANCE);
|
||||
velocity = Vec3.sum(velocity, direction);
|
||||
break;
|
||||
case findAction("LONGITUDINAL_FORWARD"):
|
||||
var direction = {x: 0.0, y: 0.0, z:-1.0};
|
||||
direction = Vec3.multiply(Vec3.normalize(direction), shifted ? SHIFT_MAG * MOVE_DISTANCE : MOVE_DISTANCE);
|
||||
velocity = Vec3.sum(velocity, direction);
|
||||
break;
|
||||
case findAction("LATERAL_LEFT"):
|
||||
var direction = {x:-1.0, y: 0.0, z: 0.0}
|
||||
direction = Vec3.multiply(Vec3.normalize(direction), shifted ? SHIFT_MAG * MOVE_DISTANCE : MOVE_DISTANCE);
|
||||
velocity = Vec3.sum(velocity, direction);
|
||||
break;
|
||||
case findAction("LATERAL_RIGHT"):
|
||||
var direction = {x:1.0, y: 0.0, z: 0.0};
|
||||
direction = Vec3.multiply(Vec3.normalize(direction), shifted ? SHIFT_MAG * MOVE_DISTANCE : MOVE_DISTANCE);
|
||||
velocity = Vec3.sum(velocity, direction);
|
||||
break;
|
||||
case findAction("VERTICAL_DOWN"):
|
||||
var direction = {x: 0.0, y: -1.0, z: 0.0};
|
||||
direction = Vec3.multiply(Vec3.normalize(direction), shifted ? SHIFT_MAG * MOVE_DISTANCE : MOVE_DISTANCE);
|
||||
velocity = Vec3.sum(velocity, direction);
|
||||
break;
|
||||
case findAction("VERTICAL_UP"):
|
||||
var direction = {x: 0.0, y: 1.0, z: 0.0};
|
||||
direction = Vec3.multiply(Vec3.normalize(direction), shifted ? SHIFT_MAG * MOVE_DISTANCE : MOVE_DISTANCE);
|
||||
velocity = Vec3.sum(velocity, direction);
|
||||
break;
|
||||
case findAction("YAW_LEFT"):
|
||||
if (yawTimer < 0.0 && HMD.active) {
|
||||
yawChange = yawChange + (shifted ? SHIFT_MAG * VR_YAW_INCREMENT : VR_YAW_INCREMENT);
|
||||
yawTimer = CAMERA_UPDATE_TIME;
|
||||
} else if (!HMD.active) {
|
||||
yawChange = yawChange + (shifted ? SHIFT_MAG * YAW_INCREMENT : YAW_INCREMENT);
|
||||
}
|
||||
break;
|
||||
case findAction("YAW_RIGHT"):
|
||||
if (yawTimer < 0.0 && HMD.active) {
|
||||
yawChange = yawChange - (shifted ? SHIFT_MAG * VR_YAW_INCREMENT : VR_YAW_INCREMENT);
|
||||
yawTimer = CAMERA_UPDATE_TIME;
|
||||
} else if (!HMD.active) {
|
||||
yawChange = yawChange - (shifted ? SHIFT_MAG * YAW_INCREMENT : YAW_INCREMENT);
|
||||
}
|
||||
break;
|
||||
case findAction("PITCH_DOWN"):
|
||||
if (!HMD.active) {
|
||||
pitchChange = pitchChange - (shifted ? SHIFT_MAG * PITCH_INCREMENT : PITCH_INCREMENT);
|
||||
}
|
||||
break;
|
||||
case findAction("PITCH_UP"):
|
||||
if (!HMD.active) {
|
||||
pitchChange = pitchChange + (shifted ? SHIFT_MAG * PITCH_INCREMENT : PITCH_INCREMENT);
|
||||
}
|
||||
break;
|
||||
case findAction("SHIFT"): // speed up
|
||||
if (shiftTimer < 0.0) {
|
||||
shifted = !shifted;
|
||||
shiftTimer = SHIFT_UPDATE_TIME;
|
||||
}
|
||||
break;
|
||||
case findAction("ACTION1"): // start/end warp
|
||||
if (warpTimer < 0.0) {
|
||||
warpActive = !warpActive;
|
||||
if (!warpActive) {
|
||||
finishWarp();
|
||||
}
|
||||
warpTimer = WARP_UPDATE_TIME;
|
||||
}
|
||||
break;
|
||||
case findAction("ACTION2"): // cancel warp
|
||||
warpActive = false;
|
||||
Overlays.editOverlay(warpSphere, {
|
||||
visible: false,
|
||||
});
|
||||
Overlays.editOverlay(warpLine, {
|
||||
visible: false,
|
||||
});
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function update(dt) {
|
||||
if (prevVRMode != HMD.active) {
|
||||
active = HMD.active;
|
||||
prevVRMode = HMD.active;
|
||||
}
|
||||
|
||||
if (yawTimer >= 0.0) {
|
||||
yawTimer = yawTimer - dt;
|
||||
}
|
||||
if (shiftTimer >= 0.0) {
|
||||
shiftTimer = shiftTimer - dt;
|
||||
}
|
||||
if (warpTimer >= 0.0) {
|
||||
warpTimer = warpTimer - dt;
|
||||
}
|
||||
|
||||
if (warpActive) {
|
||||
updateWarp();
|
||||
}
|
||||
|
||||
if (active) {
|
||||
Controller.captureActionEvents();
|
||||
|
||||
MyAvatar.bodyYaw = MyAvatar.bodyYaw + yawChange;
|
||||
MyAvatar.headPitch = Math.max(-180, Math.min(180, MyAvatar.headPitch + pitchChange));
|
||||
yawChange = 0;
|
||||
pitchChange = 0;
|
||||
|
||||
MyAvatar.motorVelocity = velocity;
|
||||
MyAvatar.motorTimescale = 0.0;
|
||||
velocity = { x: 0, y: 0, z: 0 };
|
||||
} else {
|
||||
Controller.releaseActionEvents();
|
||||
yawChange = 0;
|
||||
pitchChange = 0;
|
||||
MyAvatar.motorVelocity = {x:0.0, y:0.0, z:0.0}
|
||||
MyAvatar.motorTimescale = VERY_LONG_TIME;
|
||||
}
|
||||
}
|
||||
|
||||
function updateWarp() {
|
||||
var look = Quat.getFront(Camera.getOrientation());
|
||||
var pitch = Math.asin(look.y);
|
||||
|
||||
// Get relative to looking straight down
|
||||
pitch += Math.PI / 2;
|
||||
|
||||
// Scale up
|
||||
pitch *= 2;
|
||||
var distance = pitch * pitch * pitch;
|
||||
|
||||
var warpDirection = Vec3.normalize({ x: look.x, y: 0, z: look.z });
|
||||
warpPosition = Vec3.multiply(warpDirection, distance);
|
||||
warpPosition = Vec3.sum(MyAvatar.position, warpPosition);
|
||||
|
||||
// Commented out until ray picking can be fixed
|
||||
// var pickRay = {
|
||||
// origin: Vec3.sum(warpPosition, WARP_PICK_OFFSET),
|
||||
// direction: { x: 0, y: -1, z: 0 }
|
||||
// };
|
||||
|
||||
// var intersection = Entities.findRayIntersection(pickRay);
|
||||
|
||||
// if (intersection.intersects && intersection.distance < WARP_PICK_MAX_DISTANCE) {
|
||||
// // Warp 1 meter above the object - this is an approximation
|
||||
// // TODO Get the actual offset to the Avatar's feet and plant them to
|
||||
// // the object.
|
||||
// warpPosition = Vec3.sum(intersection.intersection, { x: 0, y: 1, z:0 });
|
||||
// }
|
||||
|
||||
// Adjust overlays to match warp position
|
||||
Overlays.editOverlay(warpSphere, {
|
||||
position: warpPosition,
|
||||
visible: true,
|
||||
});
|
||||
Overlays.editOverlay(warpLine, {
|
||||
start: warpPosition,
|
||||
end: Vec3.sum(warpPosition, { x: 0, y: WARP_LINE_HEIGHT, z: 0 }),
|
||||
visible: true,
|
||||
});
|
||||
}
|
||||
|
||||
function finishWarp() {
|
||||
Overlays.editOverlay(warpSphere, {
|
||||
visible: false,
|
||||
});
|
||||
Overlays.editOverlay(warpLine, {
|
||||
visible: false,
|
||||
});
|
||||
MyAvatar.position = warpPosition;
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
Controller.keyPressEvent.connect(onKeyPressEvent);
|
||||
|
||||
Controller.actionEvent.connect(onActionEvent);
|
||||
|
||||
Script.update.connect(update);
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
Controller.releaseActionEvents();
|
||||
MyAvatar.motorVelocity = {x:0.0, y:0.0, z:0.0}
|
||||
MyAvatar.motorTimescale = VERY_LONG_TIME;
|
||||
}
|
||||
|
||||
setUp();
|
||||
Script.scriptEnding.connect(tearDown);
|
||||
}());
|
|
@ -1,17 +0,0 @@
|
|||
//
|
||||
// hmdDefaults.js
|
||||
// examples
|
||||
//
|
||||
// Created by David Rowe on 6 Mar 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
|
||||
//
|
||||
|
||||
Script.load("progress.js");
|
||||
Script.load("lobby.js");
|
||||
Script.load("notifications.js");
|
||||
Script.load("controllers/oculus/goTo.js");
|
||||
Script.load("hmdControls.js");
|
||||
//Script.load("scripts.js"); // Not created yet
|
|
@ -1237,7 +1237,7 @@
|
|||
|
||||
|
||||
<div class="section-header">
|
||||
<label>Spacial Properties</label>
|
||||
<label>Spatial Properties</label>
|
||||
</div>
|
||||
|
||||
<div class="property">
|
||||
|
|
|
@ -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 } }); }
|
||||
|
|
@ -56,7 +56,7 @@ Window {
|
|||
if (err) {
|
||||
console.log("Asset browser - error deleting path: ", path, err);
|
||||
|
||||
box = errorMessageBox("There was an error deleting:\n" + path + "\n" + Assets.getErrorString(err));
|
||||
box = errorMessageBox("There was an error deleting:\n" + path + "\n" + err);
|
||||
box.selected.connect(reload);
|
||||
} else {
|
||||
console.log("Asset browser - finished deleting path: ", path);
|
||||
|
@ -87,7 +87,7 @@ Window {
|
|||
Assets.renameMapping(oldPath, newPath, function(err) {
|
||||
if (err) {
|
||||
console.log("Asset browser - error renaming: ", oldPath, "=>", newPath, " - error ", err);
|
||||
box = errorMessageBox("There was an error renaming:\n" + oldPath + " to " + newPath + "\n" + Assets.getErrorString(err));
|
||||
box = errorMessageBox("There was an error renaming:\n" + oldPath + " to " + newPath + "\n" + err);
|
||||
box.selected.connect(reload);
|
||||
} else {
|
||||
console.log("Asset browser - finished rename: ", oldPath, "=>", newPath);
|
||||
|
@ -129,10 +129,10 @@ Window {
|
|||
treeView.selection.clear();
|
||||
}
|
||||
|
||||
function handleGetMappingsError(errorCode) {
|
||||
function handleGetMappingsError(errorString) {
|
||||
errorMessageBox(
|
||||
"There was a problem retreiving the list of assets from your Asset Server.\n"
|
||||
+ Assets.getErrorString(errorCode)
|
||||
+ errorString
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -167,7 +167,7 @@ Window {
|
|||
if (!index) {
|
||||
index = treeView.selection.currentIndex;
|
||||
}
|
||||
|
||||
|
||||
var path = assetProxyModel.data(index, 0x100);
|
||||
if (!path) {
|
||||
return;
|
||||
|
@ -243,8 +243,6 @@ Window {
|
|||
var fileUrl = fileDialogHelper.urlToPath(url);
|
||||
currentDirectory = browser.dir;
|
||||
|
||||
//var fileUrl = fileUrlTextField.text
|
||||
|
||||
var path = assetProxyModel.data(treeView.selection.currentIndex, 0x100);
|
||||
var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/";
|
||||
var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1);
|
||||
|
@ -273,7 +271,7 @@ Window {
|
|||
} else {
|
||||
if (err > 0) {
|
||||
console.log("Asset Browser - error uploading: ", fileUrl, " - error ", err);
|
||||
var box = errorMessage("There was an error uploading:\n" + fileUrl + "\n" + Assets.getErrorString(err));
|
||||
var box = errorMessageBox("There was an error uploading:\n" + fileUrl + "\n" + Assets.getErrorString(err));
|
||||
box.selected.connect(reload);
|
||||
}
|
||||
uploadSpinner.visible = false;
|
||||
|
@ -293,6 +291,10 @@ Window {
|
|||
});
|
||||
}
|
||||
|
||||
function itemSelected() {
|
||||
return treeView.selection.hasSelection()
|
||||
}
|
||||
|
||||
Item {
|
||||
width: pane.contentWidth
|
||||
height: pane.height
|
||||
|
@ -339,6 +341,7 @@ Window {
|
|||
width: 80
|
||||
|
||||
onClicked: root.renameFile()
|
||||
enabled: treeView.selection.hasSelection
|
||||
}
|
||||
|
||||
HifiControls.Button {
|
||||
|
@ -351,6 +354,7 @@ Window {
|
|||
width: 80
|
||||
|
||||
onClicked: root.deleteFile()
|
||||
enabled: treeView.selection.hasSelection
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -399,6 +403,9 @@ Window {
|
|||
acceptedButtons: Qt.RightButton
|
||||
onClicked: {
|
||||
var index = treeView.indexAt(mouse.x, mouse.y);
|
||||
|
||||
treeView.selection.setCurrentIndex(index, 0x0002);
|
||||
|
||||
contextMenu.currentIndex = index;
|
||||
contextMenu.popup();
|
||||
}
|
||||
|
@ -424,7 +431,23 @@ Window {
|
|||
height: 30
|
||||
width: 155
|
||||
|
||||
onClicked: root.uploadClicked()
|
||||
enabled: fileUrlTextField.text != ""
|
||||
onClicked: uploadClickedTimer.running = true
|
||||
|
||||
// For some reason trigginer an API that enters
|
||||
// an internal event loop directly from the button clicked
|
||||
// trigger below causes the appliction to behave oddly.
|
||||
// Most likely because the button onClicked handling is never
|
||||
// completed until the function returns.
|
||||
// FIXME find a better way of handling the input dialogs that
|
||||
// doesn't trigger this.
|
||||
Timer {
|
||||
id: uploadClickedTimer
|
||||
interval: 5
|
||||
repeat: false
|
||||
running: false
|
||||
onTriggered: uploadClicked();
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
|
|
|
@ -72,7 +72,7 @@ ModalWindow {
|
|||
readonly property int maxHeight: 720
|
||||
|
||||
function resize() {
|
||||
var targetWidth = mainTextContainer.width
|
||||
var targetWidth = mainTextContainer.contentWidth
|
||||
var targetHeight = mainTextContainer.height + 3 * hifi.dimensions.contentSpacing.y
|
||||
+ (informativeTextContainer.text != "" ? informativeTextContainer.contentHeight + 3 * hifi.dimensions.contentSpacing.y : 0)
|
||||
+ buttons.height
|
||||
|
|
|
@ -3758,19 +3758,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;
|
||||
|
@ -3778,6 +3778,7 @@ namespace render {
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case model::SunSkyStage::NO_BACKGROUND:
|
||||
default:
|
||||
// this line intentionally left blank
|
||||
|
@ -4812,7 +4813,10 @@ void Application::updateDisplayMode() {
|
|||
}
|
||||
}
|
||||
emit activeDisplayPluginChanged();
|
||||
resetSensors();
|
||||
|
||||
// reset the avatar, to set head and hand palms back to a resonable default pose.
|
||||
getMyAvatar()->reset(false);
|
||||
|
||||
Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin");
|
||||
}
|
||||
|
||||
|
|
|
@ -130,8 +130,12 @@ Menu::Menu() {
|
|||
editMenu->addSeparator();
|
||||
|
||||
// Edit > My Asset Server
|
||||
addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer, Qt::CTRL | Qt::SHIFT | Qt::Key_A,
|
||||
qApp, SLOT(toggleAssetServerWidget()));
|
||||
auto assetServerAction = addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer,
|
||||
Qt::CTRL | Qt::SHIFT | Qt::Key_A,
|
||||
qApp, SLOT(toggleAssetServerWidget()));
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
QObject::connect(nodeList.data(), &NodeList::canRezChanged, assetServerAction, &QAction::setEnabled);
|
||||
assetServerAction->setEnabled(nodeList->getThisNodeCanRez());
|
||||
|
||||
// Edit > Reload All Content [advanced]
|
||||
addActionToQMenuAndActionHash(editMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()),
|
||||
|
@ -458,6 +462,8 @@ Menu::Menu() {
|
|||
avatar, SLOT(setUseAnimPreAndPostRotations(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::EnableInverseKinematics, 0, true,
|
||||
avatar, SLOT(setEnableInverseKinematics(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderSensorToWorldMatrix, 0, false,
|
||||
avatar, SLOT(setEnableDebugDrawSensorToWorldMatrix(bool)));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::KeyboardMotorControl,
|
||||
Qt::CTRL | Qt::SHIFT | Qt::Key_K, true, avatar, SLOT(updateMotionBehaviorFromMenu()),
|
||||
|
|
|
@ -145,6 +145,7 @@ namespace MenuOption {
|
|||
const QString RenderResolutionHalf = "1/2";
|
||||
const QString RenderResolutionThird = "1/3";
|
||||
const QString RenderResolutionQuarter = "1/4";
|
||||
const QString RenderSensorToWorldMatrix = "Show SensorToWorld Matrix";
|
||||
const QString ResetAvatarSize = "Reset Avatar Size";
|
||||
const QString ResetSensors = "Reset Sensors";
|
||||
const QString RunningScripts = "Running Scripts...";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -444,6 +444,10 @@ void MyAvatar::updateSensorToWorldMatrix() {
|
|||
|
||||
lateUpdatePalms();
|
||||
|
||||
if (_enableDebugDrawSensorToWorldMatrix) {
|
||||
DebugDraw::getInstance().addMarker("sensorToWorldMatrix", glmExtractRotation(_sensorToWorldMatrix), extractTranslation(_sensorToWorldMatrix), glm::vec4(1));
|
||||
}
|
||||
|
||||
_sensorToWorldMatrixCache.set(_sensorToWorldMatrix);
|
||||
}
|
||||
|
||||
|
@ -698,6 +702,14 @@ void MyAvatar::setEnableDebugDrawPosition(bool isEnabled) {
|
|||
}
|
||||
}
|
||||
|
||||
void MyAvatar::setEnableDebugDrawSensorToWorldMatrix(bool isEnabled) {
|
||||
_enableDebugDrawSensorToWorldMatrix = isEnabled;
|
||||
|
||||
if (!isEnabled) {
|
||||
DebugDraw::getInstance().removeMarker("sensorToWorldMatrix");
|
||||
}
|
||||
}
|
||||
|
||||
void MyAvatar::setEnableMeshVisible(bool isEnabled) {
|
||||
render::ScenePointer scene = qApp->getMain3DScene();
|
||||
_skeletonModel.setVisibleInScene(isEnabled, scene);
|
||||
|
|
|
@ -271,6 +271,7 @@ public slots:
|
|||
void setEnableDebugDrawDefaultPose(bool isEnabled);
|
||||
void setEnableDebugDrawAnimPose(bool isEnabled);
|
||||
void setEnableDebugDrawPosition(bool isEnabled);
|
||||
void setEnableDebugDrawSensorToWorldMatrix(bool isEnabled);
|
||||
bool getEnableMeshVisible() const { return _skeletonModel.isVisible(); }
|
||||
void setEnableMeshVisible(bool isEnabled);
|
||||
void setUseAnimPreAndPostRotations(bool isEnabled);
|
||||
|
@ -434,6 +435,7 @@ private:
|
|||
|
||||
bool _enableDebugDrawDefaultPose { false };
|
||||
bool _enableDebugDrawAnimPose { false };
|
||||
bool _enableDebugDrawSensorToWorldMatrix { false };
|
||||
|
||||
AudioListenerMode _audioListenerMode;
|
||||
glm::vec3 _customListenPosition;
|
||||
|
|
|
@ -144,7 +144,10 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
} else {
|
||||
handParams.isRightEnabled = false;
|
||||
}
|
||||
|
||||
handParams.bodyCapsuleRadius = myAvatar->getCharacterController()->getCapsuleRadius();
|
||||
handParams.bodyCapsuleHalfHeight = myAvatar->getCharacterController()->getCapsuleHalfHeight();
|
||||
handParams.bodyCapsuleLocalOffset = myAvatar->getCharacterController()->getCapsuleLocalOffset();
|
||||
|
||||
_rig->updateFromHandParameters(handParams, deltaTime);
|
||||
|
||||
|
|
|
@ -27,34 +27,13 @@ AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() {
|
|||
_proxyModel.sort(0);
|
||||
}
|
||||
|
||||
QString AssetMappingsScriptingInterface::getErrorString(int errorCode) const {
|
||||
switch (errorCode) {
|
||||
case MappingRequest::NoError:
|
||||
return "No error";
|
||||
case MappingRequest::NotFound:
|
||||
return "Asset not found";
|
||||
case MappingRequest::NetworkError:
|
||||
return "Unable to communicate with Asset Server";
|
||||
case MappingRequest::PermissionDenied:
|
||||
return "Permission denied";
|
||||
case MappingRequest::InvalidPath:
|
||||
return "Path is invalid";
|
||||
case MappingRequest::InvalidHash:
|
||||
return "Hash is invalid";
|
||||
case MappingRequest::UnknownError:
|
||||
return "Asset Server internal error";
|
||||
default:
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
||||
void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) {
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
auto request = assetClient->createSetMappingRequest(path, hash);
|
||||
|
||||
connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable {
|
||||
if (callback.isCallable()) {
|
||||
QJSValueList args { uint8_t(request->getError()), request->getPath() };
|
||||
QJSValueList args { request->getErrorString(), request->getPath() };
|
||||
callback.call(args);
|
||||
}
|
||||
|
||||
|
@ -70,7 +49,7 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback
|
|||
|
||||
connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable {
|
||||
if (callback.isCallable()) {
|
||||
QJSValueList args { uint8_t(request->getError()) };
|
||||
QJSValueList args { request->getErrorString() };
|
||||
callback.call(args);
|
||||
}
|
||||
|
||||
|
@ -116,7 +95,7 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping,
|
|||
QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable {
|
||||
if (upload->getError() != AssetUpload::NoError) {
|
||||
if (completedCallback.isCallable()) {
|
||||
QJSValueList args { uint8_t(upload->getError()) };
|
||||
QJSValueList args { upload->getErrorString() };
|
||||
completedCallback.call(args);
|
||||
}
|
||||
} else {
|
||||
|
@ -135,7 +114,7 @@ void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue
|
|||
|
||||
connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable {
|
||||
if (callback.isCallable()) {
|
||||
QJSValueList args { uint8_t(request->getError()) };
|
||||
QJSValueList args { request->getErrorString() };
|
||||
callback.call(args);
|
||||
}
|
||||
|
||||
|
@ -158,7 +137,7 @@ void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) {
|
|||
}
|
||||
|
||||
if (callback.isCallable()) {
|
||||
QJSValueList args { uint8_t(request->getError()), map };
|
||||
QJSValueList args { request->getErrorString(), map };
|
||||
callback.call(args);
|
||||
}
|
||||
|
||||
|
@ -174,7 +153,7 @@ void AssetMappingsScriptingInterface::renameMapping(QString oldPath, QString new
|
|||
|
||||
connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable {
|
||||
if (callback.isCallable()) {
|
||||
QJSValueList args { uint8_t(request->getError()) };
|
||||
QJSValueList args { request->getErrorString() };
|
||||
callback.call(args);
|
||||
}
|
||||
|
||||
|
@ -302,7 +281,7 @@ void AssetMappingModel::refresh() {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
emit errorGettingMappings(static_cast<int>(request->getError()));
|
||||
emit errorGettingMappings(request->getErrorString());
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -38,8 +38,7 @@ public:
|
|||
bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); }
|
||||
bool isKnownFolder(QString path) const;
|
||||
|
||||
signals:
|
||||
void errorGettingMappings(int error);
|
||||
void errorGettingMappings(QString errorString);
|
||||
|
||||
private:
|
||||
QHash<QString, QStandardItem*> _pathToItemMap;
|
||||
|
@ -60,8 +59,6 @@ public:
|
|||
Q_INVOKABLE bool isKnownMapping(QString path) const { return _assetMappingModel.isKnownMapping(path); }
|
||||
Q_INVOKABLE bool isKnownFolder(QString path) const { return _assetMappingModel.isKnownFolder(path); }
|
||||
|
||||
Q_INVOKABLE QString getErrorString(int errorCode) const;
|
||||
|
||||
Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback = QJSValue());
|
||||
Q_INVOKABLE void getMapping(QString path, QJSValue callback = QJSValue());
|
||||
Q_INVOKABLE void uploadFile(QString path, QString mapping, QJSValue startedCallback = QJSValue(), QJSValue completedCallback = QJSValue());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <RegisteredMetaTypes.h>
|
||||
#include <SharedUtil.h>
|
||||
#include "Application.h"
|
||||
|
||||
|
||||
const float DEFAULT_LINE_WIDTH = 1.0f;
|
||||
|
@ -38,15 +39,17 @@ Base3DOverlay::Base3DOverlay(const Base3DOverlay* base3DOverlay) :
|
|||
_drawInFront(base3DOverlay->_drawInFront)
|
||||
{
|
||||
}
|
||||
|
||||
void Base3DOverlay::setProperties(const QVariantMap& properties) {
|
||||
Overlay::setProperties(properties);
|
||||
|
||||
bool needRenderItemUpdate = false;
|
||||
|
||||
auto drawInFront = properties["drawInFront"];
|
||||
|
||||
if (drawInFront.isValid()) {
|
||||
bool value = drawInFront.toBool();
|
||||
setDrawInFront(value);
|
||||
needRenderItemUpdate = true;
|
||||
}
|
||||
|
||||
auto position = properties["position"];
|
||||
|
@ -60,16 +63,19 @@ void Base3DOverlay::setProperties(const QVariantMap& properties) {
|
|||
}
|
||||
if (position.isValid()) {
|
||||
setPosition(vec3FromVariant(position));
|
||||
needRenderItemUpdate = true;
|
||||
}
|
||||
|
||||
if (properties["lineWidth"].isValid()) {
|
||||
setLineWidth(properties["lineWidth"].toFloat());
|
||||
needRenderItemUpdate = true;
|
||||
}
|
||||
|
||||
auto rotation = properties["rotation"];
|
||||
|
||||
if (rotation.isValid()) {
|
||||
setRotation(quatFromVariant(rotation));
|
||||
needRenderItemUpdate = true;
|
||||
}
|
||||
|
||||
if (properties["isSolid"].isValid()) {
|
||||
|
@ -100,6 +106,17 @@ void Base3DOverlay::setProperties(const QVariantMap& properties) {
|
|||
if (properties["ignoreRayIntersection"].isValid()) {
|
||||
setIgnoreRayIntersection(properties["ignoreRayIntersection"].toBool());
|
||||
}
|
||||
|
||||
// Communicate changes to the renderItem if needed
|
||||
if (needRenderItemUpdate) {
|
||||
auto itemID = getRenderItemID();
|
||||
if (render::Item::isValidID(itemID)) {
|
||||
render::ScenePointer scene = qApp->getMain3DScene();
|
||||
render::PendingChanges pendingChanges;
|
||||
pendingChanges.updateItem(itemID);
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVariant Base3DOverlay::getProperty(const QString& property) {
|
||||
|
|
|
@ -233,19 +233,6 @@ bool Overlays::editOverlay(unsigned int id, const QVariant& properties) {
|
|||
if (thisOverlay) {
|
||||
thisOverlay->setProperties(properties.toMap());
|
||||
|
||||
if (thisOverlay->is3D()) {
|
||||
auto itemID = thisOverlay->getRenderItemID();
|
||||
if (render::Item::isValidID(itemID)) {
|
||||
render::ScenePointer scene = qApp->getMain3DScene();
|
||||
const render::Item& item = scene->getItem(itemID);
|
||||
if (item.getKey() != render::payloadGetKey(thisOverlay)) {
|
||||
render::PendingChanges pendingChanges;
|
||||
pendingChanges.updateItem(itemID);
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <QWriteLocker>
|
||||
#include <QReadLocker>
|
||||
|
||||
#include <GeometryUtil.h>
|
||||
#include <NumericalConstants.h>
|
||||
#include <DebugDraw.h>
|
||||
|
||||
|
@ -1073,32 +1074,27 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) {
|
|||
if (_animSkeleton && _animNode) {
|
||||
|
||||
const float HAND_RADIUS = 0.05f;
|
||||
const float BODY_RADIUS = params.bodyCapsuleRadius;
|
||||
const float MIN_LENGTH = 1.0e-4f;
|
||||
|
||||
// project the hips onto the xz plane.
|
||||
int hipsIndex = indexOfJoint("Hips");
|
||||
glm::vec3 hipsTrans;
|
||||
if (hipsIndex >= 0) {
|
||||
hipsTrans = _internalPoseSet._absolutePoses[hipsIndex].trans;
|
||||
}
|
||||
const glm::vec2 bodyCircleCenter(hipsTrans.x, hipsTrans.z);
|
||||
|
||||
// Use this capsule to represent the avatar body.
|
||||
const float bodyCapsuleRadius = params.bodyCapsuleRadius;
|
||||
const glm::vec3 bodyCapsuleCenter = hipsTrans - params.bodyCapsuleLocalOffset;
|
||||
const glm::vec3 bodyCapsuleStart = bodyCapsuleCenter - glm::vec3(0, params.bodyCapsuleHalfHeight, 0);
|
||||
const glm::vec3 bodyCapsuleEnd = bodyCapsuleCenter + glm::vec3(0, params.bodyCapsuleHalfHeight, 0);
|
||||
|
||||
if (params.isLeftEnabled) {
|
||||
|
||||
// project the hand position onto the xz plane.
|
||||
glm::vec2 handCircleCenter(params.leftPosition.x, params.leftPosition.z);
|
||||
|
||||
// check for 2d overlap of the hand and body circles.
|
||||
auto circleToCircle = handCircleCenter - bodyCircleCenter;
|
||||
const float circleToCircleLength = glm::length(circleToCircle);
|
||||
const float penetrationDistance = HAND_RADIUS + BODY_RADIUS - circleToCircleLength;
|
||||
if (penetrationDistance > 0.0f && circleToCircleLength > MIN_LENGTH) {
|
||||
// push the hands out of the body
|
||||
handCircleCenter += penetrationDistance * glm::normalize(circleToCircle);
|
||||
// prevent the hand IK targets from intersecting the body capsule
|
||||
glm::vec3 handPosition = params.leftPosition;
|
||||
glm::vec3 displacement(glm::vec3::_null);
|
||||
if (findSphereCapsulePenetration(handPosition, HAND_RADIUS, bodyCapsuleStart, bodyCapsuleEnd, bodyCapsuleRadius, displacement)) {
|
||||
handPosition -= displacement;
|
||||
}
|
||||
|
||||
glm::vec3 handPosition(handCircleCenter.x, params.leftPosition.y, handCircleCenter.y);
|
||||
_animVars.set("leftHandPosition", handPosition);
|
||||
_animVars.set("leftHandRotation", params.leftOrientation);
|
||||
_animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition);
|
||||
|
@ -1110,19 +1106,13 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) {
|
|||
|
||||
if (params.isRightEnabled) {
|
||||
|
||||
// project the hand position onto the xz plane.
|
||||
glm::vec2 handCircleCenter(params.rightPosition.x, params.rightPosition.z);
|
||||
|
||||
// check for 2d overlap of the hand and body circles.
|
||||
auto circleToCircle = handCircleCenter - bodyCircleCenter;
|
||||
const float circleToCircleLength = glm::length(circleToCircle);
|
||||
const float penetrationDistance = HAND_RADIUS + BODY_RADIUS - circleToCircleLength;
|
||||
if (penetrationDistance > 0.0f && circleToCircleLength > MIN_LENGTH) {
|
||||
// push the hands out of the body
|
||||
handCircleCenter += penetrationDistance * glm::normalize(circleToCircle);
|
||||
// prevent the hand IK targets from intersecting the body capsule
|
||||
glm::vec3 handPosition = params.rightPosition;
|
||||
glm::vec3 displacement(glm::vec3::_null);
|
||||
if (findSphereCapsulePenetration(handPosition, HAND_RADIUS, bodyCapsuleStart, bodyCapsuleEnd, bodyCapsuleRadius, displacement)) {
|
||||
handPosition -= displacement;
|
||||
}
|
||||
|
||||
glm::vec3 handPosition(handCircleCenter.x, params.rightPosition.y, handCircleCenter.y);
|
||||
_animVars.set("rightHandPosition", handPosition);
|
||||
_animVars.set("rightHandRotation", params.rightOrientation);
|
||||
_animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition);
|
||||
|
|
|
@ -68,6 +68,8 @@ public:
|
|||
bool isLeftEnabled;
|
||||
bool isRightEnabled;
|
||||
float bodyCapsuleRadius;
|
||||
float bodyCapsuleHalfHeight;
|
||||
glm::vec3 bodyCapsuleLocalOffset;
|
||||
glm::vec3 leftPosition = glm::vec3(); // rig space
|
||||
glm::quat leftOrientation = glm::quat(); // rig space (z forward)
|
||||
glm::vec3 rightPosition = glm::vec3(); // rig space
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -341,32 +349,30 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
|||
static QString userData;
|
||||
if (userData != zone->getUserData()) {
|
||||
userData = zone->getUserData();
|
||||
auto procedural = std::make_shared<Procedural>(userData);
|
||||
if (procedural->_enabled) {
|
||||
skybox->setProcedural(procedural);
|
||||
} else {
|
||||
skybox->setProcedural(ProceduralPointer());
|
||||
}
|
||||
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) };
|
||||
|
@ -31,7 +31,9 @@ EntityItemPointer RenderableBoxEntityItem::factory(const EntityItemID& entityID,
|
|||
void RenderableBoxEntityItem::setUserData(const QString& value) {
|
||||
if (value != getUserData()) {
|
||||
BoxEntityItem::setUserData(value);
|
||||
_procedural.reset();
|
||||
if (_procedural) {
|
||||
_procedural->parse(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,7 +42,6 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
|
|||
Q_ASSERT(getType() == EntityTypes::Box);
|
||||
Q_ASSERT(args->_batch);
|
||||
|
||||
|
||||
if (!_procedural) {
|
||||
_procedural.reset(new Procedural(this->getUserData()));
|
||||
_procedural->_vertexSource = simple_vert;
|
||||
|
@ -62,7 +63,7 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
|
|||
}
|
||||
|
||||
batch.setModelTransform(transToCenter); // we want to include the scale as well
|
||||
if (_procedural && _procedural->ready()) {
|
||||
if (_procedural->ready()) {
|
||||
_procedural->prepare(batch, getPosition(), getDimensions());
|
||||
auto color = _procedural->getColor(cubeColor);
|
||||
batch._glColor4f(color.r, color.g, color.b, color.a);
|
||||
|
|
|
@ -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.
|
||||
|
@ -36,7 +36,9 @@ EntityItemPointer RenderableSphereEntityItem::factory(const EntityItemID& entity
|
|||
void RenderableSphereEntityItem::setUserData(const QString& value) {
|
||||
if (value != getUserData()) {
|
||||
SphereEntityItem::setUserData(value);
|
||||
_procedural.reset();
|
||||
if (_procedural) {
|
||||
_procedural->parse(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -34,6 +34,8 @@ AssetUpload::AssetUpload(const QString& filename) :
|
|||
QString AssetUpload::getErrorString() const {
|
||||
// figure out the right error message for error
|
||||
switch (_error) {
|
||||
case AssetUpload::NoError:
|
||||
return QString();
|
||||
case AssetUpload::PermissionDenied:
|
||||
return PERMISSION_DENIED_ERROR;
|
||||
case AssetUpload::TooLarge:
|
||||
|
@ -42,9 +44,10 @@ QString AssetUpload::getErrorString() const {
|
|||
return "The file could not be opened. Please check your permissions and try again.";
|
||||
case AssetUpload::NetworkError:
|
||||
return "There was a problem reaching your Asset Server. Please check your network connectivity.";
|
||||
case AssetUpload::ServerFileError:
|
||||
return "The Asset Server failed to store the asset. Please try again.";
|
||||
default:
|
||||
// not handled, do not show a message box
|
||||
return QString();
|
||||
return QString("Unknown error with code %1").arg(_error);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,6 +69,8 @@ void AssetUpload::start() {
|
|||
|
||||
// emit that we are done
|
||||
emit finished(this, QString());
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,6 +95,9 @@ void AssetUpload::start() {
|
|||
case AssetServerError::PermissionDenied:
|
||||
_error = PermissionDenied;
|
||||
break;
|
||||
case AssetServerError::FileOperationFailed:
|
||||
_error = ServerFileError;
|
||||
break;
|
||||
default:
|
||||
_error = FileOpenError;
|
||||
break;
|
||||
|
|
|
@ -32,7 +32,8 @@ public:
|
|||
Timeout,
|
||||
TooLarge,
|
||||
PermissionDenied,
|
||||
FileOpenError
|
||||
FileOpenError,
|
||||
ServerFileError
|
||||
};
|
||||
|
||||
static const QString PERMISSION_DENIED_ERROR;
|
||||
|
|
|
@ -40,7 +40,8 @@ enum AssetServerError : uint8_t {
|
|||
InvalidByteRange,
|
||||
AssetTooLarge,
|
||||
PermissionDenied,
|
||||
MappingOperationFailed
|
||||
MappingOperationFailed,
|
||||
FileOperationFailed
|
||||
};
|
||||
|
||||
enum AssetMappingOperationType : uint8_t {
|
||||
|
|
|
@ -25,6 +25,27 @@ void MappingRequest::start() {
|
|||
doStart();
|
||||
};
|
||||
|
||||
QString MappingRequest::getErrorString() const {
|
||||
switch (_error) {
|
||||
case MappingRequest::NoError:
|
||||
return QString();
|
||||
case MappingRequest::NotFound:
|
||||
return "Asset not found";
|
||||
case MappingRequest::NetworkError:
|
||||
return "Unable to communicate with Asset Server";
|
||||
case MappingRequest::PermissionDenied:
|
||||
return "Permission denied";
|
||||
case MappingRequest::InvalidPath:
|
||||
return "Path is invalid";
|
||||
case MappingRequest::InvalidHash:
|
||||
return "Hash is invalid";
|
||||
case MappingRequest::UnknownError:
|
||||
return "Asset Server internal error";
|
||||
default:
|
||||
return QString("Unknown error with code %1").arg(_error);
|
||||
}
|
||||
}
|
||||
|
||||
GetMappingRequest::GetMappingRequest(const AssetPath& path) : _path(path.trimmed()) {
|
||||
};
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ public:
|
|||
|
||||
Q_INVOKABLE void start();
|
||||
Error getError() const { return _error; }
|
||||
Q_INVOKABLE QString getErrorString() const;
|
||||
|
||||
protected:
|
||||
Error _error { NoError };
|
||||
|
|
|
@ -79,6 +79,8 @@ public:
|
|||
glm::vec3 getLinearVelocity() const;
|
||||
|
||||
float getCapsuleRadius() const { return _radius; }
|
||||
float getCapsuleHalfHeight() const { return _halfHeight; }
|
||||
glm::vec3 getCapsuleLocalOffset() const { return _shapeLocalOffset; }
|
||||
|
||||
enum class State {
|
||||
Ground = 0,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -62,6 +62,9 @@ QJsonValue Procedural::getProceduralData(const QString& proceduralJson) {
|
|||
return doc.object()[PROCEDURAL_USER_DATA_KEY];
|
||||
}
|
||||
|
||||
Procedural::Procedural() {
|
||||
_state = std::make_shared<gpu::State>();
|
||||
}
|
||||
|
||||
Procedural::Procedural(const QString& userDataJson) {
|
||||
parse(userDataJson);
|
||||
|
@ -69,74 +72,111 @@ Procedural::Procedural(const QString& userDataJson) {
|
|||
}
|
||||
|
||||
void Procedural::parse(const QString& userDataJson) {
|
||||
_enabled = false;
|
||||
auto proceduralData = getProceduralData(userDataJson);
|
||||
if (proceduralData.isObject()) {
|
||||
parse(proceduralData.toObject());
|
||||
// Instead of parsing, prep for a parse on the rendering thread
|
||||
// This will be called by Procedural::ready
|
||||
std::lock_guard<std::mutex> lock(_proceduralDataMutex);
|
||||
_proceduralData = proceduralData.toObject();
|
||||
_proceduralDataDirty = true;
|
||||
}
|
||||
|
||||
bool Procedural::parseVersion(const QJsonValue& version) {
|
||||
if (version.isDouble()) {
|
||||
_version = (uint8_t)(floor(version.toDouble()));
|
||||
} else {
|
||||
// All unversioned shaders default to V1
|
||||
_version = 1;
|
||||
}
|
||||
return (_version == 1 || _version == 2);
|
||||
}
|
||||
|
||||
bool Procedural::parseUrl(const QUrl& shaderUrl) {
|
||||
if (!shaderUrl.isValid()) {
|
||||
qWarning() << "Invalid shader URL: " << shaderUrl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_shaderUrl == shaderUrl) {
|
||||
return true;
|
||||
}
|
||||
|
||||
_shaderUrl = shaderUrl;
|
||||
_shaderDirty = true;
|
||||
|
||||
if (_shaderUrl.isLocalFile()) {
|
||||
_shaderPath = _shaderUrl.toLocalFile();
|
||||
qDebug() << "Shader path: " << _shaderPath;
|
||||
if (!QFile(_shaderPath).exists()) {
|
||||
return false;;
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Shader url: " << _shaderUrl;
|
||||
_networkShader = ShaderCache::instance().getShader(_shaderUrl);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Procedural::parseUniforms(const QJsonObject& uniforms) {
|
||||
if (_parsedUniforms != uniforms) {
|
||||
_parsedUniforms = uniforms;
|
||||
_uniformsDirty = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Procedural::parseTextures(const QJsonArray& channels) {
|
||||
if (_parsedChannels != channels) {
|
||||
_parsedChannels = channels;
|
||||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
size_t channelCount = std::min(MAX_PROCEDURAL_TEXTURE_CHANNELS, (size_t)_parsedChannels.size());
|
||||
for (size_t i = 0; i < channelCount; ++i) {
|
||||
QString url = _parsedChannels.at((int)i).toString();
|
||||
_channels[i] = textureCache->getTexture(QUrl(url));
|
||||
}
|
||||
|
||||
_channelsDirty = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Procedural::parse(const QJsonObject& proceduralData) {
|
||||
// grab the version number
|
||||
{
|
||||
auto version = proceduralData[VERSION_KEY];
|
||||
if (version.isDouble()) {
|
||||
_version = (uint8_t)(floor(version.toDouble()));
|
||||
}
|
||||
_enabled = false;
|
||||
|
||||
if (proceduralData.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the path to the shader
|
||||
{
|
||||
QString shaderUrl = proceduralData[URL_KEY].toString();
|
||||
shaderUrl = ResourceManager::normalizeURL(shaderUrl);
|
||||
_shaderUrl = QUrl(shaderUrl);
|
||||
if (!_shaderUrl.isValid()) {
|
||||
qWarning() << "Invalid shader URL: " << shaderUrl;
|
||||
return;
|
||||
}
|
||||
auto version = proceduralData[VERSION_KEY];
|
||||
auto shaderUrl = proceduralData[URL_KEY].toString();
|
||||
shaderUrl = ResourceManager::normalizeURL(shaderUrl);
|
||||
auto uniforms = proceduralData[UNIFORMS_KEY].toObject();
|
||||
auto channels = proceduralData[CHANNELS_KEY].toArray();
|
||||
|
||||
if (_shaderUrl.isLocalFile()) {
|
||||
_shaderPath = _shaderUrl.toLocalFile();
|
||||
qDebug() << "Shader path: " << _shaderPath;
|
||||
if (!QFile(_shaderPath).exists()) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Shader url: " << _shaderUrl;
|
||||
_networkShader = ShaderCache::instance().getShader(_shaderUrl);
|
||||
}
|
||||
if (parseVersion(version) &&
|
||||
parseUrl(shaderUrl) &&
|
||||
parseUniforms(uniforms) &&
|
||||
parseTextures(channels)) {
|
||||
_enabled = true;
|
||||
}
|
||||
|
||||
// Grab any custom uniforms
|
||||
{
|
||||
auto uniforms = proceduralData[UNIFORMS_KEY];
|
||||
if (uniforms.isObject()) {
|
||||
_parsedUniforms = uniforms.toObject();
|
||||
}
|
||||
}
|
||||
|
||||
// Grab any textures
|
||||
{
|
||||
auto channels = proceduralData[CHANNELS_KEY];
|
||||
if (channels.isArray()) {
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
_parsedChannels = channels.toArray();
|
||||
size_t channelCount = std::min(MAX_PROCEDURAL_TEXTURE_CHANNELS, (size_t)_parsedChannels.size());
|
||||
for (size_t i = 0; i < channelCount; ++i) {
|
||||
QString url = _parsedChannels.at((int)i).toString();
|
||||
_channels[i] = textureCache->getTexture(QUrl(url));
|
||||
}
|
||||
}
|
||||
}
|
||||
_enabled = true;
|
||||
}
|
||||
|
||||
bool Procedural::ready() {
|
||||
// Load any changes to the procedural
|
||||
if (_proceduralDataDirty) {
|
||||
std::lock_guard<std::mutex> lock(_proceduralDataMutex);
|
||||
parse(_proceduralData);
|
||||
_proceduralDataDirty = false;
|
||||
}
|
||||
|
||||
if (!_enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do we have a network or local shader
|
||||
// Do we have a network or local shader, and if so, is it loaded?
|
||||
if (_shaderPath.isEmpty() && (!_networkShader || !_networkShader->isLoaded())) {
|
||||
return false;
|
||||
}
|
||||
|
@ -160,15 +200,14 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm
|
|||
QFile file(_shaderPath);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
_shaderSource = QTextStream(&file).readAll();
|
||||
_pipelineDirty = true;
|
||||
_shaderDirty = true;
|
||||
_shaderModified = lastModified;
|
||||
}
|
||||
} else if (_networkShader && _networkShader->isLoaded()) {
|
||||
_shaderSource = _networkShader->_source;
|
||||
}
|
||||
|
||||
if (!_pipeline || _pipelineDirty) {
|
||||
_pipelineDirty = true;
|
||||
if (!_pipeline || _shaderDirty) {
|
||||
if (!_vertexShader) {
|
||||
_vertexShader = gpu::Shader::createVertex(_vertexSource);
|
||||
}
|
||||
|
@ -192,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);
|
||||
|
||||
|
@ -214,11 +256,15 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm
|
|||
|
||||
batch.setPipeline(_pipeline);
|
||||
|
||||
if (_pipelineDirty) {
|
||||
_pipelineDirty = false;
|
||||
if (_shaderDirty || _uniformsDirty) {
|
||||
setupUniforms();
|
||||
}
|
||||
|
||||
if (_shaderDirty || _uniformsDirty || _channelsDirty) {
|
||||
setupChannels(_shaderDirty || _uniformsDirty);
|
||||
}
|
||||
|
||||
_shaderDirty = _uniformsDirty = _channelsDirty = false;
|
||||
|
||||
for (auto lambda : _uniforms) {
|
||||
lambda(batch);
|
||||
|
@ -359,8 +405,14 @@ void Procedural::setupUniforms() {
|
|||
batch._glUniform(_standardUniformSlots[POSITION], _entityPosition);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Procedural::setupChannels(bool shouldCreate) {
|
||||
if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[CHANNEL_RESOLUTION]) {
|
||||
if (!shouldCreate) {
|
||||
// Instead of modifying the last element, just remove and recreate it.
|
||||
_uniforms.pop_back();
|
||||
}
|
||||
_uniforms.push_back([=](gpu::Batch& batch) {
|
||||
vec3 channelSizes[MAX_PROCEDURAL_TEXTURE_CHANNELS];
|
||||
for (size_t i = 0; i < MAX_PROCEDURAL_TEXTURE_CHANNELS; ++i) {
|
||||
|
|
|
@ -28,27 +28,25 @@ const size_t MAX_PROCEDURAL_TEXTURE_CHANNELS{ 4 };
|
|||
// FIXME better encapsulation
|
||||
// FIXME better mechanism for extending to things rendered using shaders other than simple.slv
|
||||
struct Procedural {
|
||||
public:
|
||||
static QJsonValue getProceduralData(const QString& proceduralJson);
|
||||
|
||||
Procedural();
|
||||
Procedural(const QString& userDataJson);
|
||||
void parse(const QString& userDataJson);
|
||||
void parse(const QJsonObject&);
|
||||
|
||||
bool ready();
|
||||
void prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size);
|
||||
void setupUniforms();
|
||||
const gpu::ShaderPointer& getShader() const { return _shader; }
|
||||
|
||||
glm::vec4 getColor(const glm::vec4& entityColor);
|
||||
|
||||
bool _enabled{ false };
|
||||
uint8_t _version{ 1 };
|
||||
uint8_t _version { 1 };
|
||||
|
||||
std::string _vertexSource;
|
||||
std::string _fragmentSource;
|
||||
|
||||
QString _shaderSource;
|
||||
QString _shaderPath;
|
||||
QUrl _shaderUrl;
|
||||
quint64 _shaderModified{ 0 };
|
||||
bool _pipelineDirty{ true };
|
||||
gpu::StatePointer _state;
|
||||
|
||||
enum StandardUniforms {
|
||||
DATE,
|
||||
|
@ -60,23 +58,50 @@ struct Procedural {
|
|||
NUM_STANDARD_UNIFORMS
|
||||
};
|
||||
|
||||
int32_t _standardUniformSlots[NUM_STANDARD_UNIFORMS];
|
||||
protected:
|
||||
// Procedural metadata
|
||||
bool _enabled { false };
|
||||
uint64_t _start { 0 };
|
||||
int32_t _frameCount { 0 };
|
||||
|
||||
uint64_t _start{ 0 };
|
||||
int32_t _frameCount{ 0 };
|
||||
// Rendering object descriptions, from userData
|
||||
QJsonObject _proceduralData;
|
||||
std::mutex _proceduralDataMutex;
|
||||
QString _shaderSource;
|
||||
QString _shaderPath;
|
||||
QUrl _shaderUrl;
|
||||
quint64 _shaderModified { 0 };
|
||||
NetworkShaderPointer _networkShader;
|
||||
QJsonObject _parsedUniforms;
|
||||
QJsonArray _parsedChannels;
|
||||
bool _proceduralDataDirty { true };
|
||||
bool _shaderDirty { true };
|
||||
bool _uniformsDirty { true };
|
||||
bool _channelsDirty { true };
|
||||
|
||||
// Rendering objects
|
||||
UniformLambdas _uniforms;
|
||||
int32_t _standardUniformSlots[NUM_STANDARD_UNIFORMS];
|
||||
NetworkTexturePointer _channels[MAX_PROCEDURAL_TEXTURE_CHANNELS];
|
||||
gpu::PipelinePointer _pipeline;
|
||||
gpu::ShaderPointer _vertexShader;
|
||||
gpu::ShaderPointer _fragmentShader;
|
||||
gpu::ShaderPointer _shader;
|
||||
gpu::StatePointer _state;
|
||||
|
||||
// Entity metadata
|
||||
glm::vec3 _entityDimensions;
|
||||
glm::vec3 _entityPosition;
|
||||
|
||||
private:
|
||||
// This should only be called from the render thread, as it shares data with Procedural::prepare
|
||||
void parse(const QJsonObject&);
|
||||
bool parseVersion(const QJsonValue& version);
|
||||
bool parseUrl(const QUrl& url);
|
||||
bool parseUniforms(const QJsonObject& uniforms);
|
||||
bool parseTextures(const QJsonArray& channels);
|
||||
|
||||
void setupUniforms();
|
||||
void setupChannels(bool shouldCreate);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,55 +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() {
|
||||
}
|
||||
|
||||
ProceduralSkybox::ProceduralSkybox(const ProceduralSkybox& skybox) :
|
||||
model::Skybox(skybox),
|
||||
_procedural(skybox._procedural) {
|
||||
|
||||
}
|
||||
|
||||
void ProceduralSkybox::setProcedural(const ProceduralPointer& procedural) {
|
||||
_procedural = procedural;
|
||||
if (_procedural) {
|
||||
_procedural->_vertexSource = ProceduralSkybox_vert;
|
||||
_procedural->_fragmentSource = ProceduralSkybox_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));
|
||||
}
|
||||
_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)) {
|
||||
skybox.updateDataBuffer();
|
||||
Skybox::render(batch, viewFrustum, skybox);
|
||||
}
|
||||
glm::mat4 projMat;
|
||||
viewFrustum.evalProjectionMatrix(projMat);
|
||||
|
||||
if (skybox._procedural && skybox._procedural->_enabled && skybox._procedural->ready()) {
|
||||
gpu::TexturePointer skymap = skybox.getCubemap();
|
||||
// FIXME: skymap->isDefined may not be threadsafe
|
||||
assert(skymap && skymap->isDefined());
|
||||
Transform viewTransform;
|
||||
viewFrustum.evalViewTransform(viewTransform);
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewTransform);
|
||||
batch.setModelTransform(Transform()); // only for Mac
|
||||
|
||||
glm::mat4 projMat;
|
||||
viewFrustum.evalProjectionMatrix(projMat);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,22 +17,18 @@
|
|||
|
||||
#include "Procedural.h"
|
||||
|
||||
typedef std::shared_ptr<Procedural> ProceduralPointer;
|
||||
|
||||
class ProceduralSkybox: public model::Skybox {
|
||||
public:
|
||||
ProceduralSkybox();
|
||||
ProceduralSkybox(const ProceduralSkybox& skybox);
|
||||
ProceduralSkybox& operator= (const ProceduralSkybox& skybox);
|
||||
virtual ~ProceduralSkybox() {};
|
||||
|
||||
void setProcedural(const ProceduralPointer& procedural);
|
||||
void parse(const QString& userData) { _procedural.parse(userData); }
|
||||
|
||||
virtual void render(gpu::Batch& batch, const ViewFrustum& frustum) const;
|
||||
static void render(gpu::Batch& batch, const ViewFrustum& frustum, const ProceduralSkybox& skybox);
|
||||
|
||||
protected:
|
||||
ProceduralPointer _procedural;
|
||||
mutable Procedural _procedural;
|
||||
};
|
||||
typedef std::shared_ptr< ProceduralSkybox > ProceduralSkyboxPointer;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -48,6 +48,10 @@ ItemID Scene::allocateID() {
|
|||
return _IDAllocator.fetch_add(1);
|
||||
}
|
||||
|
||||
bool Scene::isAllocatedID(const ItemID& id) {
|
||||
return Item::isValidID(id) && (id < _numAllocatedItems.load());
|
||||
}
|
||||
|
||||
/// Enqueue change batch to the scene
|
||||
void Scene::enqueuePendingChanges(const PendingChanges& pendingChanges) {
|
||||
_changeQueueMutex.lock();
|
||||
|
@ -79,10 +83,22 @@ void Scene::processPendingChangesQueue() {
|
|||
}
|
||||
// Now we know for sure that we have enough items in the array to
|
||||
// capture anything coming from the pendingChanges
|
||||
|
||||
// resets and potential NEW items
|
||||
resetItems(consolidatedPendingChanges._resetItems, consolidatedPendingChanges._resetPayloads);
|
||||
|
||||
// Update the numItemsAtomic counter AFTER the reset changes went through
|
||||
_numAllocatedItems.exchange(maxID);
|
||||
|
||||
// updates
|
||||
updateItems(consolidatedPendingChanges._updatedItems, consolidatedPendingChanges._updateFunctors);
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
|
|
@ -60,18 +60,24 @@ public:
|
|||
// This call is thread safe, can be called from anywhere to allocate a new ID
|
||||
ItemID allocateID();
|
||||
|
||||
// Check that the ID is valid and allocated for this scene, this a threadsafe call
|
||||
bool isAllocatedID(const ItemID& id);
|
||||
|
||||
// THis is the total number of allocated items, this a threadsafe call
|
||||
size_t getNumItems() const { return _numAllocatedItems.load(); }
|
||||
|
||||
// Enqueue change batch to the scene
|
||||
void enqueuePendingChanges(const PendingChanges& pendingChanges);
|
||||
|
||||
// Process the penging changes equeued
|
||||
void processPendingChangesQueue();
|
||||
|
||||
// This next call are NOT threadsafe, you have to call them from the correct thread to avoid any potential issues
|
||||
|
||||
// Access a particular item form its ID
|
||||
// WARNING, There is No check on the validity of the ID, so this could return a bad Item
|
||||
const Item& getItem(const ItemID& id) const { return _items[id]; }
|
||||
|
||||
size_t getNumItems() const { return _items.size(); }
|
||||
|
||||
// Access the spatialized items
|
||||
const ItemSpatialTree& getSpatialTree() const { return _masterSpatialTree; }
|
||||
|
||||
|
@ -81,6 +87,7 @@ public:
|
|||
protected:
|
||||
// Thread safe elements that can be accessed from anywhere
|
||||
std::atomic<unsigned int> _IDAllocator{ 1 }; // first valid itemID will be One
|
||||
std::atomic<unsigned int> _numAllocatedItems{ 1 }; // num of allocated items, matching the _items.size()
|
||||
std::mutex _changeQueueMutex;
|
||||
PendingChangesQueue _changeQueue;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -68,6 +68,21 @@ void OpenVrDisplayPlugin::activate() {
|
|||
_compositor = vr::VRCompositor();
|
||||
Q_ASSERT(_compositor);
|
||||
HmdDisplayPlugin::activate();
|
||||
|
||||
// set up default sensor space such that the UI overlay will align with the front of the room.
|
||||
auto chaperone = vr::VRChaperone();
|
||||
if (chaperone) {
|
||||
float const UI_RADIUS = 1.0f;
|
||||
float const UI_HEIGHT = 1.6f;
|
||||
float const UI_Z_OFFSET = 0.5;
|
||||
|
||||
float xSize, zSize;
|
||||
chaperone->GetPlayAreaSize(&xSize, &zSize);
|
||||
glm::vec3 uiPos(0.0f, UI_HEIGHT, UI_RADIUS - (0.5f * zSize) - UI_Z_OFFSET);
|
||||
_sensorResetMat = glm::inverse(createMatFromQuatAndPos(glm::quat(), uiPos));
|
||||
} else {
|
||||
qDebug() << "OpenVR: error could not get chaperone pointer";
|
||||
}
|
||||
}
|
||||
|
||||
void OpenVrDisplayPlugin::deactivate() {
|
||||
|
@ -115,7 +130,7 @@ glm::mat4 OpenVrDisplayPlugin::getHeadPose(uint32_t frameIndex) const {
|
|||
#endif
|
||||
|
||||
vr::TrackedDevicePose_t predictedTrackedDevicePose[vr::k_unMaxTrackedDeviceCount];
|
||||
_system->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseSeated, predictedSecondsFromNow, predictedTrackedDevicePose, vr::k_unMaxTrackedDeviceCount);
|
||||
_system->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseStanding, predictedSecondsFromNow, predictedTrackedDevicePose, vr::k_unMaxTrackedDeviceCount);
|
||||
|
||||
// copy and process predictedTrackedDevicePoses
|
||||
for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) {
|
||||
|
@ -139,4 +154,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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -212,3 +212,15 @@ void GeometryUtilTests::testTwistSwingDecomposition() {
|
|||
}
|
||||
|
||||
|
||||
void GeometryUtilTests::testSphereCapsulePenetration() {
|
||||
glm::vec3 sphereCenter(1.5, 0.0, 0.0);
|
||||
float sphereRadius = 1.0f;
|
||||
glm::vec3 capsuleStart(0.0f, -10.0f, 0.0f);
|
||||
glm::vec3 capsuleEnd(0.0f, 10.0f, 0.0f);
|
||||
float capsuleRadius = 1.0f;
|
||||
|
||||
glm::vec3 penetration(glm::vec3::_null);
|
||||
bool hit = findSphereCapsulePenetration(sphereCenter, sphereRadius, capsuleStart, capsuleEnd, capsuleRadius, penetration);
|
||||
QCOMPARE(hit, true);
|
||||
QCOMPARE_WITH_ABS_ERROR(penetration, glm::vec3(-0.5f, 0.0f, 0.0f), EPSILON);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ private slots:
|
|||
void testLocalRayRectangleIntersection();
|
||||
void testWorldRayRectangleIntersection();
|
||||
void testTwistSwingDecomposition();
|
||||
void testSphereCapsulePenetration();
|
||||
};
|
||||
|
||||
float getErrorDifference(const float& a, const float& b);
|
||||
|
|
Loading…
Reference in a new issue