Merge branch 'master' of https://github.com/highfidelity/hifi into proto-received-message

This commit is contained in:
Ryan Huffman 2015-12-07 08:58:47 -08:00
commit 34138f07bd
74 changed files with 2419 additions and 550 deletions

View file

@ -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();
}

View file

@ -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;

View file

@ -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,

View 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);
}

View file

@ -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

View file

@ -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);

File diff suppressed because it is too large Load diff

View file

@ -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;

View file

@ -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();
}

View file

@ -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;

View file

@ -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;

View file

@ -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;
};

View file

@ -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);

View file

@ -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";

View file

@ -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
}

View file

@ -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

View file

@ -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;

View file

@ -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();

View file

@ -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..

View file

@ -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.

View file

@ -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);

View file

@ -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());

View file

@ -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());

View file

@ -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();

View file

@ -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()

View file

@ -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();
}

View file

@ -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.

View file

@ -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;

View file

@ -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 };
};

View file

@ -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
};

View file

@ -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();
}

View file

@ -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;
};

View file

@ -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;
}

View file

@ -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 };
};

View file

@ -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();
}

View file

@ -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 };
};

View file

@ -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

View file

@ -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 };

View file

@ -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();
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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?

View file

@ -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;
}

View file

@ -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 };
};

View file

@ -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);

View file

@ -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);

View file

@ -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() {

View file

@ -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) {

View file

@ -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());

View file

@ -88,6 +88,7 @@ public slots:
signals:
void limitOfSilentDomainCheckInsReached();
private slots:
void stopKeepalivePingTimer();
void sendPendingDSPathQuery();
void handleICEConnectionToDomainServer();

View file

@ -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) {

View file

@ -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:

View file

@ -10,6 +10,11 @@
#include <vector>
#include <memory>
enum class PluginType {
DISPLAY_PLUGIN,
INPUT_PLUGIN,
};
class DisplayPlugin;
class InputPlugin;
class Plugin;

View file

@ -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;
};

View 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();
}

View 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

View 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;
});
}

View 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

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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();
};

View file

@ -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;

View file

@ -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;
}
}
}

View file

@ -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
};

View file

@ -11,7 +11,6 @@
namespace Oculus {
ovrHmd _hmd;
unsigned int _frameIndex{ 0 };
ovrEyeRenderDesc _eyeRenderDescs[2];
ovrPosef _eyePoses[2];
ovrVector3f _eyeOffsets[2];

View file

@ -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()

View file

@ -46,7 +46,6 @@ private:
static const QString NAME;
ovrHmd _hmd;
unsigned int _frameIndex;
ovrTrackingState _trackingState;
ovrEyeRenderDesc _eyeRenderDescs[2];
ovrPosef _eyePoses[2];

View file

@ -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; }
};

View file

@ -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:

View file

@ -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();

View file

@ -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) {

View file

@ -1367,7 +1367,11 @@
userData: JSON.stringify({
resetMe: {
resetMe: true
},
grabbableKey: {
invertSolidWhileHeld: true
}
})
});

View file

@ -1347,6 +1347,9 @@ MasterReset = function() {
userData: JSON.stringify({
resetMe: {
resetMe: true
},
grabbableKey: {
invertSolidWhileHeld: true
}
})
});