mirror of
https://github.com/lubosz/overte.git
synced 2025-04-24 02:53:43 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into proto-received-message
This commit is contained in:
commit
34138f07bd
74 changed files with 2419 additions and 550 deletions
|
@ -18,7 +18,7 @@ int AvatarMixerClientData::parseData(ReceivedMessage& message) {
|
|||
message.readPrimitive(&_lastReceivedSequenceNumber);
|
||||
|
||||
// compute the offset to the data payload
|
||||
return _avatar.parseDataFromBuffer(message.readWithoutCopy(message.getBytesLeftToRead()));
|
||||
return _avatar->parseDataFromBuffer(message.readWithoutCopy(message.getBytesLeftToRead()));
|
||||
}
|
||||
|
||||
bool AvatarMixerClientData::checkAndSetHasReceivedFirstPacketsFrom(const QUuid& uuid) {
|
||||
|
@ -40,7 +40,7 @@ uint16_t AvatarMixerClientData::getLastBroadcastSequenceNumber(const QUuid& node
|
|||
}
|
||||
|
||||
void AvatarMixerClientData::loadJSONStats(QJsonObject& jsonObject) const {
|
||||
jsonObject["display_name"] = _avatar.getDisplayName();
|
||||
jsonObject["display_name"] = _avatar->getDisplayName();
|
||||
jsonObject["full_rate_distance"] = _fullRateDistance;
|
||||
jsonObject["max_av_distance"] = _maxAvatarDistance;
|
||||
jsonObject["num_avs_sent_last_frame"] = _numAvatarsSentLastFrame;
|
||||
|
@ -49,7 +49,7 @@ void AvatarMixerClientData::loadJSONStats(QJsonObject& jsonObject) const {
|
|||
jsonObject["total_num_out_of_order_sends"] = _numOutOfOrderSends;
|
||||
|
||||
jsonObject[OUTBOUND_AVATAR_DATA_STATS_KEY] = getOutboundAvatarDataKbps();
|
||||
jsonObject[INBOUND_AVATAR_DATA_STATS_KEY] = _avatar.getAverageBytesReceivedPerSecond() / (float) BYTES_PER_KILOBIT;
|
||||
jsonObject[INBOUND_AVATAR_DATA_STATS_KEY] = _avatar->getAverageBytesReceivedPerSecond() / (float) BYTES_PER_KILOBIT;
|
||||
|
||||
jsonObject["av_data_receive_rate"] = _avatar.getReceiveRate();
|
||||
jsonObject["av_data_receive_rate"] = _avatar->getReceiveRate();
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ class AvatarMixerClientData : public NodeData {
|
|||
Q_OBJECT
|
||||
public:
|
||||
int parseData(ReceivedMessage& message) override;
|
||||
AvatarData& getAvatar() { return _avatar; }
|
||||
AvatarData& getAvatar() { return *_avatar; }
|
||||
|
||||
bool checkAndSetHasReceivedFirstPacketsFrom(const QUuid& uuid);
|
||||
|
||||
|
@ -80,7 +80,7 @@ public:
|
|||
|
||||
void loadJSONStats(QJsonObject& jsonObject) const;
|
||||
private:
|
||||
AvatarData _avatar;
|
||||
AvatarSharedPointer _avatar { new AvatarData() };
|
||||
|
||||
uint16_t _lastReceivedSequenceNumber { 0 };
|
||||
std::unordered_map<QUuid, uint16_t> _lastBroadcastSequenceNumbers;
|
||||
|
|
|
@ -34,9 +34,10 @@ var BUMPER_ON_VALUE = 0.5;
|
|||
// distant manipulation
|
||||
//
|
||||
|
||||
var DISTANCE_HOLDING_RADIUS_FACTOR = 5; // multiplied by distance between hand and object
|
||||
var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object
|
||||
var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position
|
||||
var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did
|
||||
var MOVE_WITH_HEAD = true; // experimental head-controll of distantly held objects
|
||||
|
||||
var NO_INTERSECT_COLOR = {
|
||||
red: 10,
|
||||
|
@ -658,6 +659,13 @@ function MyController(hand) {
|
|||
this.currentObjectTime = now;
|
||||
this.handRelativePreviousPosition = Vec3.subtract(handControllerPosition, MyAvatar.position);
|
||||
this.handPreviousRotation = handRotation;
|
||||
this.currentCameraOrientation = Camera.orientation;
|
||||
|
||||
// compute a constant based on the initial conditions which we use below to exagerate hand motion onto the held object
|
||||
this.radiusScalar = Math.log(Vec3.distance(this.currentObjectPosition, handControllerPosition) + 1.0);
|
||||
if (this.radiusScalar < 1.0) {
|
||||
this.radiusScalar = 1.0;
|
||||
}
|
||||
|
||||
this.actionID = NULL_ACTION_ID;
|
||||
this.actionID = Entities.addAction("spring", this.grabbedEntity, {
|
||||
|
@ -689,8 +697,6 @@ function MyController(hand) {
|
|||
this.currentAvatarOrientation = MyAvatar.orientation;
|
||||
|
||||
this.overlayLineOff();
|
||||
|
||||
|
||||
};
|
||||
|
||||
this.continueDistanceHolding = function() {
|
||||
|
@ -719,8 +725,12 @@ function MyController(hand) {
|
|||
this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR);
|
||||
|
||||
// the action was set up on a previous call. update the targets.
|
||||
var radius = Math.max(Vec3.distance(this.currentObjectPosition, handControllerPosition) *
|
||||
DISTANCE_HOLDING_RADIUS_FACTOR, DISTANCE_HOLDING_RADIUS_FACTOR);
|
||||
var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) *
|
||||
this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR;
|
||||
if (radius < 1.0) {
|
||||
radius = 1.0;
|
||||
}
|
||||
|
||||
// how far did avatar move this timestep?
|
||||
var currentPosition = MyAvatar.position;
|
||||
var avatarDeltaPosition = Vec3.subtract(currentPosition, this.currentAvatarPosition);
|
||||
|
@ -751,11 +761,11 @@ function MyController(hand) {
|
|||
var handMoved = Vec3.subtract(handToAvatar, this.handRelativePreviousPosition);
|
||||
this.handRelativePreviousPosition = handToAvatar;
|
||||
|
||||
// magnify the hand movement but not the change from avatar movement & rotation
|
||||
// magnify the hand movement but not the change from avatar movement & rotation
|
||||
handMoved = Vec3.subtract(handMoved, handMovementFromTurning);
|
||||
var superHandMoved = Vec3.multiply(handMoved, radius);
|
||||
|
||||
// Move the object by the magnified amount and then by amount from avatar movement & rotation
|
||||
// Move the object by the magnified amount and then by amount from avatar movement & rotation
|
||||
var newObjectPosition = Vec3.sum(this.currentObjectPosition, superHandMoved);
|
||||
newObjectPosition = Vec3.sum(newObjectPosition, avatarDeltaPosition);
|
||||
newObjectPosition = Vec3.sum(newObjectPosition, objectMovementFromTurning);
|
||||
|
@ -777,6 +787,16 @@ function MyController(hand) {
|
|||
|
||||
Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab");
|
||||
|
||||
// mix in head motion
|
||||
if (MOVE_WITH_HEAD) {
|
||||
var objDistance = Vec3.length(objectToAvatar);
|
||||
var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { x: 0.0, y: 0.0, z: objDistance });
|
||||
var after = Vec3.multiplyQbyV(Camera.orientation, { x: 0.0, y: 0.0, z: objDistance });
|
||||
var change = Vec3.subtract(before, after);
|
||||
this.currentCameraOrientation = Camera.orientation;
|
||||
this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change);
|
||||
}
|
||||
|
||||
Entities.updateAction(this.grabbedEntity, this.actionID, {
|
||||
targetPosition: this.currentObjectPosition,
|
||||
linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
|
||||
|
|
226
examples/data_visualization/earthquakes_live.js
Normal file
226
examples/data_visualization/earthquakes_live.js
Normal file
|
@ -0,0 +1,226 @@
|
|||
// earthquakes_live.js
|
||||
//
|
||||
// exploratory implementation in prep for abstract latlong to earth graphing tool for VR
|
||||
// shows all of the quakes in the past 24 hours reported by the USGS
|
||||
//
|
||||
// created by james b. pollack @imgntn on 12/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
|
||||
//
|
||||
// working notes: maybe try doing markers as boxes,rotated to the sphere normal, and with the height representing some value
|
||||
|
||||
Script.include('../libraries/promise.js');
|
||||
var Promise = loadPromise();
|
||||
|
||||
Script.include('../libraries/tinyColor.js');
|
||||
var tinyColor = loadTinyColor();
|
||||
|
||||
//you could make it the size of the actual earth.
|
||||
var EARTH_SPHERE_RADIUS = 6371;
|
||||
var EARTH_SPHERE_RADIUS = 2;
|
||||
|
||||
var EARTH_CENTER_POSITION = Vec3.sum(Vec3.sum(MyAvatar.position, {
|
||||
x: 0,
|
||||
y: 0.5,
|
||||
z: 0
|
||||
}), Vec3.multiply(EARTH_SPHERE_RADIUS, Quat.getFront(Camera.getOrientation())));
|
||||
|
||||
var EARTH_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/earthquakes_live/models/earth-noclouds.fbx';
|
||||
|
||||
var SHOULD_SPIN=false;
|
||||
var POLL_FOR_CHANGES = true;
|
||||
//USGS updates the data every five minutes
|
||||
var CHECK_QUAKE_FREQUENCY = 5 * 60 * 1000;
|
||||
|
||||
var QUAKE_MARKER_DIMENSIONS = {
|
||||
x: 0.01,
|
||||
y: 0.01,
|
||||
z: 0.01
|
||||
};
|
||||
|
||||
function createEarth() {
|
||||
var earthProperties = {
|
||||
name: 'Earth',
|
||||
type: 'Model',
|
||||
modelURL: EARTH_MODEL_URL,
|
||||
position: EARTH_CENTER_POSITION,
|
||||
dimensions: {
|
||||
x: EARTH_SPHERE_RADIUS,
|
||||
y: EARTH_SPHERE_RADIUS,
|
||||
z: EARTH_SPHERE_RADIUS
|
||||
},
|
||||
rotation: Quat.fromPitchYawRollDegrees(0, 90, 0),
|
||||
// collisionsWillMove: true,
|
||||
//if you have a shapetype it blocks the smaller markers
|
||||
// shapeType:'sphere'
|
||||
// userData: JSON.stringify({
|
||||
// grabbableKey: {
|
||||
// grabbable: false
|
||||
// }
|
||||
// })
|
||||
}
|
||||
|
||||
return Entities.addEntity(earthProperties)
|
||||
}
|
||||
|
||||
function latLongToVector3(lat, lon, radius, height) {
|
||||
var phi = (lat) * Math.PI / 180;
|
||||
var theta = (lon - 180) * Math.PI / 180;
|
||||
|
||||
var x = -(radius + height) * Math.cos(phi) * Math.cos(theta);
|
||||
var y = (radius + height) * Math.sin(phi);
|
||||
var z = (radius + height) * Math.cos(phi) * Math.sin(theta);
|
||||
|
||||
return {
|
||||
x: x,
|
||||
y: y,
|
||||
z: z
|
||||
};
|
||||
}
|
||||
|
||||
function getQuakePosition(earthquake) {
|
||||
var longitude = earthquake.geometry.coordinates[0];
|
||||
var latitude = earthquake.geometry.coordinates[1];
|
||||
var depth = earthquake.geometry.coordinates[2];
|
||||
|
||||
var latlng = latLongToVector3(latitude, longitude, EARTH_SPHERE_RADIUS / 2, 0);
|
||||
|
||||
var position = EARTH_CENTER_POSITION;
|
||||
var finalPosition = Vec3.sum(position, latlng);
|
||||
|
||||
//print('finalpos::' + JSON.stringify(finalPosition))
|
||||
return finalPosition
|
||||
}
|
||||
|
||||
var QUAKE_URL = 'http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson'
|
||||
|
||||
function get(url) {
|
||||
print('getting' + url)
|
||||
// Return a new promise.
|
||||
return new Promise(function(resolve, reject) {
|
||||
// Do the usual XHR stuff
|
||||
var req = new XMLHttpRequest();
|
||||
req.open('GET', url);
|
||||
req.onreadystatechange = function() {
|
||||
print('req status:: ' + JSON.stringify(req.status))
|
||||
|
||||
if (req.readyState == 4 && req.status == 200) {
|
||||
var myArr = JSON.parse(req.responseText);
|
||||
resolve(myArr);
|
||||
}
|
||||
};
|
||||
|
||||
req.send();
|
||||
});
|
||||
}
|
||||
|
||||
function createQuakeMarker(earthquake) {
|
||||
var markerProperties = {
|
||||
name: earthquake.properties.place,
|
||||
type: 'Sphere',
|
||||
parentID:earth,
|
||||
dimensions: QUAKE_MARKER_DIMENSIONS,
|
||||
position: getQuakePosition(earthquake),
|
||||
ignoreForCollisions:true,
|
||||
lifetime: 6000,
|
||||
color: getQuakeMarkerColor(earthquake)
|
||||
}
|
||||
|
||||
// print('marker properties::' + JSON.stringify(markerProperties))
|
||||
return Entities.addEntity(markerProperties);
|
||||
}
|
||||
|
||||
function getQuakeMarkerColor(earthquake) {
|
||||
var color = {};
|
||||
var magnitude = earthquake.properties.mag;
|
||||
//realistic but will never get full red coloring and will probably be pretty dull for most. must experiment
|
||||
var sValue = scale(magnitude, 0, 10, 0, 100);
|
||||
var HSL_string = "hsl(0, " + sValue + "%, 50%)"
|
||||
var color = tinyColor(HSL_string);
|
||||
var finalColor = {
|
||||
red: color._r,
|
||||
green: color._g,
|
||||
blue: color._b
|
||||
}
|
||||
|
||||
return finalColor
|
||||
}
|
||||
|
||||
function scale(value, min1, max1, min2, max2) {
|
||||
return min2 + (max2 - min2) * ((value - min1) / (max1 - min1));
|
||||
}
|
||||
|
||||
function processQuakes(earthquakes) {
|
||||
print('quakers length' + earthquakes.length)
|
||||
earthquakes.forEach(function(quake) {
|
||||
// print('PROCESSING A QUAKE')
|
||||
var marker = createQuakeMarker(quake);
|
||||
markers.push(marker);
|
||||
})
|
||||
print('markers length:' + markers.length)
|
||||
}
|
||||
|
||||
var quakes;
|
||||
var markers = [];
|
||||
|
||||
var earth = createEarth();
|
||||
|
||||
function getThenProcessQuakes() {
|
||||
get(QUAKE_URL).then(function(response) {
|
||||
print('got it::' + response.features.length)
|
||||
quakes = response.features;
|
||||
processQuakes(quakes);
|
||||
//print("Success!" + JSON.stringify(response));
|
||||
}, function(error) {
|
||||
print('error getting quakes')
|
||||
});
|
||||
}
|
||||
|
||||
function cleanupMarkers() {
|
||||
print('CLEANING UP MARKERS')
|
||||
while (markers.length > 0) {
|
||||
Entities.deleteEntity(markers.pop());
|
||||
}
|
||||
}
|
||||
|
||||
function cleanupEarth() {
|
||||
Entities.deleteEntity(earth);
|
||||
Script.update.disconnect(spinEarth);
|
||||
}
|
||||
|
||||
function cleanupInterval() {
|
||||
if (pollingInterval !== null) {
|
||||
Script.clearInterval(pollingInterval)
|
||||
}
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(cleanupMarkers);
|
||||
Script.scriptEnding.connect(cleanupEarth);
|
||||
Script.scriptEnding.connect(cleanupInterval);
|
||||
|
||||
getThenProcessQuakes();
|
||||
|
||||
var pollingInterval = null;
|
||||
|
||||
if (POLL_FOR_CHANGES === true) {
|
||||
pollingInterval = Script.setInterval(function() {
|
||||
cleanupMarkers();
|
||||
getThenProcessQuakes()
|
||||
}, CHECK_QUAKE_FREQUENCY)
|
||||
}
|
||||
|
||||
|
||||
function spinEarth(){
|
||||
Entities.editEntity(earth,{
|
||||
angularVelocity:{
|
||||
x:0,
|
||||
y:0.25,
|
||||
z:0
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if(SHOULD_SPIN===true){
|
||||
Script.update.connect(spinEarth);
|
||||
}
|
|
@ -392,6 +392,11 @@ var toolBar = (function() {
|
|||
url,
|
||||
file;
|
||||
|
||||
if (!event.isLeftButton) {
|
||||
// if another mouse button than left is pressed ignore it
|
||||
return false;
|
||||
}
|
||||
|
||||
clickedOverlay = Overlays.getOverlayAtPoint({
|
||||
x: event.x,
|
||||
y: event.y
|
||||
|
|
|
@ -2340,6 +2340,11 @@ SelectionDisplay = (function () {
|
|||
|
||||
that.mousePressEvent = function(event) {
|
||||
|
||||
if (!event.isLeftButton) {
|
||||
// if another mouse button than left is pressed ignore it
|
||||
return false;
|
||||
}
|
||||
|
||||
var somethingClicked = false;
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
|
||||
|
|
1155
examples/libraries/tinyColor.js
Normal file
1155
examples/libraries/tinyColor.js
Normal file
File diff suppressed because it is too large
Load diff
|
@ -45,7 +45,12 @@ Item {
|
|||
Text {
|
||||
color: root.fontColor;
|
||||
font.pixelSize: root.fontSize
|
||||
text: "Framerate: " + root.framerate
|
||||
text: "Render Rate: " + root.renderrate
|
||||
}
|
||||
Text {
|
||||
color: root.fontColor;
|
||||
font.pixelSize: root.fontSize
|
||||
text: "Present Rate: " + root.presentrate
|
||||
}
|
||||
Text {
|
||||
color: root.fontColor;
|
||||
|
|
|
@ -44,6 +44,9 @@
|
|||
|
||||
#include <QtNetwork/QNetworkDiskCache>
|
||||
|
||||
#include <gl/Config.h>
|
||||
#include <QtGui/QOpenGLContext>
|
||||
|
||||
#include <AccountManager.h>
|
||||
#include <AddressManager.h>
|
||||
#include <ApplicationVersion.h>
|
||||
|
@ -617,6 +620,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
|
||||
// enable mouse tracking; otherwise, we only get drag events
|
||||
_glWidget->setMouseTracking(true);
|
||||
_glWidget->makeCurrent();
|
||||
_glWidget->initializeGL();
|
||||
|
||||
_offscreenContext = new OffscreenGLCanvas();
|
||||
_offscreenContext->create(_glWidget->context()->contextHandle());
|
||||
|
@ -1136,7 +1141,7 @@ void Application::paintGL() {
|
|||
_lastInstantaneousFps = instantaneousFps;
|
||||
|
||||
auto displayPlugin = getActiveDisplayPlugin();
|
||||
displayPlugin->preRender();
|
||||
// FIXME not needed anymore?
|
||||
_offscreenContext->makeCurrent();
|
||||
|
||||
// update the avatar with a fresh HMD pose
|
||||
|
@ -1191,6 +1196,9 @@ void Application::paintGL() {
|
|||
QSize size = getDeviceSize();
|
||||
renderArgs._viewport = glm::ivec4(0, 0, size.width(), size.height());
|
||||
_applicationOverlay.renderOverlay(&renderArgs);
|
||||
gpu::FramebufferPointer overlayFramebuffer = _applicationOverlay.getOverlayFramebuffer();
|
||||
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -1304,6 +1312,13 @@ void Application::paintGL() {
|
|||
auto baseProjection = renderArgs._viewFrustum->getProjection();
|
||||
auto hmdInterface = DependencyManager::get<HMDScriptingInterface>();
|
||||
float IPDScale = hmdInterface->getIPDScale();
|
||||
|
||||
// Tell the plugin what pose we're using to render. In this case we're just using the
|
||||
// unmodified head pose because the only plugin that cares (the Oculus plugin) uses it
|
||||
// for rotational timewarp. If we move to support positonal timewarp, we need to
|
||||
// ensure this contains the full pose composed with the eye offsets.
|
||||
mat4 headPose = displayPlugin->getHeadPose(_frameCount);
|
||||
|
||||
// FIXME we probably don't need to set the projection matrix every frame,
|
||||
// only when the display plugin changes (or in non-HMD modes when the user
|
||||
// changes the FOV manually, which right now I don't think they can.
|
||||
|
@ -1319,12 +1334,7 @@ void Application::paintGL() {
|
|||
mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * IPDScale);
|
||||
eyeOffsets[eye] = eyeOffsetTransform;
|
||||
|
||||
// Tell the plugin what pose we're using to render. In this case we're just using the
|
||||
// unmodified head pose because the only plugin that cares (the Oculus plugin) uses it
|
||||
// for rotational timewarp. If we move to support positonal timewarp, we need to
|
||||
// ensure this contains the full pose composed with the eye offsets.
|
||||
mat4 headPose = displayPlugin->getHeadPose();
|
||||
displayPlugin->setEyeRenderPose(eye, headPose);
|
||||
displayPlugin->setEyeRenderPose(_frameCount, eye, headPose);
|
||||
|
||||
eyeProjections[eye] = displayPlugin->getProjection(eye, baseProjection);
|
||||
});
|
||||
|
@ -1339,6 +1349,7 @@ void Application::paintGL() {
|
|||
}
|
||||
|
||||
// Overlay Composition, needs to occur after screen space effects have completed
|
||||
// FIXME migrate composition into the display plugins
|
||||
{
|
||||
PROFILE_RANGE(__FUNCTION__ "/compositor");
|
||||
PerformanceTimer perfTimer("compositor");
|
||||
|
@ -1367,44 +1378,40 @@ void Application::paintGL() {
|
|||
{
|
||||
PROFILE_RANGE(__FUNCTION__ "/pluginOutput");
|
||||
PerformanceTimer perfTimer("pluginOutput");
|
||||
auto primaryFbo = framebufferCache->getPrimaryFramebuffer();
|
||||
GLuint finalTexture = gpu::GLBackend::getTextureID(primaryFbo->getRenderBuffer(0));
|
||||
// Ensure the rendering context commands are completed when rendering
|
||||
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
// Ensure the sync object is flushed to the driver thread before releasing the context
|
||||
// CRITICAL for the mac driver apparently.
|
||||
glFlush();
|
||||
_offscreenContext->doneCurrent();
|
||||
auto primaryFramebuffer = framebufferCache->getPrimaryFramebuffer();
|
||||
auto scratchFramebuffer = framebufferCache->getFramebuffer();
|
||||
gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) {
|
||||
gpu::Vec4i rect;
|
||||
rect.z = size.width();
|
||||
rect.w = size.height();
|
||||
batch.setFramebuffer(scratchFramebuffer);
|
||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f));
|
||||
batch.blit(primaryFramebuffer, rect, scratchFramebuffer, rect);
|
||||
batch.setFramebuffer(nullptr);
|
||||
});
|
||||
auto finalTexturePointer = scratchFramebuffer->getRenderBuffer(0);
|
||||
GLuint finalTexture = gpu::GLBackend::getTextureID(finalTexturePointer);
|
||||
Q_ASSERT(0 != finalTexture);
|
||||
|
||||
Q_ASSERT(!_lockedFramebufferMap.contains(finalTexture));
|
||||
_lockedFramebufferMap[finalTexture] = scratchFramebuffer;
|
||||
|
||||
// Switches to the display plugin context
|
||||
displayPlugin->preDisplay();
|
||||
// Ensure all operations from the previous context are complete before we try to read the fbo
|
||||
glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
|
||||
glDeleteSync(sync);
|
||||
uint64_t displayStart = usecTimestampNow();
|
||||
|
||||
Q_ASSERT(QOpenGLContext::currentContext() == _offscreenContext->getContext());
|
||||
{
|
||||
PROFILE_RANGE(__FUNCTION__ "/pluginDisplay");
|
||||
PerformanceTimer perfTimer("pluginDisplay");
|
||||
displayPlugin->display(finalTexture, toGlm(size));
|
||||
PROFILE_RANGE(__FUNCTION__ "/pluginSubmitScene");
|
||||
PerformanceTimer perfTimer("pluginSubmitScene");
|
||||
displayPlugin->submitSceneTexture(_frameCount, finalTexture, toGlm(size));
|
||||
}
|
||||
Q_ASSERT(QOpenGLContext::currentContext() == _offscreenContext->getContext());
|
||||
|
||||
{
|
||||
PROFILE_RANGE(__FUNCTION__ "/bufferSwap");
|
||||
PerformanceTimer perfTimer("bufferSwap");
|
||||
displayPlugin->finishFrame();
|
||||
}
|
||||
uint64_t displayEnd = usecTimestampNow();
|
||||
const float displayPeriodUsec = (float)(displayEnd - displayStart); // usecs
|
||||
_lastPaintWait = displayPeriodUsec / (float)USECS_PER_SECOND;
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("makeCurrent");
|
||||
_offscreenContext->makeCurrent();
|
||||
Stats::getInstance()->setRenderDetails(renderArgs._details);
|
||||
|
||||
// Reset the gpu::Context Stages
|
||||
// Back to the default framebuffer;
|
||||
gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) {
|
||||
|
@ -2612,7 +2619,7 @@ void Application::updateMyAvatarLookAtPosition() {
|
|||
lookAtPosition.x = -lookAtPosition.x;
|
||||
}
|
||||
if (isHMD) {
|
||||
glm::mat4 headPose = getActiveDisplayPlugin()->getHeadPose();
|
||||
glm::mat4 headPose = getActiveDisplayPlugin()->getHeadPose(_frameCount);
|
||||
glm::quat hmdRotation = glm::quat_cast(headPose);
|
||||
lookAtSpot = _myCamera.getPosition() + myAvatar->getOrientation() * (hmdRotation * lookAtPosition);
|
||||
} else {
|
||||
|
@ -4505,7 +4512,7 @@ void Application::takeSnapshot() {
|
|||
player->setMedia(QUrl::fromLocalFile(inf.absoluteFilePath()));
|
||||
player->play();
|
||||
|
||||
QString fileName = Snapshot::saveSnapshot(_glWidget->grabFrameBuffer());
|
||||
QString fileName = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot());
|
||||
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
if (!accountManager.isLoggedIn()) {
|
||||
|
@ -4516,7 +4523,6 @@ void Application::takeSnapshot() {
|
|||
_snapshotShareDialog = new SnapshotShareDialog(fileName, _glWidget);
|
||||
}
|
||||
_snapshotShareDialog->show();
|
||||
|
||||
}
|
||||
|
||||
float Application::getRenderResolutionScale() const {
|
||||
|
@ -4699,10 +4705,6 @@ const DisplayPlugin* Application::getActiveDisplayPlugin() const {
|
|||
return ((Application*)this)->getActiveDisplayPlugin();
|
||||
}
|
||||
|
||||
bool _activatingDisplayPlugin{ false };
|
||||
QVector<QPair<QString, QString>> _currentDisplayPluginActions;
|
||||
QVector<QPair<QString, QString>> _currentInputPluginActions;
|
||||
|
||||
static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool active = false) {
|
||||
auto menu = Menu::getInstance();
|
||||
QString name = displayPlugin->getName();
|
||||
|
@ -4732,9 +4734,10 @@ void Application::updateDisplayMode() {
|
|||
bool first = true;
|
||||
foreach(auto displayPlugin, displayPlugins) {
|
||||
addDisplayPluginToMenu(displayPlugin, first);
|
||||
QObject::connect(displayPlugin.get(), &DisplayPlugin::requestRender, [this] {
|
||||
paintGL();
|
||||
});
|
||||
// This must be a queued connection to avoid a deadlock
|
||||
QObject::connect(displayPlugin.get(), &DisplayPlugin::requestRender,
|
||||
this, &Application::paintGL, Qt::QueuedConnection);
|
||||
|
||||
QObject::connect(displayPlugin.get(), &DisplayPlugin::recommendedFramebufferSizeChanged, [this](const QSize & size) {
|
||||
resizeGL();
|
||||
});
|
||||
|
@ -4776,19 +4779,18 @@ void Application::updateDisplayMode() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!_currentDisplayPluginActions.isEmpty()) {
|
||||
|
||||
if (!_pluginContainer->currentDisplayActions().isEmpty()) {
|
||||
auto menu = Menu::getInstance();
|
||||
foreach(auto itemInfo, _currentDisplayPluginActions) {
|
||||
foreach(auto itemInfo, _pluginContainer->currentDisplayActions()) {
|
||||
menu->removeMenuItem(itemInfo.first, itemInfo.second);
|
||||
}
|
||||
_currentDisplayPluginActions.clear();
|
||||
_pluginContainer->currentDisplayActions().clear();
|
||||
}
|
||||
|
||||
if (newDisplayPlugin) {
|
||||
_offscreenContext->makeCurrent();
|
||||
_activatingDisplayPlugin = true;
|
||||
newDisplayPlugin->activate();
|
||||
_activatingDisplayPlugin = false;
|
||||
_offscreenContext->makeCurrent();
|
||||
offscreenUi->resize(fromGlm(newDisplayPlugin->getRecommendedUiSize()));
|
||||
_offscreenContext->makeCurrent();
|
||||
|
@ -4914,7 +4916,7 @@ mat4 Application::getEyeOffset(int eye) const {
|
|||
|
||||
mat4 Application::getHMDSensorPose() const {
|
||||
if (isHMDMode()) {
|
||||
return getActiveDisplayPlugin()->getHeadPose();
|
||||
return getActiveDisplayPlugin()->getHeadPose(_frameCount);
|
||||
}
|
||||
return mat4();
|
||||
}
|
||||
|
|
|
@ -158,6 +158,7 @@ public:
|
|||
|
||||
bool isForeground() const { return _isForeground; }
|
||||
|
||||
uint32_t getFrameCount() { return _frameCount; }
|
||||
float getFps() const { return _fps; }
|
||||
float const HMD_TARGET_FRAME_RATE = 75.0f;
|
||||
float const DESKTOP_TARGET_FRAME_RATE = 60.0f;
|
||||
|
@ -425,6 +426,9 @@ private:
|
|||
DisplayPluginPointer _displayPlugin;
|
||||
InputPluginList _activeInputPlugins;
|
||||
|
||||
bool _activatingDisplayPlugin { false };
|
||||
QMap<uint32_t, gpu::FramebufferPointer> _lockedFramebufferMap;
|
||||
|
||||
MainWindow* _window;
|
||||
|
||||
ToolWindow* _toolWindow;
|
||||
|
|
|
@ -13,27 +13,6 @@
|
|||
#include "Application.h"
|
||||
#include "GLCanvas.h"
|
||||
|
||||
#include <QWindow>
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "Menu.h"
|
||||
|
||||
void GLCanvas::paintGL() {
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
|
||||
// FIXME - I'm not sure why this still remains, it appears as if this GLCanvas gets a single paintGL call near
|
||||
// the beginning of the application starting up. I'm not sure if we really need to call Application::paintGL()
|
||||
// in this case, since the display plugins eventually handle all the painting
|
||||
bool isThrottleFPSEnabled = Menu::getInstance()->isOptionChecked(MenuOption::ThrottleFPSIfNotFocus);
|
||||
if (!qApp->getWindow()->isMinimized() || !isThrottleFPSEnabled) {
|
||||
qApp->paintGL();
|
||||
}
|
||||
}
|
||||
|
||||
void GLCanvas::resizeGL(int width, int height) {
|
||||
qApp->resizeGL();
|
||||
}
|
||||
|
||||
bool GLCanvas::event(QEvent* event) {
|
||||
if (QEvent::Paint == event->type() && qApp->isAboutToQuit()) {
|
||||
return true;
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
class GLCanvas : public GLWidget {
|
||||
Q_OBJECT
|
||||
protected:
|
||||
virtual void paintGL() override;
|
||||
virtual void resizeGL(int width, int height) override;
|
||||
virtual bool event(QEvent* event) override;
|
||||
};
|
||||
|
||||
|
|
|
@ -432,8 +432,6 @@ Menu::Menu() {
|
|||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AvatarReceiveStats, 0, false,
|
||||
avatarManager.data(), SLOT(setShouldShowReceiveStats(bool)));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderSkeletonCollisionShapes);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderHeadCollisionShapes);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderBoundingCollisionShapes);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtVectors, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtTargets, 0, false);
|
||||
|
|
|
@ -238,10 +238,8 @@ namespace MenuOption {
|
|||
const QString ReloadContent = "Reload Content (Clears all caches)";
|
||||
const QString RenderBoundingCollisionShapes = "Show Bounding Collision Shapes";
|
||||
const QString RenderFocusIndicator = "Show Eye Focus";
|
||||
const QString RenderHeadCollisionShapes = "Show Head Collision Shapes";
|
||||
const QString RenderLookAtTargets = "Show Look-at Targets";
|
||||
const QString RenderLookAtVectors = "Show Look-at Vectors";
|
||||
const QString RenderSkeletonCollisionShapes = "Show Skeleton Collision Shapes";
|
||||
const QString RenderResolution = "Scale Resolution";
|
||||
const QString RenderResolutionOne = "1";
|
||||
const QString RenderResolutionTwoThird = "2/3";
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
#include "PluginContainerProxy.h"
|
||||
|
||||
#include <QScreen>
|
||||
#include <QWindow>
|
||||
#include <QtGui/QScreen>
|
||||
#include <QtGui/QWindow>
|
||||
|
||||
#include <plugins/Plugin.h>
|
||||
#include <plugins/PluginManager.h>
|
||||
#include <display-plugins/DisplayPlugin.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <FramebufferCache.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "MainWindow.h"
|
||||
#include "GLCanvas.h"
|
||||
#include "ui/DialogsManager.h"
|
||||
|
||||
#include <gl/OffscreenGLCanvas.h>
|
||||
#include <QtGui/QOpenGLContext>
|
||||
|
||||
PluginContainerProxy::PluginContainerProxy() {
|
||||
}
|
||||
|
||||
|
@ -30,12 +35,7 @@ void PluginContainerProxy::removeMenu(const QString& menuName) {
|
|||
Menu::getInstance()->removeMenu(menuName);
|
||||
}
|
||||
|
||||
extern bool _activatingDisplayPlugin;
|
||||
extern QVector<QPair<QString, QString>> _currentDisplayPluginActions;
|
||||
extern QVector<QPair<QString, QString>> _currentInputPluginActions;
|
||||
std::map<QString, QActionGroup*> _exclusiveGroups;
|
||||
|
||||
QAction* PluginContainerProxy::addMenuItem(const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable, bool checked, const QString& groupName) {
|
||||
QAction* PluginContainerProxy::addMenuItem(PluginType type, const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable, bool checked, const QString& groupName) {
|
||||
auto menu = Menu::getInstance();
|
||||
MenuWrapper* parentItem = menu->getMenu(path);
|
||||
QAction* action = menu->addActionToQMenuAndActionHash(parentItem, name);
|
||||
|
@ -54,7 +54,7 @@ QAction* PluginContainerProxy::addMenuItem(const QString& path, const QString& n
|
|||
});
|
||||
action->setCheckable(checkable);
|
||||
action->setChecked(checked);
|
||||
if (_activatingDisplayPlugin) {
|
||||
if (type == PluginType::DISPLAY_PLUGIN) {
|
||||
_currentDisplayPluginActions.push_back({ path, name });
|
||||
} else {
|
||||
_currentInputPluginActions.push_back({ path, name });
|
||||
|
@ -150,10 +150,37 @@ void PluginContainerProxy::showDisplayPluginsTools() {
|
|||
DependencyManager::get<DialogsManager>()->hmdTools(true);
|
||||
}
|
||||
|
||||
QGLWidget* PluginContainerProxy::getPrimarySurface() {
|
||||
GLWidget* PluginContainerProxy::getPrimaryWidget() {
|
||||
return qApp->_glWidget;
|
||||
}
|
||||
|
||||
QWindow* PluginContainerProxy::getPrimaryWindow() {
|
||||
return qApp->_glWidget->windowHandle();
|
||||
}
|
||||
|
||||
QOpenGLContext* PluginContainerProxy::getPrimaryContext() {
|
||||
return qApp->_glWidget->context()->contextHandle();
|
||||
}
|
||||
|
||||
const DisplayPlugin* PluginContainerProxy::getActiveDisplayPlugin() const {
|
||||
return qApp->getActiveDisplayPlugin();
|
||||
}
|
||||
|
||||
bool PluginContainerProxy::makeRenderingContextCurrent() {
|
||||
return qApp->_offscreenContext->makeCurrent();
|
||||
}
|
||||
|
||||
void PluginContainerProxy::releaseSceneTexture(uint32_t texture) {
|
||||
Q_ASSERT(QThread::currentThread() == qApp->thread());
|
||||
auto& framebufferMap = qApp->_lockedFramebufferMap;
|
||||
Q_ASSERT(framebufferMap.contains(texture));
|
||||
auto framebufferPointer = framebufferMap[texture];
|
||||
framebufferMap.remove(texture);
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
framebufferCache->releaseFramebuffer(framebufferPointer);
|
||||
}
|
||||
|
||||
void PluginContainerProxy::releaseOverlayTexture(uint32_t texture) {
|
||||
// FIXME implement present thread compositing
|
||||
}
|
||||
|
||||
|
|
|
@ -2,19 +2,21 @@
|
|||
#ifndef hifi_PluginContainerProxy_h
|
||||
#define hifi_PluginContainerProxy_h
|
||||
|
||||
#include <QObject>
|
||||
#include <QRect>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QRect>
|
||||
|
||||
#include <plugins/Forward.h>
|
||||
#include <plugins/PluginContainer.h>
|
||||
|
||||
class QActionGroup;
|
||||
|
||||
class PluginContainerProxy : public QObject, PluginContainer {
|
||||
Q_OBJECT
|
||||
PluginContainerProxy();
|
||||
virtual ~PluginContainerProxy();
|
||||
virtual void addMenu(const QString& menuName) override;
|
||||
virtual void removeMenu(const QString& menuName) override;
|
||||
virtual QAction* addMenuItem(const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override;
|
||||
virtual QAction* addMenuItem(PluginType type, const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override;
|
||||
virtual void removeMenuItem(const QString& menuName, const QString& menuItem) override;
|
||||
virtual bool isOptionChecked(const QString& name) override;
|
||||
virtual void setIsOptionChecked(const QString& path, bool checked) override;
|
||||
|
@ -22,13 +24,20 @@ class PluginContainerProxy : public QObject, PluginContainer {
|
|||
virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) override;
|
||||
virtual void showDisplayPluginsTools() override;
|
||||
virtual void requestReset() override;
|
||||
virtual QGLWidget* getPrimarySurface() override;
|
||||
virtual bool makeRenderingContextCurrent() override;
|
||||
virtual void releaseSceneTexture(uint32_t texture) override;
|
||||
virtual void releaseOverlayTexture(uint32_t texture) override;
|
||||
virtual GLWidget* getPrimaryWidget() override;
|
||||
virtual QWindow* getPrimaryWindow() override;
|
||||
virtual QOpenGLContext* getPrimaryContext() override;
|
||||
virtual bool isForeground() override;
|
||||
virtual const DisplayPlugin* getActiveDisplayPlugin() const override;
|
||||
|
||||
QRect _savedGeometry{ 10, 120, 800, 600 };
|
||||
std::map<QString, QActionGroup*> _exclusiveGroups;
|
||||
|
||||
friend class Application;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -433,16 +433,6 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO: re-implement these when we have more detailed avatar collision shapes
|
||||
bool renderSkeleton = Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes);
|
||||
if (renderSkeleton) {
|
||||
}
|
||||
bool renderHead = Menu::getInstance()->isOptionChecked(MenuOption::RenderHeadCollisionShapes);
|
||||
if (renderHead && shouldRenderHead(renderArgs)) {
|
||||
}
|
||||
*/
|
||||
|
||||
bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes);
|
||||
if (renderBounding && shouldRenderHead(renderArgs) && _skeletonModel.isRenderable()) {
|
||||
PROFILE_RANGE_BATCH(batch, __FUNCTION__":skeletonBoundingCollisionShapes");
|
||||
|
@ -867,18 +857,12 @@ QVector<glm::quat> Avatar::getJointRotations() const {
|
|||
}
|
||||
|
||||
glm::quat Avatar::getJointRotation(int index) const {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
return AvatarData::getJointRotation(index);
|
||||
}
|
||||
glm::quat rotation;
|
||||
_skeletonModel.getJointRotation(index, rotation);
|
||||
return rotation;
|
||||
}
|
||||
|
||||
glm::vec3 Avatar::getJointTranslation(int index) const {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
return AvatarData::getJointTranslation(index);
|
||||
}
|
||||
glm::vec3 translation;
|
||||
_skeletonModel.getJointTranslation(index, translation);
|
||||
return translation;
|
||||
|
|
|
@ -30,7 +30,8 @@ void AvatarUpdate::synchronousProcess() {
|
|||
|
||||
// Keep our own updated value, so that our asynchronous code can consult it.
|
||||
_isHMDMode = qApp->isHMDMode();
|
||||
_headPose = qApp->getActiveDisplayPlugin()->getHeadPose();
|
||||
auto frameCount = qApp->getFrameCount();
|
||||
_headPose = qApp->getActiveDisplayPlugin()->getHeadPose(frameCount);
|
||||
|
||||
if (_updateBillboard) {
|
||||
DependencyManager::get<AvatarManager>()->getMyAvatar()->doUpdateBillboard();
|
||||
|
|
|
@ -1200,7 +1200,7 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, fl
|
|||
if (qApp->isHMDMode()) {
|
||||
glm::vec3 cameraPosition = qApp->getCamera()->getPosition();
|
||||
|
||||
glm::mat4 headPose = qApp->getActiveDisplayPlugin()->getHeadPose();
|
||||
glm::mat4 headPose = qApp->getActiveDisplayPlugin()->getHeadPose(qApp->getFrameCount());
|
||||
glm::mat4 leftEyePose = qApp->getActiveDisplayPlugin()->getEyeToHeadTransform(Eye::Left);
|
||||
leftEyePose = leftEyePose * headPose;
|
||||
glm::vec3 leftEyePosition = extractTranslation(leftEyePose);
|
||||
|
@ -1254,6 +1254,16 @@ void MyAvatar::initHeadBones() {
|
|||
}
|
||||
}
|
||||
|
||||
void MyAvatar::setAnimGraphUrl(const QUrl& url) {
|
||||
if (_animGraphUrl == url) {
|
||||
return;
|
||||
}
|
||||
destroyAnimGraph();
|
||||
_skeletonModel.reset(); // Why is this necessary? Without this, we crash in the next render.
|
||||
_animGraphUrl = url;
|
||||
initAnimGraph();
|
||||
}
|
||||
|
||||
void MyAvatar::initAnimGraph() {
|
||||
// avatar.json
|
||||
// https://gist.github.com/hyperlogic/7d6a0892a7319c69e2b9
|
||||
|
@ -1270,9 +1280,9 @@ void MyAvatar::initAnimGraph() {
|
|||
// or run a local web-server
|
||||
// python -m SimpleHTTPServer&
|
||||
//auto graphUrl = QUrl("http://localhost:8000/avatar.json");
|
||||
auto graphUrl = QUrl(_animGraphUrl.isEmpty() ?
|
||||
QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_full/avatar-animation.json") :
|
||||
_animGraphUrl);
|
||||
auto graphUrl =_animGraphUrl.isEmpty() ?
|
||||
QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_full/avatar-animation.json") :
|
||||
QUrl(_animGraphUrl);
|
||||
_rig->initAnimGraph(graphUrl);
|
||||
|
||||
_bodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation..
|
||||
|
|
|
@ -249,13 +249,13 @@ public slots:
|
|||
|
||||
virtual void rebuildSkeletonBody() override;
|
||||
|
||||
const QString& getAnimGraphUrl() const { return _animGraphUrl; }
|
||||
Q_INVOKABLE QUrl getAnimGraphUrl() const { return _animGraphUrl; }
|
||||
|
||||
void setEnableDebugDrawDefaultPose(bool isEnabled);
|
||||
void setEnableDebugDrawAnimPose(bool isEnabled);
|
||||
void setEnableDebugDrawPosition(bool isEnabled);
|
||||
void setEnableMeshVisible(bool isEnabled);
|
||||
void setAnimGraphUrl(const QString& url) { _animGraphUrl = url; }
|
||||
Q_INVOKABLE void setAnimGraphUrl(const QUrl& url);
|
||||
|
||||
glm::vec3 getPositionForAudio();
|
||||
glm::quat getOrientationForAudio();
|
||||
|
@ -356,7 +356,7 @@ private:
|
|||
// Avatar Preferences
|
||||
QUrl _fullAvatarURLFromPreferences;
|
||||
QString _fullAvatarModelName;
|
||||
QString _animGraphUrl {""};
|
||||
QUrl _animGraphUrl {""};
|
||||
|
||||
// cache of the current HMD sensor position and orientation
|
||||
// in sensor space.
|
||||
|
|
|
@ -287,7 +287,7 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int
|
|||
mat4 camMat;
|
||||
_cameraBaseTransform.getMatrix(camMat);
|
||||
auto displayPlugin = qApp->getActiveDisplayPlugin();
|
||||
auto headPose = displayPlugin->getHeadPose();
|
||||
auto headPose = displayPlugin->getHeadPose(qApp->getFrameCount());
|
||||
auto eyeToHead = displayPlugin->getEyeToHeadTransform((Eye)eye);
|
||||
camMat = (headPose * eyeToHead) * camMat;
|
||||
batch.setViewportTransform(renderArgs->_viewport);
|
||||
|
|
|
@ -188,9 +188,9 @@ void PreferencesDialog::loadPreferences() {
|
|||
ui.fieldOfViewSpin->setValue(qApp->getFieldOfView());
|
||||
|
||||
ui.leanScaleSpin->setValue(myAvatar->getLeanScale());
|
||||
|
||||
|
||||
ui.avatarScaleSpin->setValue(myAvatar->getAvatarScale());
|
||||
ui.avatarAnimationEdit->setText(myAvatar->getAnimGraphUrl());
|
||||
ui.avatarAnimationEdit->setText(myAvatar->getAnimGraphUrl().toString());
|
||||
|
||||
ui.maxOctreePPSSpin->setValue(qApp->getMaxOctreePacketsPerSecond());
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <LODManager.h>
|
||||
#include <OffscreenUi.h>
|
||||
#include <PerfStat.h>
|
||||
#include <plugins/DisplayPlugin.h>
|
||||
|
||||
#include "BandwidthRecorder.h"
|
||||
#include "Menu.h"
|
||||
|
@ -118,7 +119,12 @@ void Stats::updateStats(bool force) {
|
|||
STAT_UPDATE(avatarRenderableCount, avatarManager->getNumberInRenderRange());
|
||||
STAT_UPDATE(avatarRenderDistance, (int) round(avatarManager->getRenderDistance())); // deliberately truncating
|
||||
STAT_UPDATE(serverCount, nodeList->size());
|
||||
STAT_UPDATE(framerate, (int)qApp->getFps());
|
||||
STAT_UPDATE(renderrate, (int)qApp->getFps());
|
||||
if (qApp->getActiveDisplayPlugin()) {
|
||||
STAT_UPDATE(presentrate, (int)round(qApp->getActiveDisplayPlugin()->presentRate()));
|
||||
} else {
|
||||
STAT_UPDATE(presentrate, -1);
|
||||
}
|
||||
STAT_UPDATE(simrate, (int)qApp->getAverageSimsPerSecond());
|
||||
STAT_UPDATE(avatarSimrate, (int)qApp->getAvatarSimrate());
|
||||
|
||||
|
|
|
@ -32,7 +32,8 @@ class Stats : public QQuickItem {
|
|||
Q_PROPERTY(float audioPacketlossDownstream READ getAudioPacketLossDownstream)
|
||||
|
||||
STATS_PROPERTY(int, serverCount, 0)
|
||||
STATS_PROPERTY(int, framerate, 0)
|
||||
STATS_PROPERTY(int, renderrate, 0)
|
||||
STATS_PROPERTY(int, presentrate, 0)
|
||||
STATS_PROPERTY(int, simrate, 0)
|
||||
STATS_PROPERTY(int, avatarSimrate, 0)
|
||||
STATS_PROPERTY(int, avatarCount, 0)
|
||||
|
@ -115,7 +116,8 @@ signals:
|
|||
void expandedChanged();
|
||||
void timingExpandedChanged();
|
||||
void serverCountChanged();
|
||||
void framerateChanged();
|
||||
void renderrateChanged();
|
||||
void presentrateChanged();
|
||||
void simrateChanged();
|
||||
void avatarSimrateChanged();
|
||||
void avatarCountChanged();
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <GeometryCache.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
#include <DeferredLightingEffect.h>
|
||||
|
||||
|
||||
QString const Line3DOverlay::TYPE = "line3d";
|
||||
|
@ -53,6 +54,7 @@ void Line3DOverlay::render(RenderArgs* args) {
|
|||
auto batch = args->_batch;
|
||||
if (batch) {
|
||||
batch->setModelTransform(_transform);
|
||||
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(*batch);
|
||||
|
||||
if (getIsDashedLine()) {
|
||||
// TODO: add support for color to renderDashedLine()
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include <glm/gtx/vector_angle.hpp>
|
||||
#include <queue>
|
||||
#include <QScriptValueIterator>
|
||||
#include <QWriteLocker>
|
||||
#include <QReadLocker>
|
||||
|
||||
#include <NumericalConstants.h>
|
||||
#include <DebugDraw.h>
|
||||
|
@ -158,10 +160,10 @@ void Rig::destroyAnimGraph() {
|
|||
_animSkeleton.reset();
|
||||
_animLoader.reset();
|
||||
_animNode.reset();
|
||||
_relativePoses.clear();
|
||||
_absolutePoses.clear();
|
||||
_overridePoses.clear();
|
||||
_overrideFlags.clear();
|
||||
_internalPoseSet._relativePoses.clear();
|
||||
_internalPoseSet._absolutePoses.clear();
|
||||
_internalPoseSet._overridePoses.clear();
|
||||
_internalPoseSet._overrideFlags.clear();
|
||||
}
|
||||
|
||||
void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOffset) {
|
||||
|
@ -173,16 +175,16 @@ void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOff
|
|||
|
||||
computeEyesInRootFrame(_animSkeleton->getRelativeDefaultPoses());
|
||||
|
||||
_relativePoses.clear();
|
||||
_relativePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||
_internalPoseSet._relativePoses.clear();
|
||||
_internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||
|
||||
buildAbsoluteRigPoses(_relativePoses, _absolutePoses);
|
||||
buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses);
|
||||
|
||||
_overridePoses.clear();
|
||||
_overridePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||
_internalPoseSet._overridePoses.clear();
|
||||
_internalPoseSet._overridePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||
|
||||
_overrideFlags.clear();
|
||||
_overrideFlags.resize(_animSkeleton->getNumJoints(), false);
|
||||
_internalPoseSet._overrideFlags.clear();
|
||||
_internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false);
|
||||
|
||||
buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses);
|
||||
|
||||
|
@ -201,16 +203,16 @@ void Rig::reset(const FBXGeometry& geometry) {
|
|||
|
||||
computeEyesInRootFrame(_animSkeleton->getRelativeDefaultPoses());
|
||||
|
||||
_relativePoses.clear();
|
||||
_relativePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||
_internalPoseSet._relativePoses.clear();
|
||||
_internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||
|
||||
buildAbsoluteRigPoses(_relativePoses, _absolutePoses);
|
||||
buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses);
|
||||
|
||||
_overridePoses.clear();
|
||||
_overridePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||
_internalPoseSet._overridePoses.clear();
|
||||
_internalPoseSet._overridePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||
|
||||
_overrideFlags.clear();
|
||||
_overrideFlags.resize(_animSkeleton->getNumJoints(), false);
|
||||
_internalPoseSet._overrideFlags.clear();
|
||||
_internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false);
|
||||
|
||||
buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses);
|
||||
|
||||
|
@ -228,11 +230,11 @@ void Rig::reset(const FBXGeometry& geometry) {
|
|||
}
|
||||
|
||||
bool Rig::jointStatesEmpty() {
|
||||
return _relativePoses.empty();
|
||||
return _internalPoseSet._relativePoses.empty();
|
||||
}
|
||||
|
||||
int Rig::getJointStateCount() const {
|
||||
return _relativePoses.size();
|
||||
return _internalPoseSet._relativePoses.size();
|
||||
}
|
||||
|
||||
int Rig::indexOfJoint(const QString& jointName) const {
|
||||
|
@ -262,7 +264,7 @@ void Rig::setModelOffset(const glm::mat4& modelOffsetMat) {
|
|||
|
||||
bool Rig::getJointStateRotation(int index, glm::quat& rotation) const {
|
||||
if (isIndexValid(index)) {
|
||||
rotation = _relativePoses[index].rot;
|
||||
rotation = _internalPoseSet._relativePoses[index].rot;
|
||||
return !isEqual(rotation, _animSkeleton->getRelativeDefaultPose(index).rot);
|
||||
} else {
|
||||
return false;
|
||||
|
@ -271,7 +273,7 @@ bool Rig::getJointStateRotation(int index, glm::quat& rotation) const {
|
|||
|
||||
bool Rig::getJointStateTranslation(int index, glm::vec3& translation) const {
|
||||
if (isIndexValid(index)) {
|
||||
translation = _relativePoses[index].trans;
|
||||
translation = _internalPoseSet._relativePoses[index].trans;
|
||||
return !isEqual(translation, _animSkeleton->getRelativeDefaultPose(index).trans);
|
||||
} else {
|
||||
return false;
|
||||
|
@ -280,46 +282,46 @@ bool Rig::getJointStateTranslation(int index, glm::vec3& translation) const {
|
|||
|
||||
void Rig::clearJointState(int index) {
|
||||
if (isIndexValid(index)) {
|
||||
_overrideFlags[index] = false;
|
||||
_internalPoseSet._overrideFlags[index] = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Rig::clearJointStates() {
|
||||
_overrideFlags.clear();
|
||||
_overrideFlags.resize(_animSkeleton->getNumJoints());
|
||||
_internalPoseSet._overrideFlags.clear();
|
||||
_internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints());
|
||||
}
|
||||
|
||||
void Rig::clearJointAnimationPriority(int index) {
|
||||
if (isIndexValid(index)) {
|
||||
_overrideFlags[index] = false;
|
||||
_internalPoseSet._overrideFlags[index] = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Rig::setJointTranslation(int index, bool valid, const glm::vec3& translation, float priority) {
|
||||
if (isIndexValid(index)) {
|
||||
if (valid) {
|
||||
assert(_overrideFlags.size() == _overridePoses.size());
|
||||
_overrideFlags[index] = true;
|
||||
_overridePoses[index].trans = translation;
|
||||
assert(_internalPoseSet._overrideFlags.size() == _internalPoseSet._overridePoses.size());
|
||||
_internalPoseSet._overrideFlags[index] = true;
|
||||
_internalPoseSet._overridePoses[index].trans = translation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Rig::setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation, float priority) {
|
||||
if (isIndexValid(index)) {
|
||||
assert(_overrideFlags.size() == _overridePoses.size());
|
||||
_overrideFlags[index] = true;
|
||||
_overridePoses[index].rot = rotation;
|
||||
_overridePoses[index].trans = translation;
|
||||
assert(_internalPoseSet._overrideFlags.size() == _internalPoseSet._overridePoses.size());
|
||||
_internalPoseSet._overrideFlags[index] = true;
|
||||
_internalPoseSet._overridePoses[index].rot = rotation;
|
||||
_internalPoseSet._overridePoses[index].trans = translation;
|
||||
}
|
||||
}
|
||||
|
||||
void Rig::setJointRotation(int index, bool valid, const glm::quat& rotation, float priority) {
|
||||
if (isIndexValid(index)) {
|
||||
if (valid) {
|
||||
ASSERT(_overrideFlags.size() == _overridePoses.size());
|
||||
_overrideFlags[index] = true;
|
||||
_overridePoses[index].rot = rotation;
|
||||
ASSERT(_internalPoseSet._overrideFlags.size() == _internalPoseSet._overridePoses.size());
|
||||
_internalPoseSet._overrideFlags[index] = true;
|
||||
_internalPoseSet._overridePoses[index].rot = rotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -336,7 +338,7 @@ void Rig::restoreJointTranslation(int index, float fraction, float priority) {
|
|||
|
||||
bool Rig::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position, glm::vec3 translation, glm::quat rotation) const {
|
||||
if (isIndexValid(jointIndex)) {
|
||||
position = (rotation * _absolutePoses[jointIndex].trans) + translation;
|
||||
position = (rotation * _internalPoseSet._absolutePoses[jointIndex].trans) + translation;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -345,7 +347,7 @@ bool Rig::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position, glm:
|
|||
|
||||
bool Rig::getJointPosition(int jointIndex, glm::vec3& position) const {
|
||||
if (isIndexValid(jointIndex)) {
|
||||
position = _absolutePoses[jointIndex].trans;
|
||||
position = _internalPoseSet._absolutePoses[jointIndex].trans;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -354,7 +356,7 @@ bool Rig::getJointPosition(int jointIndex, glm::vec3& position) const {
|
|||
|
||||
bool Rig::getJointRotationInWorldFrame(int jointIndex, glm::quat& result, const glm::quat& rotation) const {
|
||||
if (isIndexValid(jointIndex)) {
|
||||
result = rotation * _absolutePoses[jointIndex].rot;
|
||||
result = rotation * _internalPoseSet._absolutePoses[jointIndex].rot;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -362,8 +364,9 @@ bool Rig::getJointRotationInWorldFrame(int jointIndex, glm::quat& result, const
|
|||
}
|
||||
|
||||
bool Rig::getJointRotation(int jointIndex, glm::quat& rotation) const {
|
||||
if (isIndexValid(jointIndex)) {
|
||||
rotation = _relativePoses[jointIndex].rot;
|
||||
QReadLocker readLock(&_externalPoseSetLock);
|
||||
if (jointIndex >= 0 && jointIndex < (int)_externalPoseSet._relativePoses.size()) {
|
||||
rotation = _externalPoseSet._relativePoses[jointIndex].rot;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -371,8 +374,9 @@ bool Rig::getJointRotation(int jointIndex, glm::quat& rotation) const {
|
|||
}
|
||||
|
||||
bool Rig::getJointTranslation(int jointIndex, glm::vec3& translation) const {
|
||||
if (isIndexValid(jointIndex)) {
|
||||
translation = _relativePoses[jointIndex].trans;
|
||||
QReadLocker readLock(&_externalPoseSetLock);
|
||||
if (jointIndex >= 0 && jointIndex < (int)_externalPoseSet._relativePoses.size()) {
|
||||
translation = _externalPoseSet._relativePoses[jointIndex].trans;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -708,21 +712,27 @@ void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) {
|
|||
|
||||
// evaluate the animation
|
||||
AnimNode::Triggers triggersOut;
|
||||
_relativePoses = _animNode->evaluate(_animVars, deltaTime, triggersOut);
|
||||
if ((int)_relativePoses.size() != _animSkeleton->getNumJoints()) {
|
||||
_internalPoseSet._relativePoses = _animNode->evaluate(_animVars, deltaTime, triggersOut);
|
||||
if ((int)_internalPoseSet._relativePoses.size() != _animSkeleton->getNumJoints()) {
|
||||
// animations haven't fully loaded yet.
|
||||
_relativePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||
_internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||
}
|
||||
_animVars.clearTriggers();
|
||||
for (auto& trigger : triggersOut) {
|
||||
_animVars.setTrigger(trigger);
|
||||
}
|
||||
|
||||
computeEyesInRootFrame(_relativePoses);
|
||||
computeEyesInRootFrame(_internalPoseSet._relativePoses);
|
||||
}
|
||||
|
||||
applyOverridePoses();
|
||||
buildAbsoluteRigPoses(_relativePoses, _absolutePoses);
|
||||
buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses);
|
||||
|
||||
// copy internal poses to external poses
|
||||
{
|
||||
QWriteLocker writeLock(&_externalPoseSetLock);
|
||||
_externalPoseSet = _internalPoseSet;
|
||||
}
|
||||
}
|
||||
|
||||
void Rig::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm::quat& targetRotation, float priority,
|
||||
|
@ -884,7 +894,7 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm
|
|||
if (isIndexValid(index)) {
|
||||
glm::mat4 rigToWorld = createMatFromQuatAndPos(modelRotation, modelTranslation);
|
||||
glm::mat4 worldToRig = glm::inverse(rigToWorld);
|
||||
glm::vec3 zAxis = glm::normalize(_absolutePoses[index].trans - transformPoint(worldToRig, lookAtSpot));
|
||||
glm::vec3 zAxis = glm::normalize(_internalPoseSet._absolutePoses[index].trans - transformPoint(worldToRig, lookAtSpot));
|
||||
glm::quat q = rotationBetween(IDENTITY_FRONT, zAxis);
|
||||
|
||||
// limit rotation
|
||||
|
@ -892,7 +902,7 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm
|
|||
q = glm::angleAxis(glm::clamp(glm::angle(q), -MAX_ANGLE, MAX_ANGLE), glm::axis(q));
|
||||
|
||||
// directly set absolutePose rotation
|
||||
_absolutePoses[index].rot = q;
|
||||
_internalPoseSet._absolutePoses[index].rot = q;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -989,13 +999,13 @@ void Rig::applyOverridePoses() {
|
|||
return;
|
||||
}
|
||||
|
||||
ASSERT(_animSkeleton->getNumJoints() == (int)_relativePoses.size());
|
||||
ASSERT(_animSkeleton->getNumJoints() == (int)_overrideFlags.size());
|
||||
ASSERT(_animSkeleton->getNumJoints() == (int)_overridePoses.size());
|
||||
ASSERT(_animSkeleton->getNumJoints() == (int)_internalPoseSet._relativePoses.size());
|
||||
ASSERT(_animSkeleton->getNumJoints() == (int)_internalPoseSet._overrideFlags.size());
|
||||
ASSERT(_animSkeleton->getNumJoints() == (int)_internalPoseSet._overridePoses.size());
|
||||
|
||||
for (size_t i = 0; i < _overrideFlags.size(); i++) {
|
||||
if (_overrideFlags[i]) {
|
||||
_relativePoses[i] = _overridePoses[i];
|
||||
for (size_t i = 0; i < _internalPoseSet._overrideFlags.size(); i++) {
|
||||
if (_internalPoseSet._overrideFlags[i]) {
|
||||
_internalPoseSet._relativePoses[i] = _internalPoseSet._overridePoses[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1020,14 +1030,14 @@ void Rig::buildAbsoluteRigPoses(const AnimPoseVec& relativePoses, AnimPoseVec& a
|
|||
|
||||
// transform all absolute poses into rig space.
|
||||
AnimPose geometryToRigTransform(_geometryToRigTransform);
|
||||
for (int i = 0; i < (int)_absolutePoses.size(); i++) {
|
||||
for (int i = 0; i < (int)absolutePosesOut.size(); i++) {
|
||||
absolutePosesOut[i] = geometryToRigTransform * absolutePosesOut[i];
|
||||
}
|
||||
}
|
||||
|
||||
glm::mat4 Rig::getJointTransform(int jointIndex) const {
|
||||
if (isIndexValid(jointIndex)) {
|
||||
return _absolutePoses[jointIndex];
|
||||
return _internalPoseSet._absolutePoses[jointIndex];
|
||||
} else {
|
||||
return glm::mat4();
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <QScriptValue>
|
||||
#include <vector>
|
||||
#include <JointData.h>
|
||||
#include <QReadWriteLock>
|
||||
|
||||
#include "AnimNode.h"
|
||||
#include "AnimNodeLoader.h"
|
||||
|
@ -27,6 +28,9 @@
|
|||
class Rig;
|
||||
typedef std::shared_ptr<Rig> RigPointer;
|
||||
|
||||
// Rig instances are reentrant.
|
||||
// However only specific methods thread-safe. Noted below.
|
||||
|
||||
class Rig : public QObject, public std::enable_shared_from_this<Rig> {
|
||||
public:
|
||||
struct StateHandler {
|
||||
|
@ -123,10 +127,10 @@ public:
|
|||
// if rotation is identity, result will be in rig space
|
||||
bool getJointRotationInWorldFrame(int jointIndex, glm::quat& result, const glm::quat& rotation) const;
|
||||
|
||||
// geometry space
|
||||
// geometry space (thread-safe)
|
||||
bool getJointRotation(int jointIndex, glm::quat& rotation) const;
|
||||
|
||||
// geometry space
|
||||
// geometry space (thread-safe)
|
||||
bool getJointTranslation(int jointIndex, glm::vec3& translation) const;
|
||||
|
||||
// legacy
|
||||
|
@ -217,10 +221,19 @@ public:
|
|||
AnimPose _modelOffset; // model to rig space
|
||||
AnimPose _geometryOffset; // geometry to model space (includes unit offset & fst offsets)
|
||||
|
||||
AnimPoseVec _relativePoses; // geometry space relative to parent.
|
||||
AnimPoseVec _absolutePoses; // rig space, not relative to parent.
|
||||
AnimPoseVec _overridePoses; // geometry space relative to parent.
|
||||
std::vector<bool> _overrideFlags;
|
||||
struct PoseSet {
|
||||
AnimPoseVec _relativePoses; // geometry space relative to parent.
|
||||
AnimPoseVec _absolutePoses; // rig space, not relative to parent.
|
||||
AnimPoseVec _overridePoses; // geometry space relative to parent.
|
||||
std::vector<bool> _overrideFlags;
|
||||
};
|
||||
|
||||
// Only accessed by the main thread
|
||||
PoseSet _internalPoseSet;
|
||||
|
||||
// Copy of the _poseSet for external threads.
|
||||
PoseSet _externalPoseSet;
|
||||
mutable QReadWriteLock _externalPoseSetLock;
|
||||
|
||||
AnimPoseVec _absoluteDefaultPoses; // rig space, not relative to parent.
|
||||
|
||||
|
|
|
@ -30,12 +30,11 @@ const QString& Basic2DWindowOpenGLDisplayPlugin::getName() const {
|
|||
return NAME;
|
||||
}
|
||||
|
||||
std::vector<QAction*> _framerateActions;
|
||||
QAction* _vsyncAction{ nullptr };
|
||||
|
||||
void Basic2DWindowOpenGLDisplayPlugin::activate() {
|
||||
WindowOpenGLDisplayPlugin::activate();
|
||||
|
||||
_framerateActions.clear();
|
||||
_container->addMenuItem(MENU_PATH(), FULLSCREEN,
|
||||
_container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), FULLSCREEN,
|
||||
[this](bool clicked) {
|
||||
if (clicked) {
|
||||
_container->setFullscreen(getFullscreenTarget());
|
||||
|
@ -45,26 +44,24 @@ void Basic2DWindowOpenGLDisplayPlugin::activate() {
|
|||
}, true, false);
|
||||
_container->addMenu(FRAMERATE);
|
||||
_framerateActions.push_back(
|
||||
_container->addMenuItem(FRAMERATE, FRAMERATE_UNLIMITED,
|
||||
_container->addMenuItem(PluginType::DISPLAY_PLUGIN, FRAMERATE, FRAMERATE_UNLIMITED,
|
||||
[this](bool) { updateFramerate(); }, true, true, FRAMERATE));
|
||||
_framerateActions.push_back(
|
||||
_container->addMenuItem(FRAMERATE, FRAMERATE_60,
|
||||
_container->addMenuItem(PluginType::DISPLAY_PLUGIN, FRAMERATE, FRAMERATE_60,
|
||||
[this](bool) { updateFramerate(); }, true, false, FRAMERATE));
|
||||
_framerateActions.push_back(
|
||||
_container->addMenuItem(FRAMERATE, FRAMERATE_50,
|
||||
_container->addMenuItem(PluginType::DISPLAY_PLUGIN, FRAMERATE, FRAMERATE_50,
|
||||
[this](bool) { updateFramerate(); }, true, false, FRAMERATE));
|
||||
_framerateActions.push_back(
|
||||
_container->addMenuItem(FRAMERATE, FRAMERATE_40,
|
||||
_container->addMenuItem(PluginType::DISPLAY_PLUGIN, FRAMERATE, FRAMERATE_40,
|
||||
[this](bool) { updateFramerate(); }, true, false, FRAMERATE));
|
||||
_framerateActions.push_back(
|
||||
_container->addMenuItem(FRAMERATE, FRAMERATE_30,
|
||||
_container->addMenuItem(PluginType::DISPLAY_PLUGIN, FRAMERATE, FRAMERATE_30,
|
||||
[this](bool) { updateFramerate(); }, true, false, FRAMERATE));
|
||||
|
||||
WindowOpenGLDisplayPlugin::activate();
|
||||
|
||||
// Vsync detection happens in the parent class activate, so we need to check after that
|
||||
if (_vsyncSupported) {
|
||||
_vsyncAction = _container->addMenuItem(MENU_PATH(), VSYNC_ON, [this](bool) {}, true, true);
|
||||
_vsyncAction = _container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), VSYNC_ON, [this](bool) {}, true, true);
|
||||
} else {
|
||||
_vsyncAction = nullptr;
|
||||
}
|
||||
|
@ -72,22 +69,20 @@ void Basic2DWindowOpenGLDisplayPlugin::activate() {
|
|||
updateFramerate();
|
||||
}
|
||||
|
||||
void Basic2DWindowOpenGLDisplayPlugin::deactivate() {
|
||||
WindowOpenGLDisplayPlugin::deactivate();
|
||||
}
|
||||
|
||||
void Basic2DWindowOpenGLDisplayPlugin::display(GLuint sceneTexture, const glm::uvec2& sceneSize) {
|
||||
void Basic2DWindowOpenGLDisplayPlugin::submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) {
|
||||
if (_vsyncAction) {
|
||||
bool wantVsync = _vsyncAction->isChecked();
|
||||
bool vsyncEnabed = isVsyncEnabled();
|
||||
if (vsyncEnabed ^ wantVsync) {
|
||||
enableVsync(wantVsync);
|
||||
}
|
||||
_wantVsync = _vsyncAction->isChecked();
|
||||
}
|
||||
|
||||
WindowOpenGLDisplayPlugin::display(sceneTexture, sceneSize);
|
||||
WindowOpenGLDisplayPlugin::submitSceneTexture(frameIndex, sceneTexture, sceneSize);
|
||||
}
|
||||
|
||||
void Basic2DWindowOpenGLDisplayPlugin::internalPresent() {
|
||||
if (_wantVsync != isVsyncEnabled()) {
|
||||
enableVsync(_wantVsync);
|
||||
}
|
||||
WindowOpenGLDisplayPlugin::internalPresent();
|
||||
}
|
||||
|
||||
int Basic2DWindowOpenGLDisplayPlugin::getDesiredInterval() const {
|
||||
static const int THROTTLED_PAINT_TIMER_DELAY_MS = MSECS_PER_SECOND / 15;
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include "WindowOpenGLDisplayPlugin.h"
|
||||
|
||||
class QScreen;
|
||||
class QAction;
|
||||
|
||||
class Basic2DWindowOpenGLDisplayPlugin : public WindowOpenGLDisplayPlugin {
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -17,9 +19,10 @@ public:
|
|||
virtual const QString & getName() const override;
|
||||
|
||||
virtual void activate() override;
|
||||
virtual void deactivate() override;
|
||||
|
||||
virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) override;
|
||||
virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override;
|
||||
|
||||
virtual void internalPresent() override;
|
||||
|
||||
virtual bool isThrottled() const override;
|
||||
|
||||
|
@ -31,6 +34,9 @@ private:
|
|||
void updateFramerate();
|
||||
static const QString NAME;
|
||||
QScreen* getFullscreenTarget();
|
||||
uint32_t _framerateTarget{ 0 };
|
||||
std::vector<QAction*> _framerateActions;
|
||||
QAction* _vsyncAction { nullptr };
|
||||
uint32_t _framerateTarget { 0 };
|
||||
int _fullscreenTarget{ -1 };
|
||||
bool _wantVsync { true };
|
||||
};
|
||||
|
|
|
@ -25,8 +25,8 @@ const QString& DisplayPlugin::MENU_PATH() {
|
|||
DisplayPluginList getDisplayPlugins() {
|
||||
DisplayPlugin* PLUGIN_POOL[] = {
|
||||
new Basic2DWindowOpenGLDisplayPlugin(),
|
||||
#ifdef DEBUG
|
||||
new NullDisplayPlugin(),
|
||||
#ifdef DEBUG
|
||||
#endif
|
||||
|
||||
// Stereo modes
|
||||
|
@ -37,10 +37,10 @@ DisplayPluginList getDisplayPlugins() {
|
|||
new InterleavedStereoDisplayPlugin(),
|
||||
|
||||
// HMDs
|
||||
#ifdef Q_OS_WIN
|
||||
// SteamVR SDK
|
||||
new OpenVrDisplayPlugin(),
|
||||
#endif
|
||||
//#ifdef Q_OS_WIN
|
||||
// // SteamVR SDK
|
||||
// new OpenVrDisplayPlugin(),
|
||||
//#endif
|
||||
nullptr
|
||||
};
|
||||
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
//
|
||||
#include "NullDisplayPlugin.h"
|
||||
|
||||
#include <QtGui/QImage>
|
||||
#include <plugins/PluginContainer.h>
|
||||
|
||||
const QString NullDisplayPlugin::NAME("NullDisplayPlugin");
|
||||
|
||||
const QString & NullDisplayPlugin::getName() const {
|
||||
|
@ -23,8 +26,16 @@ bool NullDisplayPlugin::hasFocus() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
void NullDisplayPlugin::preRender() {}
|
||||
void NullDisplayPlugin::preDisplay() {}
|
||||
void NullDisplayPlugin::display(uint32_t sceneTexture, const glm::uvec2& sceneSize) {}
|
||||
void NullDisplayPlugin::finishFrame() {}
|
||||
void NullDisplayPlugin::submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) {
|
||||
_container->releaseSceneTexture(sceneTexture);
|
||||
}
|
||||
|
||||
void NullDisplayPlugin::submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) {
|
||||
_container->releaseOverlayTexture(overlayTexture);
|
||||
}
|
||||
|
||||
void NullDisplayPlugin::stop() {}
|
||||
|
||||
QImage NullDisplayPlugin::getScreenshot() const {
|
||||
return QImage();
|
||||
}
|
||||
|
|
|
@ -19,11 +19,9 @@ public:
|
|||
|
||||
virtual glm::uvec2 getRecommendedRenderSize() const override;
|
||||
virtual bool hasFocus() const override;
|
||||
virtual void preRender() override;
|
||||
virtual void preDisplay() override;
|
||||
virtual void display(uint32_t sceneTexture, const glm::uvec2& sceneSize) override;
|
||||
virtual void finishFrame() override;
|
||||
|
||||
virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override;
|
||||
virtual void submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) override;
|
||||
virtual QImage getScreenshot() const override;
|
||||
private:
|
||||
static const QString NAME;
|
||||
};
|
||||
|
|
|
@ -6,74 +6,219 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "OpenGLDisplayPlugin.h"
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include <condition_variable>
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QTimer>
|
||||
|
||||
#include <QtOpenGL/QGLWidget>
|
||||
#include <QtGui/QOpenGLContext>
|
||||
#include <QtGui/QImage>
|
||||
|
||||
#include <gl/GLWidget.h>
|
||||
#include <NumericalConstants.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include <gl/Config.h>
|
||||
#include <gl/GLEscrow.h>
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
class PresentThread : public QThread, public Dependency {
|
||||
using Mutex = std::mutex;
|
||||
using Condition = std::condition_variable;
|
||||
using Lock = std::unique_lock<Mutex>;
|
||||
public:
|
||||
|
||||
~PresentThread() {
|
||||
_shutdown = true;
|
||||
wait();
|
||||
}
|
||||
|
||||
void setNewDisplayPlugin(OpenGLDisplayPlugin* plugin) {
|
||||
Lock lock(_mutex);
|
||||
_newPlugin = plugin;
|
||||
}
|
||||
|
||||
void setContext(QGLContext * context) {
|
||||
// Move the OpenGL context to the present thread
|
||||
// Extra code because of the widget 'wrapper' context
|
||||
_context = context;
|
||||
_context->moveToThread(this);
|
||||
_context->contextHandle()->moveToThread(this);
|
||||
}
|
||||
|
||||
virtual void run() override {
|
||||
Q_ASSERT(_context);
|
||||
while (!_shutdown) {
|
||||
if (_pendingMainThreadOperation) {
|
||||
{
|
||||
Lock lock(_mutex);
|
||||
// Move the context to the main thread
|
||||
_context->moveToThread(qApp->thread());
|
||||
_context->contextHandle()->moveToThread(qApp->thread());
|
||||
_pendingMainThreadOperation = false;
|
||||
// Release the main thread to do it's action
|
||||
_condition.notify_one();
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// Main thread does it's thing while we wait on the lock to release
|
||||
Lock lock(_mutex);
|
||||
_condition.wait(lock, [&] { return _finishedMainThreadOperation; });
|
||||
}
|
||||
}
|
||||
|
||||
// Check before lock
|
||||
if (_newPlugin != nullptr) {
|
||||
Lock lock(_mutex);
|
||||
_context->makeCurrent();
|
||||
// Check if we have a new plugin to activate
|
||||
if (_newPlugin != nullptr) {
|
||||
// Deactivate the old plugin
|
||||
if (_activePlugin != nullptr) {
|
||||
_activePlugin->uncustomizeContext();
|
||||
}
|
||||
|
||||
_newPlugin->customizeContext();
|
||||
_activePlugin = _newPlugin;
|
||||
_newPlugin = nullptr;
|
||||
}
|
||||
_context->doneCurrent();
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
// If there's no active plugin, just sleep
|
||||
if (_activePlugin == nullptr) {
|
||||
QThread::usleep(100);
|
||||
continue;
|
||||
}
|
||||
|
||||
// take the latest texture and present it
|
||||
_context->makeCurrent();
|
||||
_activePlugin->present();
|
||||
_context->doneCurrent();
|
||||
}
|
||||
|
||||
_context->doneCurrent();
|
||||
_context->moveToThread(qApp->thread());
|
||||
_context->contextHandle()->moveToThread(qApp->thread());
|
||||
}
|
||||
|
||||
void withMainThreadContext(std::function<void()> f) {
|
||||
// Signal to the thread that there is work to be done on the main thread
|
||||
Lock lock(_mutex);
|
||||
_pendingMainThreadOperation = true;
|
||||
_finishedMainThreadOperation = false;
|
||||
_condition.wait(lock, [&] { return !_pendingMainThreadOperation; });
|
||||
|
||||
_context->makeCurrent();
|
||||
f();
|
||||
_context->doneCurrent();
|
||||
|
||||
// Move the context back to the presentation thread
|
||||
_context->moveToThread(this);
|
||||
_context->contextHandle()->moveToThread(this);
|
||||
|
||||
// restore control of the context to the presentation thread and signal
|
||||
// the end of the operation
|
||||
_finishedMainThreadOperation = true;
|
||||
lock.unlock();
|
||||
_condition.notify_one();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
void makeCurrent();
|
||||
void doneCurrent();
|
||||
|
||||
bool _shutdown { false };
|
||||
Mutex _mutex;
|
||||
// Used to allow the main thread to perform context operations
|
||||
Condition _condition;
|
||||
bool _pendingMainThreadOperation { false };
|
||||
bool _finishedMainThreadOperation { false };
|
||||
QThread* _mainThread { nullptr };
|
||||
OpenGLDisplayPlugin* _newPlugin { nullptr };
|
||||
OpenGLDisplayPlugin* _activePlugin { nullptr };
|
||||
QGLContext* _context { nullptr };
|
||||
};
|
||||
|
||||
OpenGLDisplayPlugin::OpenGLDisplayPlugin() {
|
||||
_sceneTextureEscrow.setRecycler([this](GLuint texture){
|
||||
cleanupForSceneTexture(texture);
|
||||
_container->releaseSceneTexture(texture);
|
||||
});
|
||||
|
||||
_overlayTextureEscrow.setRecycler([this](GLuint texture) {
|
||||
_container->releaseOverlayTexture(texture);
|
||||
});
|
||||
|
||||
connect(&_timer, &QTimer::timeout, this, [&] {
|
||||
if (_active) {
|
||||
if (_active && _sceneTextureEscrow.depth() < 1) {
|
||||
emit requestRender();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
OpenGLDisplayPlugin::~OpenGLDisplayPlugin() {
|
||||
void OpenGLDisplayPlugin::cleanupForSceneTexture(uint32_t sceneTexture) {
|
||||
Lock lock(_mutex);
|
||||
Q_ASSERT(_sceneTextureToFrameIndexMap.contains(sceneTexture));
|
||||
_sceneTextureToFrameIndexMap.remove(sceneTexture);
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::preDisplay() {
|
||||
makeCurrent();
|
||||
};
|
||||
|
||||
void OpenGLDisplayPlugin::preRender() {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::finishFrame() {
|
||||
swapBuffers();
|
||||
doneCurrent();
|
||||
};
|
||||
|
||||
void OpenGLDisplayPlugin::customizeContext() {
|
||||
using namespace oglplus;
|
||||
// TODO: write the poper code for linux
|
||||
#if defined(Q_OS_WIN)
|
||||
_vsyncSupported = wglewGetExtension("WGL_EXT_swap_control");
|
||||
#endif
|
||||
|
||||
Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha);
|
||||
Context::Disable(Capability::Blend);
|
||||
Context::Disable(Capability::DepthTest);
|
||||
Context::Disable(Capability::CullFace);
|
||||
|
||||
|
||||
_program = loadDefaultShader();
|
||||
_plane = loadPlane(_program);
|
||||
|
||||
enableVsync();
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::activate() {
|
||||
DisplayPlugin::activate();
|
||||
_timer.start(1);
|
||||
_vsyncSupported = _container->getPrimaryWidget()->isVsyncSupported();
|
||||
|
||||
// Start the present thread if necessary
|
||||
auto presentThread = DependencyManager::get<PresentThread>();
|
||||
if (!presentThread) {
|
||||
auto widget = _container->getPrimaryWidget();
|
||||
|
||||
|
||||
DependencyManager::set<PresentThread>();
|
||||
presentThread = DependencyManager::get<PresentThread>();
|
||||
presentThread->setObjectName("Presentation Thread");
|
||||
presentThread->setContext(widget->context());
|
||||
// Start execution
|
||||
presentThread->start();
|
||||
}
|
||||
presentThread->setNewDisplayPlugin(this);
|
||||
DisplayPlugin::activate();
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::stop() {
|
||||
DisplayPlugin::activate();
|
||||
_timer.stop();
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::deactivate() {
|
||||
_active = false;
|
||||
_timer.stop();
|
||||
DisplayPlugin::deactivate();
|
||||
}
|
||||
|
||||
makeCurrent();
|
||||
Q_ASSERT(0 == glGetError());
|
||||
void OpenGLDisplayPlugin::customizeContext() {
|
||||
auto presentThread = DependencyManager::get<PresentThread>();
|
||||
Q_ASSERT(thread() == presentThread->thread());
|
||||
|
||||
enableVsync();
|
||||
|
||||
using namespace oglplus;
|
||||
Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha);
|
||||
Context::Disable(Capability::Blend);
|
||||
Context::Disable(Capability::DepthTest);
|
||||
Context::Disable(Capability::CullFace);
|
||||
|
||||
_program = loadDefaultShader();
|
||||
_plane = loadPlane(_program);
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::uncustomizeContext() {
|
||||
_program.reset();
|
||||
_plane.reset();
|
||||
doneCurrent();
|
||||
}
|
||||
|
||||
// Pressing Alt (and Meta) key alone activates the menubar because its style inherits the
|
||||
|
@ -118,13 +263,65 @@ bool OpenGLDisplayPlugin::eventFilter(QObject* receiver, QEvent* event) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::display(
|
||||
GLuint finalTexture, const glm::uvec2& sceneSize) {
|
||||
void OpenGLDisplayPlugin::submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) {
|
||||
{
|
||||
Lock lock(_mutex);
|
||||
_sceneTextureToFrameIndexMap[sceneTexture] = frameIndex;
|
||||
}
|
||||
|
||||
// Submit it to the presentation thread via escrow
|
||||
_sceneTextureEscrow.submit(sceneTexture);
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::submitOverlayTexture(GLuint sceneTexture, const glm::uvec2& sceneSize) {
|
||||
// Submit it to the presentation thread via escrow
|
||||
_overlayTextureEscrow.submit(sceneTexture);
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::updateTextures() {
|
||||
_currentSceneTexture = _sceneTextureEscrow.fetchAndRelease(_currentSceneTexture);
|
||||
_currentOverlayTexture = _overlayTextureEscrow.fetchAndRelease(_currentOverlayTexture);
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::updateFramerate() {
|
||||
uint64_t now = usecTimestampNow();
|
||||
static uint64_t lastSwapEnd { now };
|
||||
uint64_t diff = now - lastSwapEnd;
|
||||
lastSwapEnd = now;
|
||||
if (diff != 0) {
|
||||
Lock lock(_mutex);
|
||||
_usecsPerFrame.updateAverage(diff);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OpenGLDisplayPlugin::internalPresent() {
|
||||
using namespace oglplus;
|
||||
uvec2 size = getSurfaceSize();
|
||||
uvec2 size = getSurfacePixels();
|
||||
Context::Viewport(size.x, size.y);
|
||||
glBindTexture(GL_TEXTURE_2D, finalTexture);
|
||||
Context::Clear().DepthBuffer();
|
||||
glBindTexture(GL_TEXTURE_2D, _currentSceneTexture);
|
||||
drawUnitQuad();
|
||||
swapBuffers();
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::present() {
|
||||
updateTextures();
|
||||
if (_currentSceneTexture) {
|
||||
internalPresent();
|
||||
updateFramerate();
|
||||
}
|
||||
}
|
||||
|
||||
float OpenGLDisplayPlugin::presentRate() {
|
||||
float result { -1.0f };
|
||||
{
|
||||
Lock lock(_mutex);
|
||||
result = _usecsPerFrame.getAverage();
|
||||
result = 1.0f / result;
|
||||
result *= USECS_PER_SECOND;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::drawUnitQuad() {
|
||||
|
@ -151,3 +348,23 @@ bool OpenGLDisplayPlugin::isVsyncEnabled() {
|
|||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::swapBuffers() {
|
||||
static auto widget = _container->getPrimaryWidget();
|
||||
widget->swapBuffers();
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::withMainThreadContext(std::function<void()> f) const {
|
||||
static auto presentThread = DependencyManager::get<PresentThread>();
|
||||
presentThread->withMainThreadContext(f);
|
||||
_container->makeRenderingContextCurrent();
|
||||
}
|
||||
|
||||
QImage OpenGLDisplayPlugin::getScreenshot() const {
|
||||
QImage result;
|
||||
withMainThreadContext([&] {
|
||||
static auto widget = _container->getPrimaryWidget();
|
||||
result = widget->grabFrameBuffer();
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -9,42 +9,79 @@
|
|||
|
||||
#include "DisplayPlugin.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <gl/OglplusHelpers.h>
|
||||
#include <QtCore/QTimer>
|
||||
|
||||
class GlWindow;
|
||||
class QOpenGLContext;
|
||||
#include <GLMHelpers.h>
|
||||
#include <SimpleMovingAverage.h>
|
||||
#include <gl/OglplusHelpers.h>
|
||||
#include <gl/GLEscrow.h>
|
||||
|
||||
class OpenGLDisplayPlugin : public DisplayPlugin {
|
||||
protected:
|
||||
using Mutex = std::recursive_mutex;
|
||||
using Lock = std::unique_lock<Mutex>;
|
||||
public:
|
||||
OpenGLDisplayPlugin();
|
||||
virtual ~OpenGLDisplayPlugin();
|
||||
virtual void preRender() override;
|
||||
virtual void preDisplay() override;
|
||||
virtual void finishFrame() override;
|
||||
|
||||
virtual void activate() override;
|
||||
virtual void deactivate() override;
|
||||
virtual void stop() override;
|
||||
virtual bool eventFilter(QObject* receiver, QEvent* event) override;
|
||||
|
||||
virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) override;
|
||||
virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override;
|
||||
virtual void submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) override;
|
||||
virtual float presentRate() override;
|
||||
|
||||
virtual glm::uvec2 getRecommendedRenderSize() const override {
|
||||
return getSurfacePixels();
|
||||
}
|
||||
|
||||
virtual glm::uvec2 getRecommendedUiSize() const override {
|
||||
return getSurfaceSize();
|
||||
}
|
||||
|
||||
virtual QImage getScreenshot() const override;
|
||||
|
||||
protected:
|
||||
virtual void customizeContext();
|
||||
virtual void drawUnitQuad();
|
||||
virtual glm::uvec2 getSurfaceSize() const = 0;
|
||||
virtual void makeCurrent() = 0;
|
||||
virtual void doneCurrent() = 0;
|
||||
virtual void swapBuffers() = 0;
|
||||
friend class PresentThread;
|
||||
|
||||
|
||||
virtual glm::uvec2 getSurfaceSize() const = 0;
|
||||
virtual glm::uvec2 getSurfacePixels() const = 0;
|
||||
|
||||
// FIXME make thread safe?
|
||||
virtual bool isVsyncEnabled();
|
||||
virtual void enableVsync(bool enable = true);
|
||||
|
||||
// These functions must only be called on the presentation thread
|
||||
virtual void customizeContext();
|
||||
virtual void uncustomizeContext();
|
||||
virtual void cleanupForSceneTexture(uint32_t sceneTexture);
|
||||
void withMainThreadContext(std::function<void()> f) const;
|
||||
|
||||
|
||||
void present();
|
||||
void updateTextures();
|
||||
void updateFramerate();
|
||||
void drawUnitQuad();
|
||||
void swapBuffers();
|
||||
// Plugin specific functionality to composite the scene and overlay and present the result
|
||||
virtual void internalPresent();
|
||||
|
||||
mutable QTimer _timer;
|
||||
ProgramPtr _program;
|
||||
ShapeWrapperPtr _plane;
|
||||
bool _vsyncSupported{ false };
|
||||
|
||||
Mutex _mutex;
|
||||
SimpleMovingAverage _usecsPerFrame { 10 };
|
||||
QMap<uint32_t, uint32_t> _sceneTextureToFrameIndexMap;
|
||||
|
||||
GLuint _currentSceneTexture { 0 };
|
||||
GLuint _currentOverlayTexture { 0 };
|
||||
|
||||
GLTextureEscrow _overlayTextureEscrow;
|
||||
GLTextureEscrow _sceneTextureEscrow;
|
||||
|
||||
bool _vsyncSupported { false };
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -7,18 +7,11 @@
|
|||
//
|
||||
#include "WindowOpenGLDisplayPlugin.h"
|
||||
|
||||
#include <QGLWidget>
|
||||
#include <gl/GLWidget.h>
|
||||
|
||||
#include "plugins/PluginContainer.h"
|
||||
|
||||
WindowOpenGLDisplayPlugin::WindowOpenGLDisplayPlugin() {
|
||||
}
|
||||
|
||||
glm::uvec2 WindowOpenGLDisplayPlugin::getRecommendedRenderSize() const {
|
||||
return getSurfaceSize();
|
||||
}
|
||||
|
||||
glm::uvec2 WindowOpenGLDisplayPlugin::getSurfaceSize() const {
|
||||
glm::uvec2 WindowOpenGLDisplayPlugin::getSurfacePixels() const {
|
||||
uvec2 result;
|
||||
if (_window) {
|
||||
result = toGlm(_window->geometry().size() * _window->devicePixelRatio());
|
||||
|
@ -26,8 +19,7 @@ glm::uvec2 WindowOpenGLDisplayPlugin::getSurfaceSize() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
glm::uvec2 WindowOpenGLDisplayPlugin::getRecommendedUiSize() const {
|
||||
glm::uvec2 WindowOpenGLDisplayPlugin::getSurfaceSize() const {
|
||||
uvec2 result;
|
||||
if (_window) {
|
||||
result = toGlm(_window->geometry().size());
|
||||
|
@ -40,11 +32,8 @@ bool WindowOpenGLDisplayPlugin::hasFocus() const {
|
|||
}
|
||||
|
||||
void WindowOpenGLDisplayPlugin::activate() {
|
||||
_window = _container->getPrimaryWidget();
|
||||
OpenGLDisplayPlugin::activate();
|
||||
_window = _container->getPrimarySurface();
|
||||
_window->makeCurrent();
|
||||
customizeContext();
|
||||
_window->doneCurrent();
|
||||
}
|
||||
|
||||
void WindowOpenGLDisplayPlugin::deactivate() {
|
||||
|
@ -52,14 +41,3 @@ void WindowOpenGLDisplayPlugin::deactivate() {
|
|||
_window = nullptr;
|
||||
}
|
||||
|
||||
void WindowOpenGLDisplayPlugin::makeCurrent() {
|
||||
_window->makeCurrent();
|
||||
}
|
||||
|
||||
void WindowOpenGLDisplayPlugin::doneCurrent() {
|
||||
_window->doneCurrent();
|
||||
}
|
||||
|
||||
void WindowOpenGLDisplayPlugin::swapBuffers() {
|
||||
_window->swapBuffers();
|
||||
}
|
||||
|
|
|
@ -9,21 +9,17 @@
|
|||
|
||||
#include "OpenGLDisplayPlugin.h"
|
||||
|
||||
class QGLWidget;
|
||||
class QWidget;
|
||||
|
||||
class WindowOpenGLDisplayPlugin : public OpenGLDisplayPlugin {
|
||||
public:
|
||||
WindowOpenGLDisplayPlugin();
|
||||
virtual glm::uvec2 getRecommendedRenderSize() const override;
|
||||
virtual glm::uvec2 getRecommendedUiSize() const override;
|
||||
virtual bool hasFocus() const override;
|
||||
virtual void activate() override;
|
||||
virtual void deactivate() override;
|
||||
|
||||
protected:
|
||||
virtual glm::uvec2 getSurfaceSize() const override final;
|
||||
virtual void makeCurrent() override;
|
||||
virtual void doneCurrent() override;
|
||||
virtual void swapBuffers() override;
|
||||
QGLWidget* _window{ nullptr };
|
||||
virtual glm::uvec2 getSurfacePixels() const override final;
|
||||
|
||||
QWidget* _window { nullptr };
|
||||
};
|
||||
|
|
|
@ -152,7 +152,7 @@ glm::mat4 OpenVrDisplayPlugin::getEyeToHeadTransform(Eye eye) const {
|
|||
return _eyesData[eye]._eyeOffset;
|
||||
}
|
||||
|
||||
glm::mat4 OpenVrDisplayPlugin::getHeadPose() const {
|
||||
glm::mat4 OpenVrDisplayPlugin::getHeadPose(uint32_t frameIndex) const {
|
||||
return _trackedDevicePoseMat4[0];
|
||||
}
|
||||
|
||||
|
@ -160,26 +160,26 @@ void OpenVrDisplayPlugin::customizeContext() {
|
|||
WindowOpenGLDisplayPlugin::customizeContext();
|
||||
}
|
||||
|
||||
void OpenVrDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) {
|
||||
// Flip y-axis since GL UV coords are backwards.
|
||||
static vr::Compositor_TextureBounds leftBounds{ 0, 1, 0.5f, 0 };
|
||||
static vr::Compositor_TextureBounds rightBounds{ 0.5f, 1, 1, 0 };
|
||||
_compositor->Submit(vr::Eye_Left, (void*)finalTexture, &leftBounds);
|
||||
_compositor->Submit(vr::Eye_Right, (void*)finalTexture, &rightBounds);
|
||||
glFinish();
|
||||
}
|
||||
//void OpenVrDisplayPlugin::display(uint32_t frameIndex, uint32_t finalTexture, const glm::uvec2& sceneSize) {
|
||||
// // Flip y-axis since GL UV coords are backwards.
|
||||
// static vr::Compositor_TextureBounds leftBounds{ 0, 1, 0.5f, 0 };
|
||||
// static vr::Compositor_TextureBounds rightBounds{ 0.5f, 1, 1, 0 };
|
||||
// _compositor->Submit(vr::Eye_Left, (void*)finalTexture, &leftBounds);
|
||||
// _compositor->Submit(vr::Eye_Right, (void*)finalTexture, &rightBounds);
|
||||
// glFinish();
|
||||
//}
|
||||
|
||||
void OpenVrDisplayPlugin::finishFrame() {
|
||||
// swapBuffers();
|
||||
doneCurrent();
|
||||
_compositor->WaitGetPoses(_trackedDevicePose, vr::k_unMaxTrackedDeviceCount);
|
||||
for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) {
|
||||
_trackedDevicePoseMat4[i] = _sensorResetMat * toGlm(_trackedDevicePose[i].mDeviceToAbsoluteTracking);
|
||||
}
|
||||
openvr_for_each_eye([&](vr::Hmd_Eye eye) {
|
||||
_eyesData[eye]._pose = _trackedDevicePoseMat4[0];
|
||||
});
|
||||
};
|
||||
//void OpenVrDisplayPlugin::finishFrame() {
|
||||
//// swapBuffers();
|
||||
// doneCurrent();
|
||||
// _compositor->WaitGetPoses(_trackedDevicePose, vr::k_unMaxTrackedDeviceCount);
|
||||
// for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) {
|
||||
// _trackedDevicePoseMat4[i] = _sensorResetMat * toGlm(_trackedDevicePose[i].mDeviceToAbsoluteTracking);
|
||||
// }
|
||||
// openvr_for_each_eye([&](vr::Hmd_Eye eye) {
|
||||
// _eyesData[eye]._pose = _trackedDevicePoseMat4[0];
|
||||
// });
|
||||
//};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -31,13 +31,11 @@ public:
|
|||
virtual void resetSensors() override;
|
||||
|
||||
virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override;
|
||||
virtual glm::mat4 getHeadPose() const override;
|
||||
virtual glm::mat4 getHeadPose(uint32_t frameIndex) const override;
|
||||
|
||||
protected:
|
||||
virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override;
|
||||
// virtual void display(uint32_t frameIndex, uint32_t finalTexture, const glm::uvec2& sceneSize) override;
|
||||
virtual void customizeContext() override;
|
||||
// Do not perform swap in finish
|
||||
virtual void finishFrame() override;
|
||||
|
||||
private:
|
||||
vr::IVRSystem* _hmd { nullptr };
|
||||
|
|
|
@ -66,10 +66,10 @@ glm::uvec2 InterleavedStereoDisplayPlugin::getRecommendedRenderSize() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void InterleavedStereoDisplayPlugin::display(
|
||||
GLuint finalTexture, const glm::uvec2& sceneSize) {
|
||||
void InterleavedStereoDisplayPlugin::internalPresent() {
|
||||
using namespace oglplus;
|
||||
_program->Bind();
|
||||
auto sceneSize = getRecommendedRenderSize();
|
||||
Uniform<ivec2>(*_program, "textureSize").SetValue(sceneSize);
|
||||
WindowOpenGLDisplayPlugin::display(finalTexture, sceneSize);
|
||||
WindowOpenGLDisplayPlugin::internalPresent();
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ public:
|
|||
virtual void customizeContext() override;
|
||||
|
||||
virtual glm::uvec2 getRecommendedRenderSize() const override;
|
||||
void display(GLuint finalTexture, const glm::uvec2& sceneSize) override;
|
||||
void internalPresent() override;
|
||||
|
||||
private:
|
||||
static const QString NAME;
|
||||
|
|
|
@ -74,7 +74,7 @@ void StereoDisplayPlugin::activate() {
|
|||
if (screen == qApp->primaryScreen()) {
|
||||
checked = true;
|
||||
}
|
||||
auto action = _container->addMenuItem(MENU_PATH(), name,
|
||||
auto action = _container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), name,
|
||||
[this](bool clicked) { updateScreen(); }, true, checked, "Screens");
|
||||
_screenActions[i] = action;
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
using Mutex = std::mutex;
|
||||
using Mutex = std::recursive_mutex;
|
||||
using Lock = std::unique_lock<Mutex>;
|
||||
using Recycler = std::function<void(T t)>;
|
||||
// deque gives us random access, double ended push & pop and size, all in constant time
|
||||
|
@ -130,6 +130,21 @@ public:
|
|||
return result;
|
||||
}
|
||||
|
||||
// Returns the next available resource provided by the submitter,
|
||||
// or if none is available (which could mean either the submission
|
||||
// list is empty or that the first item on the list isn't yet signaled
|
||||
// Also releases any previous texture held by the caller
|
||||
T fetchAndRelease(T oldValue) {
|
||||
T result = fetch();
|
||||
if (!result) {
|
||||
return oldValue;
|
||||
}
|
||||
if (oldValue) {
|
||||
release(oldValue);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// If fetch returns a non-zero value, it's the responsibility of the
|
||||
// client to release it at some point
|
||||
void release(T t, GLsync readSync = 0) {
|
||||
|
@ -162,7 +177,12 @@ private:
|
|||
pop(_releases);
|
||||
}
|
||||
|
||||
trash.swap(_trash);
|
||||
{
|
||||
// FIXME I don't think this lock should be necessary, only the submitting thread
|
||||
// touches the trash
|
||||
Lock lock(_mutex);
|
||||
trash.swap(_trash);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME maybe doing a timing on the deleters and warn if it's taking excessive time?
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include <QtGlobal>
|
||||
|
||||
#include "GLWidget.h"
|
||||
|
||||
|
@ -16,11 +17,14 @@
|
|||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
#include <QtGui/QOpenGLContext>
|
||||
#include <QtGui/QKeyEvent>
|
||||
#include <QtGui/QWindow>
|
||||
|
||||
|
||||
#include "GLHelpers.h"
|
||||
|
||||
|
||||
GLWidget::GLWidget() : QGLWidget(getDefaultGLFormat()) {
|
||||
#ifdef Q_OS_LINUX
|
||||
// Cause GLWidget::eventFilter to be called.
|
||||
|
@ -42,6 +46,12 @@ void GLWidget::initializeGL() {
|
|||
setAcceptDrops(true);
|
||||
// Note, we *DO NOT* want Qt to automatically swap buffers for us. This results in the "ringing" bug mentioned in WL#19514 when we're throttling the framerate.
|
||||
setAutoBufferSwap(false);
|
||||
|
||||
// TODO: write the proper code for linux
|
||||
makeCurrent();
|
||||
#if defined(Q_OS_WIN)
|
||||
_vsyncSupported = context()->contextHandle()->hasExtension("WGL_EXT_swap_control");;
|
||||
#endif
|
||||
}
|
||||
|
||||
void GLWidget::paintEvent(QPaintEvent* event) {
|
||||
|
@ -112,3 +122,8 @@ bool GLWidget::eventFilter(QObject*, QEvent* event) {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GLWidget::isVsyncSupported() const {
|
||||
return _vsyncSupported;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,15 +21,19 @@ public:
|
|||
int getDeviceWidth() const;
|
||||
int getDeviceHeight() const;
|
||||
QSize getDeviceSize() const { return QSize(getDeviceWidth(), getDeviceHeight()); }
|
||||
bool isVsyncSupported() const;
|
||||
virtual void initializeGL() override;
|
||||
|
||||
protected:
|
||||
virtual void initializeGL() override;
|
||||
virtual bool event(QEvent* event) override;
|
||||
virtual void paintEvent(QPaintEvent* event) override;
|
||||
virtual void resizeEvent(QResizeEvent* event) override;
|
||||
|
||||
private slots:
|
||||
virtual bool eventFilter(QObject*, QEvent* event) override;
|
||||
|
||||
private:
|
||||
bool _vsyncSupported { false };
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ void SixenseManager::activate() {
|
|||
|
||||
#ifdef HAVE_SIXENSE
|
||||
_container->addMenu(MENU_PATH);
|
||||
_container->addMenuItem(MENU_PATH, TOGGLE_SMOOTH,
|
||||
_container->addMenuItem(PluginType::INPUT_PLUGIN, MENU_PATH, TOGGLE_SMOOTH,
|
||||
[this] (bool clicked) { setSixenseFilter(clicked); },
|
||||
true, true);
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ void ViveControllerManager::activate() {
|
|||
InputPlugin::activate();
|
||||
#ifdef Q_OS_WIN
|
||||
_container->addMenu(MENU_PATH);
|
||||
_container->addMenuItem(MENU_PATH, RENDER_CONTROLLERS,
|
||||
_container->addMenuItem(PluginType::INPUT_PLUGIN, MENU_PATH, RENDER_CONTROLLERS,
|
||||
[this] (bool clicked) { this->setRenderControllers(clicked); },
|
||||
true, true);
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ void DomainHandler::softReset() {
|
|||
clearSettings();
|
||||
|
||||
// cancel the failure timeout for any pending requests for settings
|
||||
QMetaObject::invokeMethod(&_settingsTimer, "stop", Qt::AutoConnection);
|
||||
QMetaObject::invokeMethod(&_settingsTimer, "stop");
|
||||
}
|
||||
|
||||
void DomainHandler::hardReset() {
|
||||
|
|
|
@ -436,17 +436,23 @@ SharedNodePointer LimitedNodeList::nodeWithUUID(const QUuid& nodeUUID) {
|
|||
}
|
||||
|
||||
void LimitedNodeList::eraseAllNodes() {
|
||||
qCDebug(networking) << "Clearing the NodeList. Deleting all nodes in list.";
|
||||
|
||||
QSet<SharedNodePointer> killedNodes;
|
||||
eachNode([&killedNodes](const SharedNodePointer& node){
|
||||
killedNodes.insert(node);
|
||||
});
|
||||
|
||||
{
|
||||
// iterate the current nodes, emit that they are dying and remove them from the hash
|
||||
// iterate the current nodes - grab them so we can emit that they are dying
|
||||
// and then remove them from the hash
|
||||
QWriteLocker writeLocker(&_nodeMutex);
|
||||
_nodeHash.clear();
|
||||
|
||||
if (_nodeHash.size() > 0) {
|
||||
qCDebug(networking) << "LimitedNodeList::eraseAllNodes() removing all nodes from NodeList.";
|
||||
|
||||
auto it = _nodeHash.begin();
|
||||
|
||||
while (it != _nodeHash.end()) {
|
||||
killedNodes.insert(it->second);
|
||||
it = _nodeHash.unsafe_erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach(const SharedNodePointer& killedNode, killedNodes) {
|
||||
|
|
|
@ -94,7 +94,7 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned
|
|||
_keepAlivePingTimer.setInterval(KEEPALIVE_PING_INTERVAL_MS);
|
||||
connect(&_keepAlivePingTimer, &QTimer::timeout, this, &NodeList::sendKeepAlivePings);
|
||||
connect(&_domainHandler, SIGNAL(connectedToDomain(QString)), &_keepAlivePingTimer, SLOT(start()));
|
||||
connect(&_domainHandler, &DomainHandler::disconnectedFromDomain, &_keepAlivePingTimer, &QTimer::stop);
|
||||
connect(&_domainHandler, &DomainHandler::disconnectedFromDomain, this, &NodeList::stopKeepalivePingTimer);
|
||||
|
||||
// we definitely want STUN to update our public socket, so call the LNL to kick that off
|
||||
startSTUNPublicSocketUpdate();
|
||||
|
@ -200,6 +200,11 @@ void NodeList::processICEPingPacket(QSharedPointer<ReceivedMessage> message) {
|
|||
}
|
||||
|
||||
void NodeList::reset() {
|
||||
if (thread() != QThread::currentThread()) {
|
||||
QMetaObject::invokeMethod(this, "reset", Qt::BlockingQueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
LimitedNodeList::reset();
|
||||
|
||||
_numNoReplyDomainCheckIns = 0;
|
||||
|
@ -641,6 +646,12 @@ void NodeList::activateSocketFromNodeCommunication(ReceivedMessage& message, con
|
|||
}
|
||||
}
|
||||
|
||||
void NodeList::stopKeepalivePingTimer() {
|
||||
if (_keepAlivePingTimer.isActive()) {
|
||||
_keepAlivePingTimer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
void NodeList::sendKeepAlivePings() {
|
||||
eachMatchingNode([this](const SharedNodePointer& node)->bool {
|
||||
return _nodeTypesOfInterest.contains(node->getType());
|
||||
|
|
|
@ -88,6 +88,7 @@ public slots:
|
|||
signals:
|
||||
void limitOfSilentDomainCheckInsReached();
|
||||
private slots:
|
||||
void stopKeepalivePingTimer();
|
||||
void sendPendingDSPathQuery();
|
||||
void handleICEConnectionToDomainServer();
|
||||
|
||||
|
|
|
@ -196,10 +196,12 @@ void Socket::clearConnections() {
|
|||
QMetaObject::invokeMethod(this, "clearConnections", Qt::BlockingQueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
// clear all of the current connections in the socket
|
||||
qDebug() << "Clearing all remaining connections in Socket.";
|
||||
_connectionsHash.clear();
|
||||
|
||||
if (_connectionsHash.size() > 0) {
|
||||
// clear all of the current connections in the socket
|
||||
qDebug() << "Clearing all remaining connections in Socket.";
|
||||
_connectionsHash.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Socket::cleanupConnection(HifiSockAddr sockAddr) {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <QtCore/QSize>
|
||||
#include <QtCore/QPoint>
|
||||
class QImage;
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
|
@ -65,29 +66,15 @@ public:
|
|||
// processing messages in the middle of submitFrame
|
||||
virtual void stop() = 0;
|
||||
|
||||
/**
|
||||
* Called by the application before the frame rendering. Can be used for
|
||||
* render timing related calls (for instance, the Oculus begin frame timing
|
||||
* call)
|
||||
*/
|
||||
virtual void preRender() = 0;
|
||||
/**
|
||||
* Called by the application immediately before calling the display function.
|
||||
* For OpenGL based plugins, this is the best place to put activate the output
|
||||
* OpenGL context
|
||||
*/
|
||||
virtual void preDisplay() = 0;
|
||||
|
||||
/**
|
||||
* Sends the scene texture to the display plugin.
|
||||
*/
|
||||
virtual void display(uint32_t sceneTexture, const glm::uvec2& sceneSize) = 0;
|
||||
virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) = 0;
|
||||
|
||||
/**
|
||||
* Called by the application immeidately after display. For OpenGL based
|
||||
* displays, this is the best place to put the buffer swap
|
||||
*/
|
||||
virtual void finishFrame() = 0;
|
||||
* Sends the scene texture to the display plugin.
|
||||
*/
|
||||
virtual void submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) = 0;
|
||||
|
||||
// Does the rendering surface have current focus?
|
||||
virtual bool hasFocus() const = 0;
|
||||
|
@ -110,18 +97,21 @@ public:
|
|||
return baseProjection;
|
||||
}
|
||||
|
||||
// Fetch the most recently displayed image as a QImage
|
||||
virtual QImage getScreenshot() const = 0;
|
||||
|
||||
// HMD specific methods
|
||||
// TODO move these into another class?
|
||||
virtual glm::mat4 getEyeToHeadTransform(Eye eye) const {
|
||||
static const glm::mat4 transform; return transform;
|
||||
}
|
||||
|
||||
virtual glm::mat4 getHeadPose() const {
|
||||
virtual glm::mat4 getHeadPose(uint32_t frameIndex) const {
|
||||
static const glm::mat4 pose; return pose;
|
||||
}
|
||||
|
||||
// Needed for timewarp style features
|
||||
virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) {
|
||||
virtual void setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
|
@ -129,8 +119,8 @@ public:
|
|||
|
||||
virtual void abandonCalibration() {}
|
||||
virtual void resetSensors() {}
|
||||
virtual float devicePixelRatio() { return 1.0; }
|
||||
|
||||
virtual float devicePixelRatio() { return 1.0f; }
|
||||
virtual float presentRate() { return -1.0f; }
|
||||
|
||||
static const QString& MENU_PATH();
|
||||
signals:
|
||||
|
|
|
@ -10,6 +10,11 @@
|
|||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
enum class PluginType {
|
||||
DISPLAY_PLUGIN,
|
||||
INPUT_PLUGIN,
|
||||
};
|
||||
|
||||
class DisplayPlugin;
|
||||
class InputPlugin;
|
||||
class Plugin;
|
||||
|
|
|
@ -8,11 +8,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <stdint.h>
|
||||
#include <QString>
|
||||
#include <QtCore/QVector>
|
||||
#include <QtCore/QPair>
|
||||
|
||||
#include "Forward.h"
|
||||
|
||||
class QAction;
|
||||
class QGLWidget;
|
||||
class GLWidget;
|
||||
class QScreen;
|
||||
class QOpenGLContext;
|
||||
class QWindow;
|
||||
|
||||
class DisplayPlugin;
|
||||
|
||||
class PluginContainer {
|
||||
|
@ -22,7 +30,7 @@ public:
|
|||
virtual ~PluginContainer();
|
||||
virtual void addMenu(const QString& menuName) = 0;
|
||||
virtual void removeMenu(const QString& menuName) = 0;
|
||||
virtual QAction* addMenuItem(const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") = 0;
|
||||
virtual QAction* addMenuItem(PluginType pluginType, const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") = 0;
|
||||
virtual void removeMenuItem(const QString& menuName, const QString& menuItem) = 0;
|
||||
virtual bool isOptionChecked(const QString& name) = 0;
|
||||
virtual void setIsOptionChecked(const QString& path, bool checked) = 0;
|
||||
|
@ -30,7 +38,25 @@ public:
|
|||
virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) = 0;
|
||||
virtual void showDisplayPluginsTools() = 0;
|
||||
virtual void requestReset() = 0;
|
||||
virtual QGLWidget* getPrimarySurface() = 0;
|
||||
virtual bool makeRenderingContextCurrent() = 0;
|
||||
virtual void releaseSceneTexture(uint32_t texture) = 0;
|
||||
virtual void releaseOverlayTexture(uint32_t texture) = 0;
|
||||
virtual GLWidget* getPrimaryWidget() = 0;
|
||||
virtual QWindow* getPrimaryWindow() = 0;
|
||||
virtual QOpenGLContext* getPrimaryContext() = 0;
|
||||
virtual bool isForeground() = 0;
|
||||
virtual const DisplayPlugin* getActiveDisplayPlugin() const = 0;
|
||||
|
||||
QVector<QPair<QString, QString>>& currentDisplayActions() {
|
||||
return _currentDisplayPluginActions;
|
||||
}
|
||||
|
||||
QVector<QPair<QString, QString>>& currentInputActions() {
|
||||
return _currentInputPluginActions;
|
||||
}
|
||||
|
||||
protected:
|
||||
QVector<QPair<QString, QString>> _currentDisplayPluginActions;
|
||||
QVector<QPair<QString, QString>> _currentInputPluginActions;
|
||||
|
||||
};
|
||||
|
|
40
libraries/render-utils/src/QOpenGLContextWrapper.cpp
Normal file
40
libraries/render-utils/src/QOpenGLContextWrapper.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// QOpenGLContextWrapper.cpp
|
||||
//
|
||||
//
|
||||
// Created by Clement on 12/4/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "QOpenGLContextWrapper.h"
|
||||
|
||||
#include <QOpenGLContext>
|
||||
|
||||
|
||||
QOpenGLContextWrapper::QOpenGLContextWrapper() :
|
||||
_context(new QOpenGLContext)
|
||||
{
|
||||
}
|
||||
|
||||
void QOpenGLContextWrapper::setFormat(const QSurfaceFormat& format) {
|
||||
_context->setFormat(format);
|
||||
}
|
||||
|
||||
bool QOpenGLContextWrapper::create() {
|
||||
return _context->create();
|
||||
}
|
||||
|
||||
void QOpenGLContextWrapper::swapBuffers(QSurface* surface) {
|
||||
_context->swapBuffers(surface);
|
||||
}
|
||||
|
||||
bool QOpenGLContextWrapper::makeCurrent(QSurface* surface) {
|
||||
return _context->makeCurrent(surface);
|
||||
}
|
||||
|
||||
void QOpenGLContextWrapper::doneCurrent() {
|
||||
_context->doneCurrent();
|
||||
}
|
33
libraries/render-utils/src/QOpenGLContextWrapper.h
Normal file
33
libraries/render-utils/src/QOpenGLContextWrapper.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// QOpenGLContextWrapper.h
|
||||
//
|
||||
//
|
||||
// Created by Clement on 12/4/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_QOpenGLContextWrapper_h
|
||||
#define hifi_QOpenGLContextWrapper_h
|
||||
|
||||
class QOpenGLContext;
|
||||
class QSurface;
|
||||
class QSurfaceFormat;
|
||||
|
||||
class QOpenGLContextWrapper {
|
||||
public:
|
||||
QOpenGLContextWrapper();
|
||||
|
||||
void setFormat(const QSurfaceFormat& format);
|
||||
bool create();
|
||||
void swapBuffers(QSurface* surface);
|
||||
bool makeCurrent(QSurface* surface);
|
||||
void doneCurrent();
|
||||
|
||||
private:
|
||||
QOpenGLContext* _context { nullptr };
|
||||
};
|
||||
|
||||
#endif // hifi_QOpenGLContextWrapper_h
|
24
libraries/render-utils/src/QOpenGLDebugLoggerWrapper.cpp
Normal file
24
libraries/render-utils/src/QOpenGLDebugLoggerWrapper.cpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// QOpenGLDebugLoggerWrapper.cpp
|
||||
//
|
||||
//
|
||||
// Created by Clement on 12/4/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "QOpenGLDebugLoggerWrapper.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QOpenGLDebugLogger>
|
||||
|
||||
void setupDebugLogger(QObject* window) {
|
||||
QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(window);
|
||||
logger->initialize(); // initializes in the current context, i.e. ctx
|
||||
logger->enableMessages();
|
||||
QObject::connect(logger, &QOpenGLDebugLogger::messageLogged, window, [&](const QOpenGLDebugMessage & debugMessage) {
|
||||
qDebug() << debugMessage;
|
||||
});
|
||||
}
|
19
libraries/render-utils/src/QOpenGLDebugLoggerWrapper.h
Normal file
19
libraries/render-utils/src/QOpenGLDebugLoggerWrapper.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// QOpenGLDebugLoggerWrapper.h
|
||||
//
|
||||
//
|
||||
// Created by Clement on 12/4/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_QOpenGLDebugLoggerWrapper_h
|
||||
#define hifi_QOpenGLDebugLoggerWrapper_h
|
||||
|
||||
class QObject;
|
||||
|
||||
void setupDebugLogger(QObject* window);
|
||||
|
||||
#endif // hifi_QOpenGLDebugLoggerWrapper_h
|
|
@ -62,6 +62,9 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const {
|
|||
|
||||
// we have a _parentID but no parent pointer, or our parent pointer was to the wrong thing
|
||||
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
|
||||
if (!parentFinder) {
|
||||
return nullptr;
|
||||
}
|
||||
_parent = parentFinder->find(_parentID);
|
||||
parent = _parent.lock();
|
||||
if (parent) {
|
||||
|
@ -98,12 +101,14 @@ void SpatiallyNestable::setParentID(const QUuid parentID) {
|
|||
|
||||
glm::vec3 SpatiallyNestable::worldToLocal(glm::vec3 position, QUuid parentID, int parentJointIndex) {
|
||||
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
|
||||
auto parentWP = parentFinder->find(parentID);
|
||||
auto parent = parentWP.lock();
|
||||
Transform parentTransform;
|
||||
if (parent) {
|
||||
parentTransform = parent->getTransform(parentJointIndex);
|
||||
parentTransform.setScale(1.0f);
|
||||
if (parentFinder) {
|
||||
auto parentWP = parentFinder->find(parentID);
|
||||
auto parent = parentWP.lock();
|
||||
if (parent) {
|
||||
parentTransform = parent->getTransform(parentJointIndex);
|
||||
parentTransform.setScale(1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
Transform positionTransform;
|
||||
|
@ -119,12 +124,14 @@ glm::vec3 SpatiallyNestable::worldToLocal(glm::vec3 position, QUuid parentID, in
|
|||
|
||||
glm::quat SpatiallyNestable::worldToLocal(glm::quat orientation, QUuid parentID, int parentJointIndex) {
|
||||
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
|
||||
auto parentWP = parentFinder->find(parentID);
|
||||
auto parent = parentWP.lock();
|
||||
Transform parentTransform;
|
||||
if (parent) {
|
||||
parentTransform = parent->getTransform(parentJointIndex);
|
||||
parentTransform.setScale(1.0f);
|
||||
if (parentFinder) {
|
||||
auto parentWP = parentFinder->find(parentID);
|
||||
auto parent = parentWP.lock();
|
||||
if (parent) {
|
||||
parentTransform = parent->getTransform(parentJointIndex);
|
||||
parentTransform.setScale(1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
Transform orientationTransform;
|
||||
|
@ -139,12 +146,14 @@ glm::quat SpatiallyNestable::worldToLocal(glm::quat orientation, QUuid parentID,
|
|||
|
||||
glm::vec3 SpatiallyNestable::localToWorld(glm::vec3 position, QUuid parentID, int parentJointIndex) {
|
||||
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
|
||||
auto parentWP = parentFinder->find(parentID);
|
||||
auto parent = parentWP.lock();
|
||||
Transform parentTransform;
|
||||
if (parent) {
|
||||
parentTransform = parent->getTransform(parentJointIndex);
|
||||
parentTransform.setScale(1.0f);
|
||||
if (parentFinder) {
|
||||
auto parentWP = parentFinder->find(parentID);
|
||||
auto parent = parentWP.lock();
|
||||
if (parent) {
|
||||
parentTransform = parent->getTransform(parentJointIndex);
|
||||
parentTransform.setScale(1.0f);
|
||||
}
|
||||
}
|
||||
Transform positionTransform;
|
||||
positionTransform.setTranslation(position);
|
||||
|
@ -155,12 +164,14 @@ glm::vec3 SpatiallyNestable::localToWorld(glm::vec3 position, QUuid parentID, in
|
|||
|
||||
glm::quat SpatiallyNestable::localToWorld(glm::quat orientation, QUuid parentID, int parentJointIndex) {
|
||||
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
|
||||
auto parentWP = parentFinder->find(parentID);
|
||||
auto parent = parentWP.lock();
|
||||
Transform parentTransform;
|
||||
if (parent) {
|
||||
parentTransform = parent->getTransform(parentJointIndex);
|
||||
parentTransform.setScale(1.0f);
|
||||
if (parentFinder) {
|
||||
auto parentWP = parentFinder->find(parentID);
|
||||
auto parent = parentWP.lock();
|
||||
if (parent) {
|
||||
parentTransform = parent->getTransform(parentJointIndex);
|
||||
parentTransform.setScale(1.0f);
|
||||
}
|
||||
}
|
||||
Transform orientationTransform;
|
||||
orientationTransform.setRotation(orientation);
|
||||
|
|
|
@ -15,13 +15,6 @@ uvec2 OculusBaseDisplayPlugin::getRecommendedRenderSize() const {
|
|||
return _desiredFramebufferSize;
|
||||
}
|
||||
|
||||
void OculusBaseDisplayPlugin::preRender() {
|
||||
#if (OVR_MAJOR_VERSION >= 6)
|
||||
ovrFrameTiming ftiming = ovr_GetFrameTiming(_hmd, _frameIndex);
|
||||
_trackingState = ovr_GetTrackingState(_hmd, ftiming.DisplayMidpointSeconds);
|
||||
#endif
|
||||
}
|
||||
|
||||
glm::mat4 OculusBaseDisplayPlugin::getProjection(Eye eye, const glm::mat4& baseProjection) const {
|
||||
return _eyeProjections[eye];
|
||||
}
|
||||
|
@ -29,7 +22,6 @@ glm::mat4 OculusBaseDisplayPlugin::getProjection(Eye eye, const glm::mat4& baseP
|
|||
void OculusBaseDisplayPlugin::resetSensors() {
|
||||
#if (OVR_MAJOR_VERSION >= 6)
|
||||
ovr_RecenterPose(_hmd);
|
||||
preRender();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -37,15 +29,14 @@ glm::mat4 OculusBaseDisplayPlugin::getEyeToHeadTransform(Eye eye) const {
|
|||
return glm::translate(mat4(), toGlm(_eyeOffsets[eye]));
|
||||
}
|
||||
|
||||
glm::mat4 OculusBaseDisplayPlugin::getHeadPose() const {
|
||||
return toGlm(_trackingState.HeadPose.ThePose);
|
||||
glm::mat4 OculusBaseDisplayPlugin::getHeadPose(uint32_t frameIndex) const {
|
||||
#if (OVR_MAJOR_VERSION >= 6)
|
||||
auto frameTiming = ovr_GetFrameTiming(_hmd, frameIndex);
|
||||
auto trackingState = ovr_GetTrackingState(_hmd, frameTiming.DisplayMidpointSeconds);
|
||||
return toGlm(trackingState.HeadPose.ThePose);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OculusBaseDisplayPlugin::setEyeRenderPose(Eye eye, const glm::mat4& pose) {
|
||||
_eyePoses[eye] = ovrPoseFromGlm(pose);
|
||||
}
|
||||
|
||||
|
||||
bool OculusBaseDisplayPlugin::isSupported() const {
|
||||
#if (OVR_MAJOR_VERSION >= 6)
|
||||
if (!OVR_SUCCESS(ovr_Initialize(nullptr))) {
|
||||
|
@ -77,6 +68,7 @@ void OculusBaseDisplayPlugin::deinit() {
|
|||
}
|
||||
|
||||
void OculusBaseDisplayPlugin::activate() {
|
||||
WindowOpenGLDisplayPlugin::activate();
|
||||
#if (OVR_MAJOR_VERSION >= 6)
|
||||
if (!OVR_SUCCESS(ovr_Initialize(nullptr))) {
|
||||
qFatal("Could not init OVR");
|
||||
|
@ -123,8 +115,6 @@ void OculusBaseDisplayPlugin::activate() {
|
|||
eyeSizes[0].x + eyeSizes[1].x,
|
||||
std::max(eyeSizes[0].y, eyeSizes[1].y));
|
||||
|
||||
_frameIndex = 0;
|
||||
|
||||
if (!OVR_SUCCESS(ovr_ConfigureTracking(_hmd,
|
||||
ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, 0))) {
|
||||
qFatal("Could not attach to sensor device");
|
||||
|
@ -145,8 +135,6 @@ void OculusBaseDisplayPlugin::activate() {
|
|||
qFatal("Could not attach to sensor device");
|
||||
}
|
||||
#endif
|
||||
|
||||
WindowOpenGLDisplayPlugin::activate();
|
||||
}
|
||||
|
||||
void OculusBaseDisplayPlugin::deactivate() {
|
||||
|
@ -159,9 +147,6 @@ void OculusBaseDisplayPlugin::deactivate() {
|
|||
#endif
|
||||
}
|
||||
|
||||
void OculusBaseDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) {
|
||||
++_frameIndex;
|
||||
}
|
||||
|
||||
float OculusBaseDisplayPlugin::getIPD() const {
|
||||
float result = OVR_DEFAULT_IPD;
|
||||
|
|
|
@ -30,24 +30,18 @@ public:
|
|||
virtual glm::uvec2 getRecommendedUiSize() const override final { return uvec2(1920, 1080); }
|
||||
virtual void resetSensors() override final;
|
||||
virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override final;
|
||||
virtual glm::mat4 getHeadPose() const override final;
|
||||
virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) override final;
|
||||
virtual float getIPD() const override final;
|
||||
virtual glm::mat4 getHeadPose(uint32_t frameIndex) const override;
|
||||
|
||||
protected:
|
||||
virtual void customizeContext() override;
|
||||
virtual void preRender() override final;
|
||||
virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override;
|
||||
|
||||
protected:
|
||||
ovrPosef _eyePoses[2];
|
||||
ovrVector3f _eyeOffsets[2];
|
||||
|
||||
mat4 _eyeProjections[3];
|
||||
mat4 _compositeEyeProjections[2];
|
||||
uvec2 _desiredFramebufferSize;
|
||||
ovrTrackingState _trackingState;
|
||||
unsigned int _frameIndex{ 0 };
|
||||
|
||||
#if (OVR_MAJOR_VERSION >= 6)
|
||||
ovrHmd _hmd;
|
||||
|
|
|
@ -28,13 +28,3 @@ void OculusDebugDisplayPlugin::customizeContext() {
|
|||
OculusBaseDisplayPlugin::customizeContext();
|
||||
enableVsync(false);
|
||||
}
|
||||
|
||||
void OculusDebugDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) {
|
||||
WindowOpenGLDisplayPlugin::display(finalTexture, sceneSize);
|
||||
OculusBaseDisplayPlugin::display(finalTexture, sceneSize);
|
||||
}
|
||||
|
||||
void OculusDebugDisplayPlugin::finishFrame() {
|
||||
swapBuffers();
|
||||
doneCurrent();
|
||||
};
|
||||
|
|
|
@ -15,10 +15,7 @@ public:
|
|||
virtual bool isSupported() const override;
|
||||
|
||||
protected:
|
||||
virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override;
|
||||
virtual void customizeContext() override;
|
||||
// Do not perform swap in finish
|
||||
virtual void finishFrame() override;
|
||||
|
||||
private:
|
||||
static const QString NAME;
|
||||
|
|
|
@ -144,8 +144,7 @@ static const QString MONO_PREVIEW = "Mono Preview";
|
|||
static const QString FRAMERATE = DisplayPlugin::MENU_PATH() + ">Framerate";
|
||||
|
||||
void OculusDisplayPlugin::activate() {
|
||||
|
||||
_container->addMenuItem(MENU_PATH(), MONO_PREVIEW,
|
||||
_container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), MONO_PREVIEW,
|
||||
[this](bool clicked) {
|
||||
_monoPreview = clicked;
|
||||
}, true, true);
|
||||
|
@ -170,18 +169,19 @@ void OculusDisplayPlugin::customizeContext() {
|
|||
_enablePreview = !isVsyncEnabled();
|
||||
}
|
||||
|
||||
void OculusDisplayPlugin::deactivate() {
|
||||
void OculusDisplayPlugin::uncustomizeContext() {
|
||||
#if (OVR_MAJOR_VERSION >= 6)
|
||||
makeCurrent();
|
||||
_sceneFbo.reset();
|
||||
doneCurrent();
|
||||
#endif
|
||||
|
||||
OculusBaseDisplayPlugin::deactivate();
|
||||
OculusBaseDisplayPlugin::uncustomizeContext();
|
||||
}
|
||||
|
||||
void OculusDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) {
|
||||
void OculusDisplayPlugin::internalPresent() {
|
||||
#if (OVR_MAJOR_VERSION >= 6)
|
||||
if (!_currentSceneTexture) {
|
||||
return;
|
||||
}
|
||||
|
||||
using namespace oglplus;
|
||||
// Need to make sure only the display plugin is responsible for
|
||||
// controlling vsync
|
||||
|
@ -196,7 +196,7 @@ void OculusDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSi
|
|||
} else {
|
||||
Context::Viewport(windowSize.x, windowSize.y);
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, finalTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, _currentSceneTexture);
|
||||
GLenum err = glGetError();
|
||||
Q_ASSERT(0 == err);
|
||||
drawUnitQuad();
|
||||
|
@ -205,16 +205,24 @@ void OculusDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSi
|
|||
_sceneFbo->Bound([&] {
|
||||
auto size = _sceneFbo->size;
|
||||
Context::Viewport(size.x, size.y);
|
||||
glBindTexture(GL_TEXTURE_2D, finalTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, _currentSceneTexture);
|
||||
GLenum err = glGetError();
|
||||
drawUnitQuad();
|
||||
});
|
||||
|
||||
ovr_for_each_eye([&](ovrEyeType eye) {
|
||||
_sceneLayer.RenderPose[eye] = _eyePoses[eye];
|
||||
});
|
||||
uint32_t frameIndex { 0 };
|
||||
EyePoses eyePoses;
|
||||
{
|
||||
Lock lock(_mutex);
|
||||
Q_ASSERT(_sceneTextureToFrameIndexMap.contains(_currentSceneTexture));
|
||||
frameIndex = _sceneTextureToFrameIndexMap[_currentSceneTexture];
|
||||
Q_ASSERT(_frameEyePoses.contains(frameIndex));
|
||||
eyePoses = _frameEyePoses[frameIndex];
|
||||
}
|
||||
|
||||
_sceneLayer.RenderPose[ovrEyeType::ovrEye_Left] = eyePoses.first;
|
||||
_sceneLayer.RenderPose[ovrEyeType::ovrEye_Right] = eyePoses.second;
|
||||
|
||||
auto windowSize = toGlm(_window->size());
|
||||
{
|
||||
ovrViewScaleDesc viewScaleDesc;
|
||||
viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f;
|
||||
|
@ -228,19 +236,26 @@ void OculusDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSi
|
|||
}
|
||||
}
|
||||
_sceneFbo->Increment();
|
||||
|
||||
++_frameIndex;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
The swapbuffer call here is only required if we want to mirror the content to the screen.
|
||||
However, it should only be done if we can reliably disable v-sync on the mirror surface,
|
||||
However, it should only be done if we can reliably disable v-sync on the mirror surface,
|
||||
otherwise the swapbuffer delay will interefere with the framerate of the headset
|
||||
*/
|
||||
void OculusDisplayPlugin::finishFrame() {
|
||||
*/
|
||||
if (_enablePreview) {
|
||||
swapBuffers();
|
||||
}
|
||||
doneCurrent();
|
||||
};
|
||||
}
|
||||
|
||||
void OculusDisplayPlugin::setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) {
|
||||
auto ovrPose = ovrPoseFromGlm(pose);
|
||||
{
|
||||
Lock lock(_mutex);
|
||||
if (eye == Eye::Left) {
|
||||
_frameEyePoses[frameIndex].first = ovrPose;
|
||||
} else {
|
||||
_frameEyePoses[frameIndex].second = ovrPose;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,22 +15,21 @@ using SwapFboPtr = QSharedPointer<SwapFramebufferWrapper>;
|
|||
class OculusDisplayPlugin : public OculusBaseDisplayPlugin {
|
||||
public:
|
||||
virtual void activate() override;
|
||||
virtual void deactivate() override;
|
||||
virtual const QString & getName() const override;
|
||||
virtual void setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) override final;
|
||||
|
||||
protected:
|
||||
virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override;
|
||||
virtual void internalPresent() override;
|
||||
virtual void customizeContext() override;
|
||||
// Do not perform swap in finish
|
||||
virtual void finishFrame() override;
|
||||
virtual void uncustomizeContext() override;
|
||||
|
||||
private:
|
||||
using EyePoses = std::pair<ovrPosef, ovrPosef>;
|
||||
static const QString NAME;
|
||||
bool _enablePreview { false };
|
||||
bool _monoPreview { true };
|
||||
QMap<uint32_t, EyePoses> _frameEyePoses;
|
||||
|
||||
#if (OVR_MAJOR_VERSION >= 6)
|
||||
SwapFboPtr _sceneFbo;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
namespace Oculus {
|
||||
ovrHmd _hmd;
|
||||
unsigned int _frameIndex{ 0 };
|
||||
ovrEyeRenderDesc _eyeRenderDescs[2];
|
||||
ovrPosef _eyePoses[2];
|
||||
ovrVector3f _eyeOffsets[2];
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
# See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
if (NOT WIN32)
|
||||
#if (NOT WIN32)
|
||||
if (FALSE)
|
||||
|
||||
set(TARGET_NAME oculusLegacy)
|
||||
setup_hifi_plugin()
|
||||
|
|
|
@ -46,7 +46,6 @@ private:
|
|||
static const QString NAME;
|
||||
|
||||
ovrHmd _hmd;
|
||||
unsigned int _frameIndex;
|
||||
ovrTrackingState _trackingState;
|
||||
ovrEyeRenderDesc _eyeRenderDescs[2];
|
||||
ovrPosef _eyePoses[2];
|
||||
|
|
|
@ -83,7 +83,7 @@ public:
|
|||
virtual ~PluginContainerProxy() {}
|
||||
virtual void addMenu(const QString& menuName) override {}
|
||||
virtual void removeMenu(const QString& menuName) override {}
|
||||
virtual QAction* addMenuItem(const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override { return nullptr; }
|
||||
virtual QAction* addMenuItem(PluginType type, const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override { return nullptr; }
|
||||
virtual void removeMenuItem(const QString& menuName, const QString& menuItem) override {}
|
||||
virtual bool isOptionChecked(const QString& name) override { return false; }
|
||||
virtual void setIsOptionChecked(const QString& path, bool checked) override {}
|
||||
|
@ -91,7 +91,12 @@ public:
|
|||
virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) override {}
|
||||
virtual void showDisplayPluginsTools() override {}
|
||||
virtual void requestReset() override {}
|
||||
virtual QGLWidget* getPrimarySurface() override { return nullptr; }
|
||||
virtual bool makeRenderingContextCurrent() override { return true; }
|
||||
virtual void releaseSceneTexture(uint32_t texture) override {}
|
||||
virtual void releaseOverlayTexture(uint32_t texture) override {}
|
||||
virtual GLWidget* getPrimaryWidget() override { return nullptr; }
|
||||
virtual QWindow* getPrimaryWindow() override { return nullptr; }
|
||||
virtual QOpenGLContext* getPrimaryContext() override { return nullptr; }
|
||||
virtual bool isForeground() override { return true; }
|
||||
virtual const DisplayPlugin* getActiveDisplayPlugin() const override { return nullptr; }
|
||||
};
|
||||
|
|
|
@ -33,9 +33,8 @@
|
|||
#include <gpu/StandardShaderLib.h>
|
||||
#include <gpu/GLBackend.h>
|
||||
|
||||
// Must come after GL headers
|
||||
#include <QtGui/QOpenGLContext>
|
||||
#include <QtGui/QOpenGLDebugLogger>
|
||||
#include <QOpenGLContextWrapper.h>
|
||||
#include <QOpenGLDebugLoggerWrapper.h>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
#include <PathUtils.h>
|
||||
|
@ -118,7 +117,7 @@ gpu::Stream::FormatPointer& getInstancedSolidStreamFormat();
|
|||
class QTestWindow : public QWindow {
|
||||
Q_OBJECT
|
||||
|
||||
QOpenGLContext* _qGlContext{ nullptr };
|
||||
QOpenGLContextWrapper _qGlContext;
|
||||
QSize _size;
|
||||
|
||||
gpu::ContextPointer _context;
|
||||
|
@ -151,19 +150,12 @@ public:
|
|||
|
||||
setFormat(format);
|
||||
|
||||
_qGlContext = new QOpenGLContext;
|
||||
_qGlContext->setFormat(format);
|
||||
_qGlContext->create();
|
||||
_qGlContext.setFormat(format);
|
||||
_qGlContext.create();
|
||||
|
||||
show();
|
||||
makeCurrent();
|
||||
QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(this);
|
||||
logger->initialize(); // initializes in the current context, i.e. ctx
|
||||
connect(logger, &QOpenGLDebugLogger::messageLogged, [](const QOpenGLDebugMessage& message){
|
||||
qDebug() << message;
|
||||
});
|
||||
logger->startLogging(QOpenGLDebugLogger::SynchronousLogging);
|
||||
|
||||
setupDebugLogger(this);
|
||||
|
||||
gpu::Context::init<gpu::GLBackend>();
|
||||
_context = std::make_shared<gpu::Context>();
|
||||
|
@ -371,7 +363,7 @@ public:
|
|||
geometryCache->renderWireCube(batch);
|
||||
|
||||
_context->render(batch);
|
||||
_qGlContext->swapBuffers(this);
|
||||
_qGlContext.swapBuffers(this);
|
||||
|
||||
fps.increment();
|
||||
if (fps.elapsed() >= 0.5f) {
|
||||
|
@ -381,7 +373,7 @@ public:
|
|||
}
|
||||
|
||||
void makeCurrent() {
|
||||
_qGlContext->makeCurrent(this);
|
||||
_qGlContext.makeCurrent(this);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
#include <gpu/GLBackend.h>
|
||||
|
||||
#include <QOpenGLContext>
|
||||
#include <QOpenGLDebugLogger>
|
||||
#include <QOpenGLContextWrapper.h>
|
||||
#include <QOpenGLDebugLoggerWrapper.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QElapsedTimer>
|
||||
|
@ -77,7 +77,7 @@ const QString& getQmlDir() {
|
|||
class QTestWindow : public QWindow {
|
||||
Q_OBJECT
|
||||
|
||||
QOpenGLContext* _context{ nullptr };
|
||||
QOpenGLContextWrapper _context;
|
||||
QSize _size;
|
||||
//TextRenderer* _textRenderer[4];
|
||||
RateCounter fps;
|
||||
|
@ -104,9 +104,8 @@ public:
|
|||
|
||||
setFormat(format);
|
||||
|
||||
_context = new QOpenGLContext;
|
||||
_context->setFormat(format);
|
||||
_context->create();
|
||||
_context.setFormat(format);
|
||||
_context.create();
|
||||
|
||||
show();
|
||||
makeCurrent();
|
||||
|
@ -114,15 +113,7 @@ public:
|
|||
gpu::Context::init<gpu::GLBackend>();
|
||||
|
||||
|
||||
{
|
||||
QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(this);
|
||||
logger->initialize(); // initializes in the current context, i.e. ctx
|
||||
logger->enableMessages();
|
||||
connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) {
|
||||
qDebug() << debugMessage;
|
||||
});
|
||||
// logger->startLogging(QOpenGLDebugLogger::SynchronousLogging);
|
||||
}
|
||||
setupDebugLogger(this);
|
||||
qDebug() << (const char*)glGetString(GL_VERSION);
|
||||
|
||||
//_textRenderer[0] = TextRenderer::getInstance(SANS_FONT_FAMILY, 12, false);
|
||||
|
@ -147,7 +138,7 @@ public:
|
|||
|
||||
void draw();
|
||||
void makeCurrent() {
|
||||
_context->makeCurrent(this);
|
||||
_context.makeCurrent(this);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -185,7 +176,7 @@ void QTestWindow::draw() {
|
|||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glViewport(0, 0, _size.width() * devicePixelRatio(), _size.height() * devicePixelRatio());
|
||||
|
||||
_context->swapBuffers(this);
|
||||
_context.swapBuffers(this);
|
||||
glFinish();
|
||||
|
||||
fps.increment();
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
|
||||
#include <gpu/GLBackend.h>
|
||||
|
||||
#include <QOpenGLDebugLogger>
|
||||
|
||||
#include <QLoggingCategory>
|
||||
#include <QResizeEvent>
|
||||
#include <QTimer>
|
||||
|
@ -22,6 +20,9 @@
|
|||
|
||||
#include <gl/GLHelpers.h>
|
||||
|
||||
#include <QOpenGLDebugLoggerWrapper.h>
|
||||
#include <QOpenGLContextWrapper.h>
|
||||
|
||||
#include "../model/Skybox_vert.h"
|
||||
#include "../model/Skybox_frag.h"
|
||||
|
||||
|
@ -120,7 +121,7 @@
|
|||
// Create a simple OpenGL window that renders text in various ways
|
||||
class QTestWindow : public QWindow {
|
||||
Q_OBJECT
|
||||
QOpenGLContext* _context{ nullptr };
|
||||
QOpenGLContextWrapper _context;
|
||||
|
||||
protected:
|
||||
void renderText();
|
||||
|
@ -130,22 +131,14 @@ public:
|
|||
setSurfaceType(QSurface::OpenGLSurface);
|
||||
QSurfaceFormat format = getDefaultOpenGLSurfaceFormat();
|
||||
setFormat(format);
|
||||
_context = new QOpenGLContext;
|
||||
_context->setFormat(format);
|
||||
_context->create();
|
||||
_context.setFormat(format);
|
||||
_context.create();
|
||||
|
||||
show();
|
||||
makeCurrent();
|
||||
|
||||
gpu::Context::init<gpu::GLBackend>();
|
||||
{
|
||||
QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(this);
|
||||
logger->initialize(); // initializes in the current context, i.e. ctx
|
||||
logger->enableMessages();
|
||||
connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) {
|
||||
qDebug() << debugMessage;
|
||||
});
|
||||
}
|
||||
setupDebugLogger(this);
|
||||
makeCurrent();
|
||||
resize(QSize(800, 600));
|
||||
}
|
||||
|
@ -155,7 +148,7 @@ public:
|
|||
|
||||
void draw();
|
||||
void makeCurrent() {
|
||||
_context->makeCurrent(this);
|
||||
_context.makeCurrent(this);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -248,7 +241,7 @@ void QTestWindow::draw() {
|
|||
testShaderBuild(polyvox_vert, polyvox_frag);
|
||||
|
||||
});
|
||||
_context->swapBuffers(this);
|
||||
_context.swapBuffers(this);
|
||||
}
|
||||
|
||||
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
||||
|
|
|
@ -1367,7 +1367,11 @@
|
|||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true
|
||||
},
|
||||
grabbableKey: {
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
|
||||
})
|
||||
});
|
||||
|
||||
|
|
|
@ -1347,6 +1347,9 @@ MasterReset = function() {
|
|||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true
|
||||
},
|
||||
grabbableKey: {
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
})
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue