3
0
Fork 0
mirror of https://github.com/lubosz/overte.git synced 2025-04-15 08:26:47 +02:00

Merge branch 'master' of https://github.com/highfidelity/hifi into correct-target-frame-rate

This commit is contained in:
Howard Stearns 2015-12-04 16:12:22 -08:00
commit fa0ad1fe4d
216 changed files with 2819 additions and 2542 deletions
assignment-client/src
cmake
examples
interface
libraries

View file

@ -157,7 +157,7 @@ void AvatarMixer::broadcastAvatarData() {
++_sumListeners;
AvatarData& avatar = nodeData->getAvatar();
glm::vec3 myPosition = avatar.getPosition();
glm::vec3 myPosition = avatar.getClientGlobalPosition();
// reset the internal state for correct random number distribution
distribution.reset();
@ -290,7 +290,7 @@ void AvatarMixer::broadcastAvatarData() {
// The full rate distance is the distance at which EVERY update will be sent for this avatar
// at twice the full rate distance, there will be a 50% chance of sending this avatar's update
glm::vec3 otherPosition = otherAvatar.getPosition();
glm::vec3 otherPosition = otherAvatar.getClientGlobalPosition();
float distanceToAvatar = glm::length(myPosition - otherPosition);
// potentially update the max full rate distance for this frame

View file

@ -0,0 +1,19 @@
//
// AssignmentParentFinder.cpp
// assignment-client/src/entities
//
// Created by Seth Alves on 2015-10-22
// 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 "AssignmentParentFinder.h"
SpatiallyNestableWeakPointer AssignmentParentFinder::find(QUuid parentID) const {
SpatiallyNestableWeakPointer parent;
// search entities
parent = _tree->findEntityByEntityItemID(parentID);
return parent;
}

View file

@ -0,0 +1,34 @@
//
// AssignmentParentFinder.h
// interface/src/entities
//
// Created by Seth Alves on 2015-10-21
// 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_AssignmentParentFinder_h
#define hifi_AssignmentParentFinder_h
#include <memory>
#include <QUuid>
#include <EntityTree.h>
#include <SpatialParentFinder.h>
// This interface is used to turn a QUuid into a pointer to a "parent" -- something that children can
// be spatially relative to. At this point, this means either an EntityItem or an Avatar.
class AssignmentParentFinder : public SpatialParentFinder {
public:
AssignmentParentFinder(EntityTreePointer tree) : _tree(tree) { }
virtual ~AssignmentParentFinder() { }
virtual SpatiallyNestableWeakPointer find(QUuid parentID) const;
protected:
EntityTreePointer _tree;
};
#endif // hifi_AssignmentParentFinder_h

View file

@ -16,6 +16,7 @@
#include "EntityServer.h"
#include "EntityServerConsts.h"
#include "EntityNodeData.h"
#include "AssignmentParentFinder.h"
const char* MODEL_SERVER_NAME = "Entity";
const char* MODEL_SERVER_LOGGING_TARGET_NAME = "entity-server";
@ -60,6 +61,10 @@ OctreePointer EntityServer::createTree() {
tree->setSimulation(simpleSimulation);
_entitySimulation = simpleSimulation;
}
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
DependencyManager::set<AssignmentParentFinder>(tree);
return tree;
}

View file

@ -50,10 +50,10 @@ public:
virtual void entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode) override;
virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject) override;
virtual QString serverSubclassStats();
virtual QString serverSubclassStats() override;
virtual void trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode);
virtual void trackViewerGone(const QUuid& viewerNode);
virtual void trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode) override;
virtual void trackViewerGone(const QUuid& viewerNode) override;
public slots:
void pruneDeletedEntities();

View file

@ -179,9 +179,14 @@ void OctreeQueryNode::resetOctreePacket() {
// If we're moving, and the client asked for low res, then we force monochrome, otherwise, use
// the clients requested color state.
_currentPacketIsCompressed = getWantCompression();
OCTREE_PACKET_FLAGS flags = 0;
setAtBit(flags, PACKET_IS_COLOR_BIT);
setAtBit(flags, PACKET_IS_COMPRESSED_BIT);
if (_currentPacketIsColor) {
setAtBit(flags, PACKET_IS_COLOR_BIT);
}
if (_currentPacketIsCompressed) {
setAtBit(flags, PACKET_IS_COMPRESSED_BIT);
}
_octreePacket->reset();

View file

@ -77,7 +77,9 @@ public:
bool getCurrentPacketIsColor() const { return _currentPacketIsColor; }
bool getCurrentPacketIsCompressed() const { return _currentPacketIsCompressed; }
bool getCurrentPacketFormatMatches() { return (getCurrentPacketIsCompressed() == true); } // FIXME
bool getCurrentPacketFormatMatches() {
return (getCurrentPacketIsCompressed() == getWantCompression());
}
bool hasLodChanged() const { return _lodChanged; }

View file

@ -321,6 +321,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus
// If we're starting a fresh packet, then...
// If we're moving, and the client asked for low res, then we force monochrome, otherwise, use
// the clients requested color state.
bool wantCompression = nodeData->getWantCompression();
// If we have a packet waiting, and our desired want color, doesn't match the current waiting packets color
// then let's just send that waiting packet.
@ -331,8 +332,10 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus
nodeData->resetOctreePacket();
}
int targetSize = MAX_OCTREE_PACKET_DATA_SIZE;
targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE);
_packetData.changeSettings(targetSize);
if (wantCompression) {
targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE);
}
_packetData.changeSettings(wantCompression, targetSize);
}
const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL;
@ -548,7 +551,10 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus
packetsSentThisInterval += handlePacketSend(nodeData, trueBytesSent, truePacketsSent);
quint64 packetSendingEnd = usecTimestampNow();
packetSendingElapsedUsec = (float)(packetSendingEnd - packetSendingStart);
targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE);
if (wantCompression) {
targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE);
}
} else {
// If we're in compressed mode, then we want to see if we have room for more in this wire packet.
// but we've finalized the _packetData, so we want to start a new section, we will do that by
@ -558,7 +564,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus
// a larger compressed size then uncompressed size
targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE) - COMPRESS_PADDING;
}
_packetData.changeSettings(targetSize); // will do reset
_packetData.changeSettings(nodeData->getWantCompression(), targetSize); // will do reset
}
OctreeServer::trackTreeWaitTime(lockWaitElapsedUsec);

View file

@ -1,31 +0,0 @@
set(EXTERNAL_NAME gverb)
if (ANDROID)
set(ANDROID_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19")
endif ()
include(ExternalProject)
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://hifi-public.s3.amazonaws.com/dependencies/gverb-master.zip
URL_MD5 8b16d586390a2102804e46b87820dfc6
CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
LOG_DOWNLOAD 1
LOG_CONFIGURE 1
LOG_BUILD 1
)
# Hide this external target (for ide users)
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE FILEPATH "Path to gverb include directory")
if (WIN32)
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/gverb.lib CACHE FILEPATH "List of gverb libraries")
else ()
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/libgverb.a CACHE FILEPATH "List of gverb libraries")
endif ()

View file

@ -18,10 +18,16 @@ hifi_library_search_hints("leapmotion")
find_path(LEAPMOTION_INCLUDE_DIRS Leap.h PATH_SUFFIXES include HINTS ${LEAPMOTION_SEARCH_DIRS})
if (WIN32)
find_library(LEAPMOTION_LIBRARY_DEBUG Leapd PATH_SUFFIXES lib/x86 HINTS ${LEAPMOTION_SEARCH_DIRS})
find_library(LEAPMOTION_LIBRARY_RELEASE Leap PATH_SUFFIXES lib/x86 HINTS ${LEAPMOTION_SEARCH_DIRS})
find_path(LEAPMOTION_DLL_PATH Leap.dll PATH_SUFFIXES lib/x86 HINTS ${LEAPMOTION_SEARCH_DIRS})
if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
set(ARCH_DIR "x64")
else()
set(ARCH_DIR "x86")
endif()
find_library(LEAPMOTION_LIBRARY_DEBUG Leapd PATH_SUFFIXES "lib/${ARCH_DIR}" HINTS ${LEAPMOTION_SEARCH_DIRS})
find_library(LEAPMOTION_LIBRARY_RELEASE Leap PATH_SUFFIXES "lib/${ARCH_DIR}" HINTS ${LEAPMOTION_SEARCH_DIRS})
find_path(LEAPMOTION_DLL_PATH Leap.dll PATH_SUFFIXES "lib/${ARCH_DIR}" HINTS ${LEAPMOTION_SEARCH_DIRS})
elseif (APPLE)
find_library(LEAPMOTION_LIBRARY_RELEASE Leap PATH_SUFFIXES lib HINTS ${LEAPMOTION_SEARCH_DIRS})
endif ()

View file

@ -1,33 +0,0 @@
# Try to find the RSSDK library
#
# You must provide a RSSDK_ROOT_DIR which contains lib and include directories
#
# Once done this will define
#
# RSSDK_FOUND - system found RSSDK
# RSSDK_INCLUDE_DIRS - the RSSDK include directory
# RSSDK_LIBRARIES - Link this to use RSSDK
#
# Created on 12/7/2014 by Thijs Wenker
# Copyright (c) 2014 High Fidelity
#
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("rssdk")
find_path(RSSDK_INCLUDE_DIRS pxcbase.h PATH_SUFFIXES include HINTS ${RSSDK_SEARCH_DIRS})
if (WIN32)
find_library(RSSDK_LIBRARY_DEBUG libpxc_d PATH_SUFFIXES lib/Win32 HINTS ${RSSDK_SEARCH_DIRS})
find_library(RSSDK_LIBRARY_RELEASE libpxc PATH_SUFFIXES lib/Win32 HINTS ${RSSDK_SEARCH_DIRS})
endif ()
include(SelectLibraryConfigurations)
select_library_configurations(RSSDK)
set(RSSDK_LIBRARIES "${RSSDK_LIBRARY}")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(RSSDK DEFAULT_MSG RSSDK_INCLUDE_DIRS RSSDK_LIBRARIES)
mark_as_advanced(RSSDK_INCLUDE_DIRS RSSDK_LIBRARIES RSSDK_SEARCH_DIRS)

View file

@ -1,30 +0,0 @@
#
# FindRtMidi.cmake
#
# Try to find the RtMidi library
#
# You can provide a RTMIDI_ROOT_DIR which contains lib and include directories
#
# Once done this will define
#
# RTMIDI_FOUND - system found RtMidi
# RTMIDI_INCLUDE_DIRS - the RtMidi include directory
# RTMIDI_LIBRARIES - link to this to use RtMidi
#
# Created on 6/30/2014 by Stephen Birarda
# Copyright 2014 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("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("rtmidi")
find_path(RTMIDI_INCLUDE_DIRS RtMidi.h PATH_SUFFIXES include HINTS ${RTMIDI_SEARCH_DIRS})
find_library(RTMIDI_LIBRARIES NAMES rtmidi PATH_SUFFIXES lib HINTS ${RTMIDI_SEARCH_DIRS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(RtMidi DEFAULT_MSG RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES)
mark_as_advanced(RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES RTMIDI_SEARCH_DIRS)

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

@ -223,7 +223,9 @@
var elDimensionsZ = document.getElementById("property-dim-z");
var elResetToNaturalDimensions = document.getElementById("reset-to-natural-dimensions");
var elRescaleDimensionsPct = document.getElementById("dimension-rescale-pct");
var elRescaleDimensionsButton = document.getElementById("dimension-rescale-button");
var elRescaleDimensionsButton = document.getElementById("dimension-rescale-button");
var elParentID = document.getElementById("property-parent-id");
var elRegistrationX = document.getElementById("property-reg-x");
var elRegistrationY = document.getElementById("property-reg-y");
@ -453,6 +455,8 @@
elDimensionsY.value = properties.dimensions.y.toFixed(2);
elDimensionsZ.value = properties.dimensions.z.toFixed(2);
elParentID.value = properties.parentID;
elRegistrationX.value = properties.registrationPoint.x.toFixed(2);
elRegistrationY.value = properties.registrationPoint.y.toFixed(2);
elRegistrationZ.value = properties.registrationPoint.z.toFixed(2);
@ -666,6 +670,8 @@
elDimensionsY.addEventListener('change', dimensionsChangeFunction);
elDimensionsZ.addEventListener('change', dimensionsChangeFunction);
elParentID.addEventListener('change', createEmitTextPropertyUpdateFunction('parentID'));
var registrationChangeFunction = createEmitVec3PropertyUpdateFunction(
'registrationPoint', elRegistrationX, elRegistrationY, elRegistrationZ);
elRegistrationX.addEventListener('change', registrationChangeFunction);
@ -1055,6 +1061,13 @@
</div>
</div>
<div class="property">
<span class="label" style="float: left; margin-right: 6px">ParentID</span>
<div class="value" style="overflow: hidden;">
<input type="text" id="property-parent-id">
</div>
</div>
<div class="property">
<div class="label">Registration</div>
<div class="value">

View file

@ -2,7 +2,7 @@ set(TARGET_NAME interface)
project(${TARGET_NAME})
# set a default root dir for each of our optional externals if it was not passed
set(OPTIONAL_EXTERNALS "LeapMotion" "RtMidi" "RSSDK")
set(OPTIONAL_EXTERNALS "LeapMotion")
if(WIN32)
list(APPEND OPTIONAL_EXTERNALS "3DConnexionClient")
@ -161,13 +161,6 @@ foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
endif ()
endforeach()
# special OS X modifications for RtMidi library
if (RTMIDI_FOUND AND NOT DISABLE_RTMIDI AND APPLE)
find_library(CoreMIDI CoreMIDI)
add_definitions(-D__MACOSX_CORE__)
target_link_libraries(${TARGET_NAME} ${CoreMIDI})
endif ()
# include headers for interface and InterfaceConfig.
include_directories("${PROJECT_SOURCE_DIR}/src")

View file

@ -1,9 +0,0 @@
Instructions for adding the Intel Realsense (RSSDK) to Interface
Thijs Wenker, December 19, 2014
This is Windows only for now.
1. Download the SDK at https://software.intel.com/en-us/intel-realsense-sdk/download
2. Copy the `lib` and `include` folder inside this directory

View file

@ -1,43 +0,0 @@
Instructions for adding the RtMidi library to Interface
Stephen Birarda, June 30, 2014
1. Download the RtMidi tarball from High Fidelity S3.
http://public.highfidelity.io/dependencies/rtmidi-2.1.0.tar.gz
2. Copy RtMidi.h to externals/rtmidi/include.
3. Compile the RtMidi library.
3. Copy either librtmidi.dylib (dynamic) or librtmidi.a (static) to externals/rtmidi/lib
4. Delete your build directory, run cmake and build, and you should be all set.
=========================
RtMidi: realtime MIDI i/o C++ classes<BR>
Copyright (c) 2003-2014 Gary P. Scavone
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Any person wishing to distribute modifications to the Software is
asked to send the modifications to the original developer so that
they can be incorporated into the canonical version. This is,
however, not a binding provision of this license.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

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>
@ -110,8 +113,6 @@
#include "devices/EyeTracker.h"
#include "devices/Faceshift.h"
#include "devices/Leapmotion.h"
#include "devices/MIDIManager.h"
#include "devices/RealSense.h"
#include "DiscoverabilityManager.h"
#include "GLCanvas.h"
#include "InterfaceActionFactory.h"
@ -149,6 +150,8 @@
#include "ui/Stats.h"
#include "ui/UpdateDialog.h"
#include "Util.h"
#include "InterfaceParentFinder.h"
// ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
@ -297,6 +300,7 @@ bool setupEssentials(int& argc, char** argv) {
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
DependencyManager::registerInheritance<AvatarHashMap, AvatarManager>();
DependencyManager::registerInheritance<EntityActionFactoryInterface, InterfaceActionFactory>();
DependencyManager::registerInheritance<SpatialParentFinder, InterfaceParentFinder>();
Setting::init();
@ -345,6 +349,7 @@ bool setupEssentials(int& argc, char** argv) {
DependencyManager::set<MessagesClient>();
DependencyManager::set<UserInputMapper>();
DependencyManager::set<controller::ScriptingInterface, ControllerScriptingInterface>();
DependencyManager::set<InterfaceParentFinder>();
return true;
}
@ -615,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());
@ -719,12 +726,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
// set the local loopback interface for local sounds from audio scripts
AudioScriptingInterface::getInstance().setLocalAudioInterface(audioIO.data());
#ifdef HAVE_RTMIDI
// setup the MIDIManager
MIDIManager& midiManagerInstance = MIDIManager::getInstance();
midiManagerInstance.openDefaultPort();
#endif
this->installEventFilter(this);
// initialize our face trackers after loading the menu settings
@ -970,7 +971,6 @@ Application::~Application() {
nodeThread->wait();
Leapmotion::destroy();
RealSense::destroy();
#if 0
ConnexionClient::getInstance().destroy();
@ -1141,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
@ -1196,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();
}
{
@ -1250,7 +1253,7 @@ void Application::paintGL() {
* glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)) * hmdRotation);
glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix());
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
+ glm::vec3(0, _raiseMirror * myAvatar->getScale(), 0)
+ glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0)
+ (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) *
glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror
+ (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))) * hmdOffset);
@ -1258,7 +1261,7 @@ void Application::paintGL() {
_myCamera.setRotation(myAvatar->getWorldAlignedOrientation()
* glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
+ glm::vec3(0, _raiseMirror * myAvatar->getScale(), 0)
+ glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0)
+ (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) *
glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
}
@ -1309,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.
@ -1324,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);
});
@ -1344,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");
@ -1372,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) {
@ -2519,7 +2521,6 @@ void Application::init() {
qCDebug(interfaceapp) << "Loaded settings";
Leapmotion::init();
RealSense::init();
// fire off an immediate domain-server check in now that settings are loaded
DependencyManager::get<NodeList>()->sendDomainServerCheckIn();
@ -2618,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 {
@ -3075,6 +3076,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
// These will be the same for all servers, so we can set them up once and then reuse for each server we send to.
_octreeQuery.setWantLowResMoving(true);
_octreeQuery.setWantDelta(true);
_octreeQuery.setWantCompression(true);
_octreeQuery.setCameraPosition(_viewFrustum.getPosition());
_octreeQuery.setCameraOrientation(_viewFrustum.getOrientation());
@ -3322,7 +3324,7 @@ MyAvatar* Application::getMyAvatar() const {
return DependencyManager::get<AvatarManager>()->getMyAvatar();
}
const glm::vec3& Application::getAvatarPosition() const {
glm::vec3 Application::getAvatarPosition() const {
return getMyAvatar()->getPosition();
}
@ -4069,10 +4071,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
scriptEngine->registerGlobalObject("Scene", DependencyManager::get<SceneScriptingInterface>().data());
scriptEngine->registerGlobalObject("ScriptDiscoveryService", this->getRunningScriptsWidget());
#ifdef HAVE_RTMIDI
scriptEngine->registerGlobalObject("MIDI", &MIDIManager::getInstance());
#endif
}
bool Application::canAcceptURL(const QString& urlString) {
@ -4520,7 +4518,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()) {
@ -4531,7 +4529,6 @@ void Application::takeSnapshot() {
_snapshotShareDialog = new SnapshotShareDialog(fileName, _glWidget);
}
_snapshotShareDialog->show();
}
float Application::getRenderResolutionScale() const {
@ -4714,10 +4711,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();
@ -4747,9 +4740,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();
});
@ -4791,19 +4785,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();
@ -4929,7 +4922,7 @@ mat4 Application::getEyeOffset(int eye) const {
mat4 Application::getHMDSensorPose() const {
if (isHMDMode()) {
return getActiveDisplayPlugin()->getHeadPose();
return getActiveDisplayPlugin()->getHeadPose(_frameCount);
}
return mat4();
}

View file

@ -159,6 +159,7 @@ public:
bool isForeground() const { return _isForeground; }
uint32_t getFrameCount() { return _frameCount; }
float getFps() const { return _fps; }
float getTargetFrameRate(); // frames/second
float getTargetFramePeriod(); // seconds
@ -184,7 +185,7 @@ public:
virtual float getSizeScale() const;
virtual int getBoundaryLevelAdjust() const;
virtual PickRay computePickRay(float x, float y) const;
virtual const glm::vec3& getAvatarPosition() const;
virtual glm::vec3 getAvatarPosition() const;
virtual void overrideEnvironmentData(const EnvironmentData& newData) { _environment.override(newData); }
virtual void endOverrideEnvironmentData() { _environment.endOverride(); }
virtual qreal getDevicePixelRatio();
@ -424,6 +425,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

@ -0,0 +1,37 @@
//
// InterfaceParentFinder.cpp
// interface/src/
//
// Created by Seth Alves on 2015-10-21
// 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 <Application.h>
#include <EntityTree.h>
#include <EntityTreeRenderer.h>
#include <avatar/AvatarManager.h>
#include "InterfaceParentFinder.h"
SpatiallyNestableWeakPointer InterfaceParentFinder::find(QUuid parentID) const {
SpatiallyNestableWeakPointer parent;
if (parentID.isNull()) {
return parent;
}
// search entities
EntityTreeRenderer* treeRenderer = qApp->getEntities();
EntityTreePointer tree = treeRenderer->getTree();
parent = tree->findEntityByEntityItemID(parentID);
if (!parent.expired()) {
return parent;
}
// search avatars
QSharedPointer<AvatarManager> avatarManager = DependencyManager::get<AvatarManager>();
return avatarManager->getAvatarBySessionID(parentID);
}

View file

@ -0,0 +1,27 @@
//
// InterfaceParentFinder.h
// interface/src/
//
// Created by Seth Alves on 2015-10-21
// 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_InterfaceParentFinder_h
#define hifi_InterfaceParentFinder_h
#include <memory>
#include <QUuid>
#include <SpatialParentFinder.h>
class InterfaceParentFinder : public SpatialParentFinder {
public:
InterfaceParentFinder() { }
virtual ~InterfaceParentFinder() { }
virtual SpatiallyNestableWeakPointer find(QUuid parentID) const;
};
#endif // hifi_InterfaceParentFinder_h

View file

@ -29,7 +29,6 @@
#include "avatar/AvatarManager.h"
#include "devices/DdeFaceTracker.h"
#include "devices/Faceshift.h"
#include "devices/RealSense.h"
#include "input-plugins/SpacemouseManager.h"
#include "MainWindow.h"
#include "scripting/MenuScriptingInterface.h"
@ -433,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);
@ -462,12 +459,6 @@ Menu::Menu() {
MenuWrapper* leapOptionsMenu = handOptionsMenu->addMenu("Leap Motion");
addCheckableActionToQMenuAndActionHash(leapOptionsMenu, MenuOption::LeapMotionOnHMD, 0, false);
#ifdef HAVE_RSSDK
MenuWrapper* realSenseOptionsMenu = handOptionsMenu->addMenu("RealSense");
addActionToQMenuAndActionHash(realSenseOptionsMenu, MenuOption::LoadRSSDKFile, 0,
RealSense::getInstance(), SLOT(loadRSSDKFile()));
#endif
MenuWrapper* networkMenu = developerMenu->addMenu("Network");
addActionToQMenuAndActionHash(networkMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()));
addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::DisableNackPackets, 0, false,

View file

@ -211,7 +211,6 @@ namespace MenuOption {
const QString LeapMotionOnHMD = "Leap Motion on HMD";
const QString LoadScript = "Open and Run Script File...";
const QString LoadScriptURL = "Open and Run Script from URL...";
const QString LoadRSSDKFile = "Load .rssdk file";
const QString LodTools = "LOD Tools";
const QString Login = "Login";
const QString Log = "Log";
@ -239,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

@ -130,9 +130,9 @@ void Stars::render(RenderArgs* renderArgs, float alpha) {
std::call_once(once, [&] {
{
auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)));
auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(starsGrid_frag)));
auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps));
auto vs = gpu::Shader::createVertex(std::string(standardTransformPNTC_vert));
auto ps = gpu::Shader::createPixel(std::string(starsGrid_frag));
auto program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::makeProgram((*program));
_timeSlot = program->getBuffers().findLocation(UNIFORM_TIME_NAME);
if (_timeSlot == gpu::Shader::INVALID_LOCATION) {
@ -143,12 +143,12 @@ void Stars::render(RenderArgs* renderArgs, float alpha) {
state->setDepthTest(gpu::State::DepthTest(false));
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
_gridPipeline.reset(gpu::Pipeline::create(program, state));
_gridPipeline = gpu::Pipeline::create(program, state);
}
{
auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(stars_vert)));
auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(stars_frag)));
auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps));
auto vs = gpu::Shader::createVertex(std::string(stars_vert));
auto ps = gpu::Shader::createPixel(std::string(stars_frag));
auto program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::makeProgram((*program));
auto state = gpu::StatePointer(new gpu::State());
// enable decal blend
@ -156,7 +156,7 @@ void Stars::render(RenderArgs* renderArgs, float alpha) {
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
state->setAntialiasedLineEnable(true); // line smoothing also smooth points
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
_starsPipeline.reset(gpu::Pipeline::create(program, state));
_starsPipeline = gpu::Pipeline::create(program, state);
}

View file

@ -38,7 +38,6 @@
#include "Hand.h"
#include "Head.h"
#include "Menu.h"
#include "ModelReferential.h"
#include "Physics.h"
#include "Util.h"
#include "world.h"
@ -91,7 +90,6 @@ Avatar::Avatar(RigPointer rig) :
_angularAcceleration(0.0f),
_lastOrientation(),
_leanScale(0.5f),
_scale(1.0f),
_worldUpDirection(DEFAULT_UP_DIRECTION),
_moving(false),
_initialized(false),
@ -101,6 +99,7 @@ Avatar::Avatar(RigPointer rig) :
// we may have been created in the network thread, but we live in the main thread
moveToThread(qApp->thread());
setAvatarScale(1.0f);
// give the pointer to our head to inherited _headData variable from AvatarData
_headData = static_cast<HeadData*>(new Head(this));
_handData = static_cast<HandData*>(new Hand(this));
@ -125,12 +124,12 @@ void Avatar::init() {
glm::vec3 Avatar::getChestPosition() const {
// for now, let's just assume that the "chest" is halfway between the root and the neck
glm::vec3 neckPosition;
return _skeletonModel.getNeckPosition(neckPosition) ? (_position + neckPosition) * 0.5f : _position;
return _skeletonModel.getNeckPosition(neckPosition) ? (getPosition() + neckPosition) * 0.5f : getPosition();
}
glm::vec3 Avatar::getNeckPosition() const {
glm::vec3 neckPosition;
return _skeletonModel.getNeckPosition(neckPosition) ? neckPosition : _position;
return _skeletonModel.getNeckPosition(neckPosition) ? neckPosition : getPosition();
}
@ -144,38 +143,14 @@ AABox Avatar::getBounds() const {
float Avatar::getLODDistance() const {
return DependencyManager::get<LODManager>()->getAvatarLODDistanceMultiplier() *
glm::distance(qApp->getCamera()->getPosition(), _position) / _scale;
glm::distance(qApp->getCamera()->getPosition(), getPosition()) / getAvatarScale();
}
void Avatar::simulate(float deltaTime) {
PerformanceTimer perfTimer("simulate");
// update the avatar's position according to its referential
if (_referential) {
if (_referential->hasExtraData()) {
EntityTreePointer tree = qApp->getEntities()->getTree();
switch (_referential->type()) {
case Referential::MODEL:
_referential = new ModelReferential(_referential,
tree,
this);
break;
case Referential::JOINT:
_referential = new JointReferential(_referential,
tree,
this);
break;
default:
qCDebug(interfaceapp) << "[WARNING] Avatar::simulate(): Unknown referential type.";
break;
}
}
_referential->update();
}
if (_scale != _targetScale) {
setScale(_targetScale);
if (getAvatarScale() != _targetScale) {
setAvatarScale(_targetScale);
}
// update the billboard render flag
@ -193,7 +168,7 @@ void Avatar::simulate(float deltaTime) {
const bool isControllerLogging = DependencyManager::get<AvatarManager>()->getRenderDistanceControllerIsLogging();
float renderDistance = DependencyManager::get<AvatarManager>()->getRenderDistance();
const float SKIP_HYSTERESIS_PROPORTION = isControllerLogging ? 0.0f : BILLBOARD_HYSTERESIS_PROPORTION;
float distance = glm::distance(qApp->getCamera()->getPosition(), _position);
float distance = glm::distance(qApp->getCamera()->getPosition(), getPosition());
if (_shouldSkipRender) {
if (distance < renderDistance * (1.0f - SKIP_HYSTERESIS_PROPORTION)) {
_shouldSkipRender = false;
@ -212,7 +187,7 @@ void Avatar::simulate(float deltaTime) {
// simple frustum check
float boundingRadius = getBillboardSize();
bool inViewFrustum = qApp->getViewFrustum()->sphereInFrustum(_position, boundingRadius) !=
bool inViewFrustum = qApp->getViewFrustum()->sphereInFrustum(getPosition(), boundingRadius) !=
ViewFrustum::OUTSIDE;
{
@ -231,11 +206,11 @@ void Avatar::simulate(float deltaTime) {
}
{
PerformanceTimer perfTimer("head");
glm::vec3 headPosition = _position;
glm::vec3 headPosition = getPosition();
_skeletonModel.getHeadPosition(headPosition);
Head* head = getHead();
head->setPosition(headPosition);
head->setScale(_scale);
head->setScale(getAvatarScale());
head->simulate(deltaTime, false, _shouldRenderBillboard);
}
}
@ -268,7 +243,7 @@ bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) {
glm::vec3 theirLookAt = dynamic_pointer_cast<Avatar>(avatar)->getHead()->getLookAtPosition();
glm::vec3 myEyePosition = getHead()->getEyePosition();
return glm::distance(theirLookAt, myEyePosition) <= (HEAD_SPHERE_RADIUS * getScale());
return glm::distance(theirLookAt, myEyePosition) <= (HEAD_SPHERE_RADIUS * getAvatarScale());
}
void Avatar::slamPosition(const glm::vec3& newPosition) {
@ -279,7 +254,7 @@ void Avatar::slamPosition(const glm::vec3& newPosition) {
}
void Avatar::applyPositionDelta(const glm::vec3& delta) {
_position += delta;
setPosition(getPosition() + delta);
_positionDeltaAccumulator += delta;
}
@ -345,15 +320,10 @@ void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptr<render::S
}
void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
startRender();
if (_referential) {
_referential->update();
}
auto& batch = *renderArgs->_batch;
PROFILE_RANGE_BATCH(batch, __FUNCTION__);
if (glm::distance(DependencyManager::get<AvatarManager>()->getMyAvatar()->getPosition(), _position) < 10.0f) {
if (glm::distance(DependencyManager::get<AvatarManager>()->getMyAvatar()->getPosition(), getPosition()) < 10.0f) {
auto geometryCache = DependencyManager::get<GeometryCache>();
auto deferredLighting = DependencyManager::get<DeferredLightingEffect>();
@ -453,7 +423,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
const float BASE_LIGHT_DISTANCE = 2.0f;
const float LIGHT_EXPONENT = 1.0f;
const float LIGHT_CUTOFF = glm::radians(80.0f);
float distance = BASE_LIGHT_DISTANCE * _scale;
float distance = BASE_LIGHT_DISTANCE * getAvatarScale();
glm::vec3 position = glm::mix(_skeletonModel.getTranslation(), getHead()->getFaceModel().getTranslation(), 0.9f);
glm::quat orientation = getOrientation();
foreach (const AvatarManager::LocalLight& light, DependencyManager::get<AvatarManager>()->getLocalLights()) {
@ -463,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");
@ -484,7 +444,8 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
static const float INDICATOR_OFFSET = 0.22f;
static const float INDICATOR_RADIUS = 0.03f;
static const glm::vec4 LOOK_AT_INDICATOR_COLOR = { 0.8f, 0.0f, 0.0f, 0.75f };
glm::vec3 position = glm::vec3(_position.x, getDisplayNamePosition().y + INDICATOR_OFFSET, _position.z);
glm::vec3 avatarPosition = getPosition();
glm::vec3 position = glm::vec3(avatarPosition.x, getDisplayNamePosition().y + INDICATOR_OFFSET, avatarPosition.z);
PROFILE_RANGE_BATCH(batch, __FUNCTION__":renderFocusIndicator");
Transform transform;
transform.setTranslation(position);
@ -518,7 +479,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
}
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphereInstance(batch,
Transform(transform).postScale(eyeDiameter * _scale / 2.0f + RADIUS_INCREMENT),
Transform(transform).postScale(eyeDiameter * getAvatarScale() / 2.0f + RADIUS_INCREMENT),
glm::vec4(LOOKING_AT_ME_COLOR, alpha));
position = getHead()->getRightEyePosition();
@ -528,7 +489,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
eyeDiameter = DEFAULT_EYE_DIAMETER;
}
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphereInstance(batch,
Transform(transform).postScale(eyeDiameter * _scale / 2.0f + RADIUS_INCREMENT),
Transform(transform).postScale(eyeDiameter * getAvatarScale() / 2.0f + RADIUS_INCREMENT),
glm::vec4(LOOKING_AT_ME_COLOR, alpha));
}
@ -559,7 +520,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
Transform transform;
transform.setTranslation(_position);
transform.setTranslation(getPosition());
transform.setScale(height);
transform.postScale(sphereRadius);
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphereInstance(batch,
@ -662,9 +623,9 @@ void Avatar::simulateAttachments(float deltaTime) {
glm::quat jointRotation;
if (_skeletonModel.getJointPositionInWorldFrame(jointIndex, jointPosition) &&
_skeletonModel.getJointRotationInWorldFrame(jointIndex, jointRotation)) {
model->setTranslation(jointPosition + jointRotation * attachment.translation * _scale);
model->setTranslation(jointPosition + jointRotation * attachment.translation * getAvatarScale());
model->setRotation(jointRotation * attachment.rotation);
model->setScaleToFit(true, _scale * attachment.scale, true); // hack to force rescale
model->setScaleToFit(true, getAvatarScale() * attachment.scale, true); // hack to force rescale
model->setSnapModelToCenter(false); // hack to force resnap
model->setSnapModelToCenter(true);
model->simulate(deltaTime);
@ -694,14 +655,14 @@ void Avatar::renderBillboard(RenderArgs* renderArgs) {
}
// rotate about vertical to face the camera
glm::quat rotation = getOrientation();
glm::vec3 cameraVector = glm::inverse(rotation) * (qApp->getCamera()->getPosition() - _position);
glm::vec3 cameraVector = glm::inverse(rotation) * (qApp->getCamera()->getPosition() - getPosition());
rotation = rotation * glm::angleAxis(atan2f(-cameraVector.x, -cameraVector.z), glm::vec3(0.0f, 1.0f, 0.0f));
// compute the size from the billboard camera parameters and scale
float size = getBillboardSize();
Transform transform;
transform.setTranslation(_position);
transform.setTranslation(getPosition());
transform.setRotation(rotation);
transform.setScale(size);
@ -719,7 +680,7 @@ void Avatar::renderBillboard(RenderArgs* renderArgs) {
}
float Avatar::getBillboardSize() const {
return _scale * BILLBOARD_DISTANCE * glm::tan(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f));
return getAvatarScale() * BILLBOARD_DISTANCE * glm::tan(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f));
}
#ifdef DEBUG
@ -754,9 +715,9 @@ glm::vec3 Avatar::getDisplayNamePosition() const {
const float HEAD_PROPORTION = 0.75f;
float billboardSize = getBillboardSize();
DEBUG_VALUE("_position =", _position);
DEBUG_VALUE("_position =", getPosition());
DEBUG_VALUE("billboardSize =", billboardSize);
namePosition = _position + bodyUpDirection * (billboardSize * HEAD_PROPORTION);
namePosition = getPosition() + bodyUpDirection * (billboardSize * HEAD_PROPORTION);
}
if (glm::any(glm::isnan(namePosition)) || glm::any(glm::isinf(namePosition))) {
@ -868,7 +829,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, co
}
void Avatar::setSkeletonOffset(const glm::vec3& offset) {
const float MAX_OFFSET_LENGTH = _scale * 0.5f;
const float MAX_OFFSET_LENGTH = getAvatarScale() * 0.5f;
float offsetLength = glm::length(offset);
if (offsetLength > MAX_OFFSET_LENGTH) {
_skeletonOffset = (MAX_OFFSET_LENGTH / offsetLength) * offset;
@ -881,7 +842,7 @@ glm::vec3 Avatar::getSkeletonPosition() const {
// The avatar is rotated PI about the yAxis, so we have to correct for it
// to get the skeleton offset contribution in the world-frame.
const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
return _position + getOrientation() * FLIP * _skeletonOffset;
return getPosition() + getOrientation() * FLIP * _skeletonOffset;
}
QVector<glm::quat> Avatar::getJointRotations() const {
@ -960,7 +921,7 @@ glm::vec3 Avatar::getJointPosition(const QString& name) const {
void Avatar::scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const {
//Scale a world space vector as if it was relative to the position
positionToScale = _position + _scale * (positionToScale - _position);
positionToScale = getPosition() + getAvatarScale() * (positionToScale - getPosition());
}
void Avatar::setFaceModelURL(const QUrl& faceModelURL) {
@ -1000,7 +961,7 @@ void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
for (int i = 0; i < attachmentData.size(); i++) {
_attachmentModels[i]->setURL(attachmentData.at(i).modelURL);
_attachmentModels[i]->setSnapModelToCenter(true);
_attachmentModels[i]->setScaleToFit(true, _scale * _attachmentData.at(i).scale);
_attachmentModels[i]->setScaleToFit(true, getAvatarScale() * _attachmentData.at(i).scale);
}
}
@ -1019,12 +980,12 @@ int Avatar::parseDataFromBuffer(const QByteArray& buffer) {
}
// change in position implies movement
glm::vec3 oldPosition = _position;
glm::vec3 oldPosition = getPosition();
int bytesRead = AvatarData::parseDataFromBuffer(buffer);
const float MOVE_DISTANCE_THRESHOLD = 0.001f;
_moving = glm::distance(oldPosition, _position) > MOVE_DISTANCE_THRESHOLD;
_moving = glm::distance(oldPosition, getPosition()) > MOVE_DISTANCE_THRESHOLD;
if (_moving && _motionState) {
_motionState->addDirtyFlags(Simulation::DIRTY_POSITION);
}
@ -1088,12 +1049,12 @@ void Avatar::renderJointConnectingCone(gpu::Batch& batch, glm::vec3 position1, g
}
}
void Avatar::setScale(float scale) {
_scale = scale;
if (_targetScale * (1.0f - RESCALING_TOLERANCE) < _scale &&
_scale < _targetScale * (1.0f + RESCALING_TOLERANCE)) {
_scale = _targetScale;
void Avatar::setAvatarScale(float scale) {
if (_targetScale * (1.0f - RESCALING_TOLERANCE) < scale &&
scale < _targetScale * (1.0f + RESCALING_TOLERANCE)) {
setScale(glm::vec3(_targetScale));
} else {
setScale(glm::vec3(scale));
}
}
@ -1108,7 +1069,7 @@ float Avatar::getHeadHeight() const {
// HACK: We have a really odd case when fading out for some models where this value explodes
float result = extents.maximum.y - extents.minimum.y;
if (result >= 0.0f && result < 100.0f * _scale ) {
if (result >= 0.0f && result < 100.0f * getAvatarScale() ) {
return result;
}
}
@ -1116,7 +1077,7 @@ float Avatar::getHeadHeight() const {
extents = _skeletonModel.getMeshExtents();
glm::vec3 neckPosition;
if (!extents.isEmpty() && extents.isValid() && _skeletonModel.getNeckPosition(neckPosition)) {
return extents.maximum.y / 2.0f - neckPosition.y + _position.y;
return extents.maximum.y / 2.0f - neckPosition.y + getPosition().y;
}
const float DEFAULT_HEAD_HEIGHT = 0.25f;
@ -1189,3 +1150,13 @@ glm::quat Avatar::getRightPalmRotation() {
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation);
return rightRotation;
}
void Avatar::setPosition(const glm::vec3 position) {
AvatarData::setPosition(position);
updateAttitude();
}
void Avatar::setOrientation(const glm::quat orientation) {
AvatarData::setOrientation(orientation);
updateAttitude();
}

View file

@ -89,7 +89,7 @@ public:
const SkeletonModel& getSkeletonModel() const { return _skeletonModel; }
const QVector<Model*>& getAttachmentModels() const { return _attachmentModels; }
glm::vec3 getChestPosition() const;
float getScale() const { return _scale; }
float getAvatarScale() const { return getScale().y; }
const Head* getHead() const { return static_cast<const Head*>(_headData); }
Head* getHead() { return static_cast<Head*>(_headData); }
Hand* getHand() { return static_cast<Hand*>(_handData); }
@ -155,6 +155,9 @@ public:
void setMotionState(AvatarMotionState* motionState) { _motionState = motionState; }
AvatarMotionState* getMotionState() { return _motionState; }
virtual void setPosition(glm::vec3 position);
virtual void setOrientation(glm::quat orientation);
public slots:
// FIXME - these should be migrated to use Pose data instead
@ -186,7 +189,6 @@ protected:
glm::quat _lastOrientation;
float _leanScale;
float _scale;
glm::vec3 _worldUpDirection;
float _stringLength;
bool _moving; ///< set when position is changing
@ -198,7 +200,7 @@ protected:
glm::vec3 getBodyUpDirection() const { return getOrientation() * IDENTITY_UP; }
glm::vec3 getBodyFrontDirection() const { return getOrientation() * IDENTITY_FRONT; }
glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const;
void setScale(float scale);
void setAvatarScale(float scale);
void measureMotionDerivatives(float deltaTime);
float getSkeletonHeight() const;

View file

@ -206,7 +206,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) {
while (fadingIterator != _avatarFades.end()) {
auto avatar = std::static_pointer_cast<Avatar>(*fadingIterator);
avatar->startUpdate();
avatar->setTargetScale(avatar->getScale() * SHRINK_RATE, true);
avatar->setTargetScale(avatar->getAvatarScale() * SHRINK_RATE);
if (avatar->getTargetScale() <= MIN_FADE_SCALE) {
avatar->removeFromScene(*fadingIterator, scene, pendingChanges);
fadingIterator = _avatarFades.erase(fadingIterator);

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

@ -37,7 +37,7 @@ void Hand::simulate(float deltaTime, bool isMine) {
void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) {
float avatarScale = 1.0f;
if (_owningAvatar) {
avatarScale = _owningAvatar->getScale();
avatarScale = _owningAvatar->getAvatarScale();
}
const float alpha = 1.0f;

View file

@ -1,192 +0,0 @@
//
// ModelReferential.cpp
//
//
// Created by Clement on 7/30/14.
// Copyright 2014 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 <AvatarData.h>
#include <EntityTree.h>
#include <Model.h>
#include "InterfaceLogging.h"
#include "ModelReferential.h"
ModelReferential::ModelReferential(Referential* referential, EntityTreePointer tree, AvatarData* avatar) :
Referential(MODEL, avatar),
_tree(tree)
{
_translation = referential->getTranslation();
_rotation = referential->getRotation();
unpackExtraData(reinterpret_cast<unsigned char*>(referential->getExtraData().data()),
referential->getExtraData().size());
if (!isValid()) {
qCDebug(interfaceapp) << "ModelReferential::copyConstructor(): Not Valid";
return;
}
EntityItemPointer item = _tree->findEntityByID(_entityID);
if (item != NULL) {
_lastRefDimension = item->getDimensions();
_refRotation = item->getRotation();
_refPosition = item->getPosition();
update();
}
}
ModelReferential::ModelReferential(const QUuid& entityID, EntityTreePointer tree, AvatarData* avatar) :
Referential(MODEL, avatar),
_entityID(entityID),
_tree(tree)
{
EntityItemPointer item = _tree->findEntityByID(_entityID);
if (!isValid() || item == NULL) {
qCDebug(interfaceapp) << "ModelReferential::constructor(): Not Valid";
_isValid = false;
return;
}
_lastRefDimension = item->getDimensions();
_refRotation = item->getRotation();
_refPosition = item->getPosition();
glm::quat refInvRot = glm::inverse(_refRotation);
_rotation = refInvRot * _avatar->getOrientation();
_translation = refInvRot * (avatar->getPosition() - _refPosition);
}
void ModelReferential::update() {
EntityItemPointer item = _tree->findEntityByID(_entityID);
if (!isValid() || item == NULL || _avatar == NULL) {
return;
}
bool somethingChanged = false;
if (item->getDimensions() != _lastRefDimension) {
glm::vec3 oldDimension = _lastRefDimension;
_lastRefDimension = item->getDimensions();
_translation *= _lastRefDimension / oldDimension;
somethingChanged = true;
}
if (item->getRotation() != _refRotation) {
_refRotation = item->getRotation();
_avatar->setOrientation(_refRotation * _rotation, true);
somethingChanged = true;
}
if (item->getPosition() != _refPosition || somethingChanged) {
_refPosition = item->getPosition();
_avatar->setPosition(_refPosition + _refRotation * _translation, true);
}
}
int ModelReferential::packExtraData(unsigned char* destinationBuffer) const {
QByteArray encodedEntityID = _entityID.toRfc4122();
memcpy(destinationBuffer, encodedEntityID.constData(), encodedEntityID.size());
return encodedEntityID.size();
}
int ModelReferential::unpackExtraData(const unsigned char *sourceBuffer, int size) {
QByteArray encodedEntityID((const char*)sourceBuffer, NUM_BYTES_RFC4122_UUID);
_entityID = QUuid::fromRfc4122(encodedEntityID);
return NUM_BYTES_RFC4122_UUID;
}
JointReferential::JointReferential(Referential* referential, EntityTreePointer tree, AvatarData* avatar) :
ModelReferential(referential, tree, avatar)
{
_type = JOINT;
if (!isValid()) {
qCDebug(interfaceapp) << "JointReferential::copyConstructor(): Not Valid";
return;
}
EntityItemPointer item = _tree->findEntityByID(_entityID);
const Model* model = getModel(item);
if (isValid() && model != NULL && _jointIndex < (uint32_t)(model->getJointStateCount())) {
_lastRefDimension = item->getDimensions();
model->getJointRotationInWorldFrame(_jointIndex, _refRotation);
model->getJointPositionInWorldFrame(_jointIndex, _refPosition);
}
update();
}
JointReferential::JointReferential(uint32_t jointIndex, const QUuid& entityID, EntityTreePointer tree, AvatarData* avatar) :
ModelReferential(entityID, tree, avatar),
_jointIndex(jointIndex)
{
_type = JOINT;
EntityItemPointer item = _tree->findEntityByID(_entityID);
const Model* model = getModel(item);
if (!isValid() || model == NULL || _jointIndex >= (uint32_t)(model->getJointStateCount())) {
qCDebug(interfaceapp) << "JointReferential::constructor(): Not Valid";
_isValid = false;
return;
}
_lastRefDimension = item->getDimensions();
model->getJointRotationInWorldFrame(_jointIndex, _refRotation);
model->getJointPositionInWorldFrame(_jointIndex, _refPosition);
glm::quat refInvRot = glm::inverse(_refRotation);
_rotation = refInvRot * _avatar->getOrientation();
// BUG! _refPosition is in domain units, but avatar is in meters
_translation = refInvRot * (avatar->getPosition() - _refPosition);
}
void JointReferential::update() {
EntityItemPointer item = _tree->findEntityByID(_entityID);
const Model* model = getModel(item);
if (!isValid() || model == NULL || _jointIndex >= (uint32_t)(model->getJointStateCount())) {
return;
}
bool somethingChanged = false;
if (item->getDimensions() != _lastRefDimension) {
glm::vec3 oldDimension = _lastRefDimension;
_lastRefDimension = item->getDimensions();
_translation *= _lastRefDimension / oldDimension;
somethingChanged = true;
}
if (item->getRotation() != _refRotation) {
model->getJointRotationInWorldFrame(_jointIndex, _refRotation);
_avatar->setOrientation(_refRotation * _rotation, true);
somethingChanged = true;
}
if (item->getPosition() != _refPosition || somethingChanged) {
model->getJointPositionInWorldFrame(_jointIndex, _refPosition);
_avatar->setPosition(_refPosition + _refRotation * _translation, true);
}
}
const Model* JointReferential::getModel(EntityItemPointer item) {
EntityItemFBXService* fbxService = _tree->getFBXService();
if (item != NULL && fbxService != NULL) {
return fbxService->getModelForEntityItem(item);
}
return NULL;
}
int JointReferential::packExtraData(unsigned char* destinationBuffer) const {
unsigned char* startPosition = destinationBuffer;
destinationBuffer += ModelReferential::packExtraData(destinationBuffer);
memcpy(destinationBuffer, &_jointIndex, sizeof(_jointIndex));
destinationBuffer += sizeof(_jointIndex);
return destinationBuffer - startPosition;
}
int JointReferential::unpackExtraData(const unsigned char *sourceBuffer, int size) {
const unsigned char* startPosition = sourceBuffer;
sourceBuffer += ModelReferential::unpackExtraData(sourceBuffer, size);
memcpy(&_jointIndex, sourceBuffer, sizeof(_jointIndex));
sourceBuffer += sizeof(_jointIndex);
return sourceBuffer - startPosition;
}

View file

@ -1,48 +0,0 @@
//
// ModelReferential.h
//
//
// Created by Clement on 7/30/14.
// Copyright 2014 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_ModelReferential_h
#define hifi_ModelReferential_h
#include <Referential.h>
class EntityTree;
class Model;
class ModelReferential : public Referential {
public:
ModelReferential(Referential* ref, EntityTreePointer tree, AvatarData* avatar);
ModelReferential(const QUuid& entityID, EntityTreePointer tree, AvatarData* avatar);
virtual void update();
protected:
virtual int packExtraData(unsigned char* destinationBuffer) const;
virtual int unpackExtraData(const unsigned char* sourceBuffer, int size);
QUuid _entityID;
EntityTreePointer _tree;
};
class JointReferential : public ModelReferential {
public:
JointReferential(Referential* ref, EntityTreePointer tree, AvatarData* avatar);
JointReferential(uint32_t jointIndex, const QUuid& entityID, EntityTreePointer tree, AvatarData* avatar);
virtual void update();
protected:
const Model* getModel(EntityItemPointer item);
virtual int packExtraData(unsigned char* destinationBuffer) const;
virtual int unpackExtraData(const unsigned char* sourceBuffer, int size);
uint32_t _jointIndex;
};
#endif // hifi_ModelReferential_h

View file

@ -45,7 +45,6 @@
#include "AvatarManager.h"
#include "Environment.h"
#include "Menu.h"
#include "ModelReferential.h"
#include "MyAvatar.h"
#include "Physics.h"
#include "Util.h"
@ -204,13 +203,14 @@ MyAvatar::~MyAvatar() {
QByteArray MyAvatar::toByteArray(bool cullSmallChanges, bool sendAll) {
CameraMode mode = qApp->getCamera()->getMode();
_globalPosition = getPosition();
if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) {
// fake the avatar position that is sent up to the AvatarMixer
glm::vec3 oldPosition = _position;
_position = getSkeletonPosition();
glm::vec3 oldPosition = getPosition();
setPosition(getSkeletonPosition());
QByteArray array = AvatarData::toByteArray(cullSmallChanges, sendAll);
// copy the correct position back
_position = oldPosition;
setPosition(oldPosition);
return array;
}
return AvatarData::toByteArray(cullSmallChanges, sendAll);
@ -269,10 +269,6 @@ void MyAvatar::update(float deltaTime) {
updateSensorToWorldMatrix();
}
if (_referential) {
_referential->update();
}
Head* head = getHead();
head->relaxLean(deltaTime);
updateFromTrackers(deltaTime);
@ -291,9 +287,9 @@ extern void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avata
void MyAvatar::simulate(float deltaTime) {
PerformanceTimer perfTimer("simulate");
if (_scale != _targetScale) {
float scale = (1.0f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _targetScale;
setScale(scale);
if (getAvatarScale() != _targetScale) {
float scale = (1.0f - SMOOTHING_RATIO) * getAvatarScale() + SMOOTHING_RATIO * _targetScale;
setAvatarScale(scale);
}
{
@ -343,10 +339,10 @@ void MyAvatar::simulate(float deltaTime) {
Head* head = getHead();
glm::vec3 headPosition;
if (!_skeletonModel.getHeadPosition(headPosition)) {
headPosition = _position;
headPosition = getPosition();
}
head->setPosition(headPosition);
head->setScale(_scale);
head->setScale(getAvatarScale());
head->simulate(deltaTime, true);
}
@ -568,32 +564,6 @@ void MyAvatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
Avatar::render(renderArgs, cameraPosition);
}
void MyAvatar::clearReferential() {
changeReferential(NULL);
}
bool MyAvatar::setModelReferential(const QUuid& id) {
EntityTreePointer tree = qApp->getEntities()->getTree();
changeReferential(new ModelReferential(id, tree, this));
if (_referential->isValid()) {
return true;
} else {
changeReferential(NULL);
return false;
}
}
bool MyAvatar::setJointReferential(const QUuid& id, int jointIndex) {
EntityTreePointer tree = qApp->getEntities()->getTree();
changeReferential(new JointReferential(jointIndex, id, tree, this));
if (!_referential->isValid()) {
return true;
} else {
changeReferential(NULL);
return false;
}
}
void MyAvatar::overrideAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "overrideAnimation", Q_ARG(const QString&, url), Q_ARG(float, fps),
@ -732,7 +702,7 @@ void MyAvatar::loadData() {
_leanScale = loadSetting(settings, "leanScale", 0.05f);
_targetScale = loadSetting(settings, "scale", 1.0f);
setScale(_scale);
setAvatarScale(getAvatarScale());
_animGraphUrl = settings.value("animGraphURL", "").toString();
_fullAvatarURLFromPreferences = settings.value("fullAvatarURL", AvatarData::defaultFullAvatarModelUrl()).toUrl();
@ -859,7 +829,8 @@ void MyAvatar::updateLookAtTargetAvatar() {
bool isCurrentTarget = avatar->getIsLookAtTarget();
float distanceTo = glm::length(avatar->getHead()->getEyePosition() - cameraPosition);
avatar->setIsLookAtTarget(false);
if (!avatar->isMyAvatar() && avatar->isInitialized() && (distanceTo < GREATEST_LOOKING_AT_DISTANCE * getScale())) {
if (!avatar->isMyAvatar() && avatar->isInitialized() &&
(distanceTo < GREATEST_LOOKING_AT_DISTANCE * getAvatarScale())) {
float angleTo = glm::angle(lookForward, glm::normalize(avatar->getHead()->getEyePosition() - cameraPosition));
if (angleTo < (smallestAngleTo * (isCurrentTarget ? KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR : 1.0f))) {
_lookAtTargetAvatar = avatarPointer;
@ -1071,7 +1042,7 @@ glm::vec3 MyAvatar::getSkeletonPosition() const {
// The avatar is rotated PI about the yAxis, so we have to correct for it
// to get the skeleton offset contribution in the world-frame.
const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
return _position + getOrientation() * FLIP * _skeletonOffset;
return getPosition() + getOrientation() * FLIP * _skeletonOffset;
}
return Avatar::getPosition();
}
@ -1229,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);
@ -1283,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
@ -1299,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..
@ -1361,7 +1342,7 @@ const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f;
bool MyAvatar::cameraInsideHead() const {
const Head* head = getHead();
const glm::vec3 cameraPosition = qApp->getCamera()->getPosition();
return glm::length(cameraPosition - head->getEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * _scale);
return glm::length(cameraPosition - head->getEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getAvatarScale());
}
bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const {
@ -1491,11 +1472,11 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe
if (isHovering) {
// we're flying --> complex acceleration curve with high max speed
float motorSpeed = glm::length(_keyboardMotorVelocity);
float finalMaxMotorSpeed = _scale * MAX_KEYBOARD_MOTOR_SPEED;
float finalMaxMotorSpeed = getAvatarScale() * MAX_KEYBOARD_MOTOR_SPEED;
float speedGrowthTimescale = 2.0f;
float speedIncreaseFactor = 1.8f;
motorSpeed *= 1.0f + glm::clamp(deltaTime / speedGrowthTimescale , 0.0f, 1.0f) * speedIncreaseFactor;
const float maxBoostSpeed = _scale * MAX_BOOST_SPEED;
const float maxBoostSpeed = getAvatarScale() * MAX_BOOST_SPEED;
if (motorSpeed < maxBoostSpeed) {
// an active keyboard motor should never be slower than this
float boostCoefficient = (maxBoostSpeed - motorSpeed) / maxBoostSpeed;

View file

@ -247,19 +247,15 @@ public slots:
Q_INVOKABLE void updateMotionBehaviorFromMenu();
void clearReferential();
bool setModelReferential(const QUuid& id);
bool setJointReferential(const QUuid& id, int jointIndex);
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();
@ -360,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

@ -1,73 +0,0 @@
//
// MIDIManager.cpp
//
//
// Created by Stephen Birarda on 2014-06-30.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QtCore/QDebug>
#include "InterfaceLogging.h"
#include "MIDIManager.h"
MIDIManager& MIDIManager::getInstance() {
static MIDIManager sharedInstance;
return sharedInstance;
}
void MIDIManager::midiCallback(double deltaTime, std::vector<unsigned char>* message, void* userData) {
#ifdef HAVE_RTMIDI
MIDIEvent callbackEvent;
callbackEvent.deltaTime = deltaTime;
callbackEvent.type = message->at(0);
if (message->size() > 1) {
callbackEvent.data1 = message->at(1);
}
if (message->size() > 2) {
callbackEvent.data2 = message->at(2);
}
emit getInstance().midiEvent(callbackEvent);
#endif
}
MIDIManager::~MIDIManager() {
#ifdef HAVE_RTMIDI
delete _midiInput;
#endif
}
#ifdef HAVE_RTMIDI
const int DEFAULT_MIDI_PORT = 0;
#endif
void MIDIManager::openDefaultPort() {
#ifdef HAVE_RTMIDI
if (!_midiInput) {
_midiInput = new RtMidiIn();
if (_midiInput->getPortCount() > 0) {
qCDebug(interfaceapp) << "MIDIManager opening port" << DEFAULT_MIDI_PORT;
_midiInput->openPort(DEFAULT_MIDI_PORT);
// don't ignore sysex, timing, or active sensing messages
_midiInput->ignoreTypes(false, false, false);
_midiInput->setCallback(&MIDIManager::midiCallback);
} else {
qCDebug(interfaceapp) << "MIDIManager openDefaultPort called but there are no ports available.";
delete _midiInput;
_midiInput = NULL;
}
}
#endif
}

View file

@ -1,58 +0,0 @@
//
// MIDIManager.h
// interface/src/devices
//
// Created by Stephen Birarda on 2014-06-30.
// Copyright 2014 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_MIDIManager_h
#define hifi_MIDIManager_h
#include <QtCore/QObject>
#include <QtScript/QScriptEngine>
#include <MIDIEvent.h>
#ifdef HAVE_RTMIDI
#include <RtMidi.h>
#endif
class MIDIManager : public QObject {
Q_OBJECT
Q_PROPERTY(unsigned int NoteOn READ NoteOn)
Q_PROPERTY(unsigned int NoteOff READ NoteOff)
Q_PROPERTY(unsigned int ModWheel READ ModWheel)
Q_PROPERTY(unsigned int PitchWheel READ PitchWheel)
public:
static MIDIManager& getInstance();
static void midiCallback(double deltaTime, std::vector<unsigned char>* message, void* userData);
~MIDIManager();
void openDefaultPort();
#ifdef HAVE_RTMIDI
bool hasDevice() const { return !!_midiInput; }
#endif
public slots:
unsigned int NoteOn() const { return 144; }
unsigned int NoteOff() const { return 128; }
unsigned int ModWheel() const { return 176; }
unsigned int PitchWheel() const { return 224; }
signals:
void midiEvent(const MIDIEvent& event);
private:
#ifdef HAVE_RTMIDI
RtMidiIn* _midiInput;
#endif
};
#endif // hifi_MIDIManager_h

View file

@ -1,259 +0,0 @@
//
// RealSense.cpp
// interface/src/devices
//
// Created by Thijs Wenker on 12/10/14
// Copyright 2014 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 "Application.h"
#include "RealSense.h"
#include "MainWindow.h"
#include "Menu.h"
#include "SharedUtil.h"
#ifdef HAVE_RSSDK
const int PALMROOT_NUM_JOINTS = 3;
const int FINGER_NUM_JOINTS = 4;
#endif // HAVE_RSSDK
const DeviceTracker::Name RealSense::NAME = "RealSense";
// find the index of a joint from
// the side: true = right
// the finger & the bone:
// finger in [0..4] : bone in [0..3] a finger phalange
// [-1] up the hand branch : bone in [0..1] <=> [ hand, forearm]
MotionTracker::Index evalRealSenseJointIndex(bool isRightSide, int finger, int bone) {
#ifdef HAVE_RSSDK
MotionTracker::Index offset = 1 // start after root
+ (int(isRightSide) * PXCHandData::NUMBER_OF_JOINTS) // then offset for side
+ PALMROOT_NUM_JOINTS; // then add the arm/forearm/hand chain
if (finger >= 0) {
// from there go down in the correct finger and bone
return offset + (finger * FINGER_NUM_JOINTS) + bone;
} else {
// or go back up for the correct root bone
return offset - 1 - bone;
}
#else
return -1;
#endif // HAVE_RSSDK
}
// static
void RealSense::init() {
DeviceTracker* device = DeviceTracker::getDevice(NAME);
if (!device) {
// create a new RealSense and register it
RealSense* realSense = new RealSense();
DeviceTracker::registerDevice(NAME, realSense);
}
}
// static
void RealSense::destroy() {
DeviceTracker::destroyDevice(NAME);
}
// static
RealSense* RealSense::getInstance() {
DeviceTracker* device = DeviceTracker::getDevice(NAME);
if (!device) {
// create a new RealSense and register it
RealSense* realSense = new RealSense();
DeviceTracker::registerDevice(NAME, realSense);
}
return dynamic_cast< RealSense* > (device);
}
RealSense::RealSense() :
MotionTracker(),
_active(false)
{
#ifdef HAVE_RSSDK
_handData = NULL;
_session = PXCSession_Create();
initSession(false, NULL);
// Create the RealSense joint hierarchy
std::vector< Semantic > sides;
sides.push_back("joint_L_");
sides.push_back("joint_R_");
std::vector< Semantic > rootBones;
rootBones.push_back("wrist");
rootBones.push_back("hand");
std::vector< Semantic > fingers;
fingers.push_back("thumb");
fingers.push_back("index");
fingers.push_back("middle");
fingers.push_back("ring");
fingers.push_back("pinky");
std::vector< Semantic > fingerBones;
fingerBones.push_back("1");
fingerBones.push_back("2");
fingerBones.push_back("3");
fingerBones.push_back("4");
std::vector< Index > palms;
for (unsigned int s = 0; s < sides.size(); s++) {
Index rootJoint = 0;
for (unsigned int rb = 0; rb < rootBones.size(); rb++) {
rootJoint = addJoint(sides[s] + rootBones[rb], rootJoint);
}
// capture the hand index for debug
palms.push_back(rootJoint);
for (unsigned int f = 0; f < fingers.size(); f++) {
for (unsigned int b = 0; b < fingerBones.size(); b++) {
rootJoint = addJoint(sides[s] + fingers[f] + fingerBones[b], rootJoint);
}
}
}
#endif // HAVE_RSSDK
}
RealSense::~RealSense() {
#ifdef HAVE_RSSDK
_manager->Release();
#endif // HAVE_RSSDK
}
void RealSense::initSession(bool playback, QString filename) {
#ifdef HAVE_RSSDK
_active = false;
_properlyInitialized = false;
if (_handData != NULL) {
_handData->Release();
_handController->Release();
_session->Release();
_config->Release();
}
_manager = _session->CreateSenseManager();
if (playback) {
_manager->QueryCaptureManager()->SetFileName(filename.toStdWString().c_str(), false);
}
_manager->QueryCaptureManager()->SetRealtime(!playback);
_manager->EnableHand(0);
_handController = _manager->QueryHand();
if (_manager->Init() == PXC_STATUS_NO_ERROR) {
_handData = _handController->CreateOutput();
PXCCapture::Device *device = _manager->QueryCaptureManager()->QueryDevice();
PXCCapture::DeviceInfo dinfo;
_manager->QueryCaptureManager()->QueryDevice()->QueryDeviceInfo(&dinfo);
if (dinfo.model == PXCCapture::DEVICE_MODEL_IVCAM)
{
device->SetDepthConfidenceThreshold(1);
device->SetMirrorMode(PXCCapture::Device::MIRROR_MODE_DISABLED);
device->SetIVCAMFilterOption(6);
}
_properlyInitialized = true;
}
_config = _handController->CreateActiveConfiguration();
_config->EnableStabilizer(true);
_config->SetTrackingMode(PXCHandData::TRACKING_MODE_FULL_HAND);
_config->ApplyChanges();
#endif // HAVE_RSSDK
}
#ifdef HAVE_RSSDK
glm::quat quatFromPXCPoint4DF32(const PXCPoint4DF32& basis) {
return glm::normalize(glm::quat(basis.w, basis.x, basis.y, basis.z) * glm::quat(glm::vec3(0, M_PI, 0)));
}
glm::vec3 vec3FromPXCPoint3DF32(const PXCPoint3DF32& vec) {
return glm::vec3(-vec.x, vec.y, -vec.z);
}
#endif // HAVE_RSSDK
void RealSense::update() {
#ifdef HAVE_RSSDK
bool wasActive = _active;
_active = _manager->IsConnected() && _properlyInitialized;
if (_active || wasActive) {
// Go through all the joints and increment their counter since last update.
// Increment all counters once after controller first becomes inactive so that each joint reports itself as inactive.
// TODO C++11 for (auto jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++) {
for (JointTracker::Vector::iterator jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++) {
(*jointIt).tickNewFrame();
}
}
if (!_active) {
return;
}
pxcStatus sts = _manager->AcquireFrame(true);
_handData->Update();
PXCHandData::JointData nodes[2][PXCHandData::NUMBER_OF_JOINTS] = {};
PXCHandData::ExtremityData extremitiesPointsNodes[2][PXCHandData::NUMBER_OF_EXTREMITIES] = {};
for (pxcI32 i = 0; i < _handData->QueryNumberOfHands(); i++) {
PXCHandData::IHand* handData;
if (_handData->QueryHandData(PXCHandData::ACCESS_ORDER_BY_TIME, i, handData) == PXC_STATUS_NO_ERROR) {
int rightSide = handData->QueryBodySide() == PXCHandData::BODY_SIDE_RIGHT;
PXCHandData::JointData jointData;
JointTracker* parentJointTracker = _jointsArray.data();
//Iterate Joints
int rootBranchIndex = -1;
JointTracker* palmJoint = NULL;
for (int j = 0; j < PXCHandData::NUMBER_OF_JOINTS; j++) {
handData->QueryTrackedJoint((PXCHandData::JointType)j, jointData);
nodes[i][j] = jointData;
if (j == PXCHandData::JOINT_WRIST) {
JointTracker* wrist = editJointTracker(evalRealSenseJointIndex(rightSide, rootBranchIndex, 1)); // 1 is the index of the wrist joint
wrist->editAbsFrame().setTranslation(vec3FromPXCPoint3DF32(jointData.positionWorld));
wrist->editAbsFrame().setRotation(quatFromPXCPoint4DF32(jointData.globalOrientation));
wrist->updateLocFromAbsTransform(parentJointTracker);
wrist->activeFrame();
parentJointTracker = wrist;
continue;
} else if (j == PXCHandData::JOINT_CENTER) {
palmJoint = editJointTracker(evalRealSenseJointIndex(rightSide, rootBranchIndex, 0)); // 0 is the index of the palm joint
palmJoint->editAbsFrame().setTranslation(vec3FromPXCPoint3DF32(jointData.positionWorld));
palmJoint->editAbsFrame().setRotation(quatFromPXCPoint4DF32(jointData.globalOrientation));
palmJoint->updateLocFromAbsTransform(parentJointTracker);
palmJoint->activeFrame();
parentJointTracker = palmJoint;
continue;
}
int finger_index = j - PALMROOT_NUM_JOINTS;
int finger = finger_index / FINGER_NUM_JOINTS;
int finger_bone = finger_index % FINGER_NUM_JOINTS;
JointTracker* ljointTracker = editJointTracker(evalRealSenseJointIndex(rightSide, finger, finger_bone));
if (jointData.confidence > 0) {
ljointTracker->editAbsFrame().setTranslation(vec3FromPXCPoint3DF32(jointData.positionWorld));
ljointTracker->editAbsFrame().setRotation(quatFromPXCPoint4DF32(jointData.globalOrientation));
ljointTracker->updateLocFromAbsTransform(parentJointTracker);
ljointTracker->activeFrame();
}
if (finger_bone == (FINGER_NUM_JOINTS - 1)) {
parentJointTracker = palmJoint;
continue;
}
parentJointTracker = ljointTracker;
}
}
}
_manager->ReleaseFrame();
#endif // HAVE_RSSDK
}
void RealSense::loadRSSDKFile() {
QString locationDir(QStandardPaths::displayName(QStandardPaths::DesktopLocation));
QString fileNameString = QFileDialog::getOpenFileName(qApp->getWindow(), tr("Open RSSDK clip"),
locationDir,
tr("RSSDK Recordings (*.rssdk)"));
if (!fileNameString.isEmpty()) {
initSession(true, fileNameString);
}
}

View file

@ -1,65 +0,0 @@
//
// RealSense.h
// interface/src/devices
//
// Created by Thijs Wenker on 12/10/14
// Copyright 2014 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_RealSense_h
#define hifi_RealSense_h
#include <QFileDialog>
#include "MotionTracker.h"
#ifdef HAVE_RSSDK
#include <pxcsession.h>
#include <pxchandmodule.h>
#include <pxchandconfiguration.h>
#include <pxcsensemanager.h>
#include <pxchanddata.h>
#endif
/// Handles interaction with the RealSense skeleton tracking suit.
class RealSense : public QObject, public MotionTracker {
Q_OBJECT
public:
static const Name NAME;
static void init();
static void destroy();
/// RealSense MotionTracker factory
static RealSense* getInstance();
bool isActive() const { return _active; }
virtual void update();
public slots:
void loadRSSDKFile();
protected:
RealSense();
virtual ~RealSense();
void initSession(bool playback, QString filename);
private:
#ifdef HAVE_RSSDK
PXCSession* _session;
PXCSenseManager* _manager;
PXCHandModule* _handController;
PXCHandData* _handData;
PXCHandConfiguration* _config;
#endif
bool _properlyInitialized;
bool _active;
};
#endif // hifi_RealSense_h

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);
@ -416,7 +416,7 @@ bool ApplicationCompositor::calculateRayUICollisionPoint(const glm::vec3& positi
glm::vec3 relativeDirection = glm::normalize(inverseOrientation * direction);
float t;
if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getScale(), &t)){
if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getAvatarScale(), &t)){
result = position + direction * t;
return true;
}

View file

@ -188,9 +188,9 @@ void PreferencesDialog::loadPreferences() {
ui.fieldOfViewSpin->setValue(qApp->getFieldOfView());
ui.leanScaleSpin->setValue(myAvatar->getLeanScale());
ui.avatarScaleSpin->setValue(myAvatar->getScale());
ui.avatarAnimationEdit->setText(myAvatar->getAnimGraphUrl());
ui.avatarScaleSpin->setValue(myAvatar->getAvatarScale());
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

@ -533,15 +533,13 @@ bool Overlays::isLoaded(unsigned int id) {
QSizeF Overlays::textSize(unsigned int id, const QString& text) const {
Overlay::Pointer thisOverlay = _overlaysHUD[id];
if (thisOverlay) {
if (typeid(*thisOverlay) == typeid(TextOverlay)) {
return std::dynamic_pointer_cast<TextOverlay>(thisOverlay)->textSize(text);
if (auto textOverlay = std::dynamic_pointer_cast<TextOverlay>(thisOverlay)) {
return textOverlay->textSize(text);
}
} else {
thisOverlay = _overlaysWorld[id];
if (thisOverlay) {
if (typeid(*thisOverlay) == typeid(Text3DOverlay)) {
return std::dynamic_pointer_cast<Text3DOverlay>(thisOverlay)->textSize(text);
}
if (auto text3dOverlay = std::dynamic_pointer_cast<Text3DOverlay>(thisOverlay)) {
return text3dOverlay->textSize(text);
}
}
return QSizeF(0.0f, 0.0f);

View file

@ -68,7 +68,7 @@ namespace render {
glm::vec3 myAvatarPosition = avatar->getPosition();
float angle = glm::degrees(glm::angle(myAvatarRotation));
glm::vec3 axis = glm::axis(myAvatarRotation);
float myAvatarScale = avatar->getScale();
float myAvatarScale = avatar->getAvatarScale();
Transform transform = Transform();
transform.setTranslation(myAvatarPosition);
transform.setRotation(glm::angleAxis(angle, axis));

View file

@ -6,11 +6,6 @@ link_hifi_libraries(audio)
target_include_directories(${TARGET_NAME} PUBLIC "${HIFI_LIBRARY_DIR}/audio/src")
# have CMake grab externals for us
add_dependency_external_projects(gverb)
find_package(Gverb REQUIRED)
target_link_libraries(${TARGET_NAME} ${GVERB_LIBRARIES})
target_include_directories(${TARGET_NAME} PRIVATE ${GVERB_INCLUDE_DIRS})
if (APPLE)
find_library(CoreAudio CoreAudio)
find_library(CoreFoundation CoreFoundation)

View file

@ -34,6 +34,7 @@ inline static int MULHI(int a, int b) {
#endif
static const float PHI = 0.6180339887f; // maximum allpass diffusion
static const float TWOPI = 6.283185307f;
static const double PI = 3.14159265358979323846;
static const double SQRT2 = 1.41421356237309504880;
@ -383,7 +384,7 @@ static void BQPeakAbovePi(double coef[5], double w0, double dbgain, double Q) {
// Biquad Peaking EQ using analog matching.
// Supports full range of w0.
//
static void BQPeak(double coef[5], double w0, double dbgain, double Q) {
void BQPeak(double coef[5], double w0, double dbgain, double Q) {
w0 = MAX(w0, 0.0); // allow w0 > pi
Q = MIN(MAX(Q, 1.0e-6), 1.0e+6);
@ -402,7 +403,7 @@ static void BQPeak(double coef[5], double w0, double dbgain, double Q) {
//
// Biquad Shelf using analog matching.
//
static void BQShelf(double coef[5], double w0, double dbgain, double resonance, int isHigh) {
void BQShelf(double coef[5], double w0, double dbgain, double resonance, int isHigh) {
double G, G1;
double wpi, wn, wd;
double wna, wda;
@ -499,7 +500,7 @@ static void BQShelf(double coef[5], double w0, double dbgain, double resonance,
// Biquad Lowpass/Highpass using analog matching.
// Q = sqrt(0.5) = 2nd order Butterworth
//
static void BQFilter(double coef[5], double w0, int isHigh) {
void BQFilter(double coef[5], double w0, int isHigh) {
double G1;
double wpi, wn, wd;
double wna, wda;
@ -587,7 +588,7 @@ static void BQFilter(double coef[5], double w0, int isHigh) {
// PoleZero Shelf. For Lowpass/Highpass, setCoef dbgain to -100dB.
// NOTE: w0 always sets the pole frequency (3dB corner from unity gain)
//
static void PZShelf(double coef[3], double w0, double dbgain, int isHigh) {
void PZShelf(double coef[3], double w0, double dbgain, int isHigh) {
double G, G0, G1;
double b0, b1, a0, a1;
double temp, scale;
@ -653,7 +654,7 @@ public:
// lowpass filter, -3dB @ freq
double coef[5];
BQFilter(coef, PI * freq / (0.5 * sampleRate), 0);
BQFilter(coef, TWOPI * freq / sampleRate, 0);
_b0 = (float)coef[0];
_b1 = (float)coef[1];
_b2 = (float)coef[2];
@ -661,7 +662,7 @@ public:
_a2 = (float)coef[4];
// DC-blocking filter, -3dB @ 10Hz
_alpha = (float)(1.0 - exp(-PI * 10.0 / (0.5 * sampleRate)));
_alpha = 1.0f - expf(-TWOPI * 10.0f / sampleRate);
}
void process(float input0, float input1, float& output0, float& output1) {
@ -807,11 +808,13 @@ public:
freq = MIN(freq, 1/16.0f * sampleRate);
freq = MAX(freq, 1/16777216.0f * sampleRate);
// amplitude slightly less than 1.0
_y0 = (int32_t)(0.000 * FIXQ31);
_y1 = (int32_t)(0.999 * cos(PI * freq / sampleRate) * FIXQ31);
double w = PI * (double)freq / (double)sampleRate;
_k = (int32_t)(2.0 * sin(PI * freq / sampleRate) * FIXQ32);
// amplitude slightly less than 1.0
_y0 = 0;
_y1 = (int32_t)(0.999 * cos(w) * FIXQ31);
_k = (int32_t)(2.0 * sin(w) * FIXQ32);
}
void setGain(int32_t gain) {
@ -985,8 +988,8 @@ public:
freq1 = MIN(MAX(freq1, 1.0f), 24000.0f);
double coefLo[3], coefHi[3];
PZShelf(coefLo, PI * freq0 / (0.5 * sampleRate), dBgain0, 0); // low shelf
PZShelf(coefHi, PI * freq1 / (0.5 * sampleRate), dBgain1, 1); // high shelf
PZShelf(coefLo, TWOPI * freq0 / sampleRate, dBgain0, 0); // low shelf
PZShelf(coefHi, TWOPI * freq1 / sampleRate, dBgain1, 1); // high shelf
// convolve into a single biquad
_b0 = (float)(coefLo[0] * coefHi[0]);
@ -1324,64 +1327,64 @@ static int scaleDelay(float delay, float sampleRate) {
// input clamped to [0.0f, 100.0f]
//
static const float earlyMix0Table[][2] = {
0.0000f, 0.6000f,
63.3333f, 0.0800f,
83.3333f, 0.0200f,
93.3333f, 0.0048f,
100.0000f, 0.0048f,
{0.0000f, 0.6000f},
{63.3333f, 0.0800f},
{83.3333f, 0.0200f},
{93.3333f, 0.0048f},
{100.0000f, 0.0048f},
};
static const float earlyMix1Table[][2] = {
0.0000f, 0.3360f,
20.0000f, 0.6000f,
100.0000f, 0.0240f,
{0.0000f, 0.3360f},
{20.0000f, 0.6000f},
{100.0000f, 0.0240f},
};
static const float earlyMix2Table[][2] = {
0.0000f, 0.0480f,
13.3333f, 0.0960f,
53.3333f, 0.9600f,
100.0000f, 0.1200f,
{0.0000f, 0.0480f},
{13.3333f, 0.0960f},
{53.3333f, 0.9600f},
{100.0000f, 0.1200f},
};
static const float lateMix0Table[][2] = {
0.0000f, 0.1250f,
13.3333f, 0.1875f,
66.6666f, 0.7500f,
100.0000f, 0.8750f,
{0.0000f, 0.1250f},
{13.3333f, 0.1875f},
{66.6666f, 0.7500f},
{100.0000f, 0.8750f},
};
static const float lateMix1Table[][2] = {
0.0000f, 0.9990f,
33.3333f, 0.5000f,
66.6666f, 0.9990f,
93.3333f, 0.6000f,
100.0000f, 0.6000f,
{0.0000f, 0.9990f},
{33.3333f, 0.5000f},
{66.6666f, 0.9990f},
{93.3333f, 0.6000f},
{100.0000f, 0.6000f},
};
static const float lateMix2Table[][2] = {
0.0000f, 0.9990f,
33.3333f, 0.9990f,
63.3333f, 0.4500f,
100.0000f, 0.9990f,
{0.0000f, 0.9990f},
{33.3333f, 0.9990f},
{63.3333f, 0.4500f},
{100.0000f, 0.9990f},
};
static const float diffusionCoefTable[][2] = {
0.0000f, 0.0000f,
20.0000f, 0.0470f,
33.3333f, 0.0938f,
46.6666f, 0.1563f,
60.0000f, 0.2344f,
73.3333f, 0.3125f,
93.3333f, 0.5000f,
100.0000f, PHI,
{0.0000f, 0.0000f},
{20.0000f, 0.0470f},
{33.3333f, 0.0938f},
{46.6666f, 0.1563f},
{60.0000f, 0.2344f},
{73.3333f, 0.3125f},
{93.3333f, 0.5000f},
{100.0000f, PHI},
};
static const float roomSizeTable[][2] = {
0.0000f, 0.1500f,
25.0000f, 0.3000f,
50.0000f, 0.5000f,
100.0000f, 1.0000f,
{0.0000f, 0.1500f},
{25.0000f, 0.3000f},
{50.0000f, 0.5000f},
{100.0000f, 1.0000f},
};
static float interpolateTable(const float table[][2], float x) {
@ -1407,7 +1410,7 @@ void ReverbImpl::setParameters(ReverbParameters *p) {
// Modulation
_lfo.setFreq(p->modRate, sampleRate);
_lfo.setGain((int32_t)MIN(MAX(p->modDepth * (1/100.0) * FIXQ31, 0.0), 0X7fffffff));
_lfo.setGain((int32_t)MIN(MAX((double)p->modDepth * (1/100.0) * FIXQ31, 0.0), (double)0x7fffffff));
//
// Set delays

View file

@ -47,13 +47,8 @@ const QString AvatarData::FRAME_NAME = "com.highfidelity.recording.AvatarData";
static std::once_flag frameTypeRegistration;
AvatarData::AvatarData() :
_sessionUUID(),
_position(0.0f),
SpatiallyNestable(NestableTypes::Avatar, QUuid()),
_handPosition(0.0f),
_referential(NULL),
_bodyYaw(-90.0f),
_bodyPitch(0.0f),
_bodyRoll(0.0f),
_targetScale(1.0f),
_handState(0),
_keyState(NO_KEY_DOWN),
@ -72,12 +67,14 @@ AvatarData::AvatarData() :
_targetVelocity(0.0f),
_localAABox(DEFAULT_LOCAL_AABOX_CORNER, DEFAULT_LOCAL_AABOX_SCALE)
{
setBodyPitch(0.0f);
setBodyYaw(-90.0f);
setBodyRoll(0.0f);
}
AvatarData::~AvatarData() {
delete _headData;
delete _handData;
delete _referential;
}
// We cannot have a file-level variable (const or otherwise) in the header if it uses PathUtils, because that references Application, which will not yet initialized.
@ -90,49 +87,18 @@ const QUrl& AvatarData::defaultFullAvatarModelUrl() {
return _defaultFullAvatarModelUrl;
}
const glm::vec3& AvatarData::getPosition() const {
if (_referential) {
_referential->update();
}
return _position;
}
void AvatarData::setPosition(const glm::vec3 position, bool overideReferential) {
if (!_referential || overideReferential) {
_position = position;
}
}
glm::quat AvatarData::getOrientation() const {
if (_referential) {
_referential->update();
}
return glm::quat(glm::radians(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll)));
}
void AvatarData::setOrientation(const glm::quat& orientation, bool overideReferential) {
if (!_referential || overideReferential) {
glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(orientation));
_bodyPitch = eulerAngles.x;
_bodyYaw = eulerAngles.y;
_bodyRoll = eulerAngles.z;
}
}
// There are a number of possible strategies for this set of tools through endRender, below.
void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) {
avatarLock.lock();
setPosition(position, true);
setOrientation(orientation, true);
Transform trans;
trans.setTranslation(position);
trans.setRotation(orientation);
SpatiallyNestable::setTransform(trans);
avatarLock.unlock();
updateAttitude();
}
void AvatarData::startCapture() {
avatarLock.lock();
assert(_nextAllowed);
_nextAllowed = false;
_nextPosition = getPosition();
_nextOrientation = getOrientation();
}
void AvatarData::endCapture() {
avatarLock.unlock();
@ -145,57 +111,42 @@ void AvatarData::endUpdate() {
}
void AvatarData::startRenderRun() {
// I'd like to get rid of this and just (un)lock at (end-)startRender.
// But somehow that causes judder in rotations.
// But somehow that causes judder in rotations.
avatarLock.lock();
}
void AvatarData::endRenderRun() {
avatarLock.unlock();
}
void AvatarData::startRender() {
glm::vec3 pos = getPosition();
glm::quat rot = getOrientation();
setPosition(_nextPosition, true);
setOrientation(_nextOrientation, true);
updateAttitude();
_nextPosition = pos;
_nextOrientation = rot;
}
void AvatarData::endRender() {
setPosition(_nextPosition, true);
setOrientation(_nextOrientation, true);
updateAttitude();
_nextAllowed = true;
}
float AvatarData::getTargetScale() const {
if (_referential) {
_referential->update();
}
return _targetScale;
}
void AvatarData::setTargetScale(float targetScale, bool overideReferential) {
if (!_referential || overideReferential) {
_targetScale = std::max(MIN_AVATAR_SCALE, std::min(MAX_AVATAR_SCALE, targetScale));
}
void AvatarData::setTargetScale(float targetScale) {
_targetScale = std::max(MIN_AVATAR_SCALE, std::min(MAX_AVATAR_SCALE, targetScale));
}
void AvatarData::setClampedTargetScale(float targetScale, bool overideReferential) {
void AvatarData::setClampedTargetScale(float targetScale) {
targetScale = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE);
setTargetScale(targetScale, overideReferential);
setTargetScale(targetScale);
qCDebug(avatars) << "Changed scale to " << _targetScale;
}
glm::vec3 AvatarData::getHandPosition() const {
return getOrientation() * _handPosition + _position;
return getOrientation() * _handPosition + getPosition();
}
void AvatarData::setHandPosition(const glm::vec3& handPosition) {
// store relative to position/orientation
_handPosition = glm::inverse(getOrientation()) * (handPosition - _position);
_handPosition = glm::inverse(getOrientation()) * (handPosition - getPosition());
}
QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) {
@ -216,13 +167,18 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) {
unsigned char* destinationBuffer = reinterpret_cast<unsigned char*>(avatarDataByteArray.data());
unsigned char* startPosition = destinationBuffer;
memcpy(destinationBuffer, &_position, sizeof(_position));
destinationBuffer += sizeof(_position);
const glm::vec3& position = getLocalPosition();
memcpy(destinationBuffer, &position, sizeof(position));
destinationBuffer += sizeof(position);
// Body rotation (NOTE: This needs to become a quaternion to save two bytes)
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _bodyYaw);
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _bodyPitch);
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _bodyRoll);
memcpy(destinationBuffer, &_globalPosition, sizeof(_globalPosition));
destinationBuffer += sizeof(_globalPosition);
// Body rotation
glm::vec3 bodyEulerAngles = glm::degrees(safeEulerAngles(getLocalOrientation()));
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, bodyEulerAngles.y);
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, bodyEulerAngles.x);
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, bodyEulerAngles.z);
// Body scale
destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _targetScale);
@ -255,14 +211,18 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) {
setAtBit(bitItems, IS_EYE_TRACKER_CONNECTED);
}
// referential state
if (_referential != NULL && _referential->isValid()) {
SpatiallyNestablePointer parent = getParentPointer();
if (parent) {
setAtBit(bitItems, HAS_REFERENTIAL);
}
*destinationBuffer++ = bitItems;
// Add referential
if (_referential != NULL && _referential->isValid()) {
destinationBuffer += _referential->packReferential(destinationBuffer);
if (parent) {
QByteArray referentialAsBytes = parent->getID().toRfc4122();
memcpy(destinationBuffer, referentialAsBytes.data(), referentialAsBytes.size());
destinationBuffer += referentialAsBytes.size();
memcpy(destinationBuffer, &_parentJointIndex, sizeof(_parentJointIndex));
destinationBuffer += sizeof(_parentJointIndex);
}
// If it is connected, pack up the data
@ -496,13 +456,16 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
memcpy(&position, sourceBuffer, sizeof(position));
sourceBuffer += sizeof(position);
memcpy(&_globalPosition, sourceBuffer, sizeof(_globalPosition));
sourceBuffer += sizeof(_globalPosition);
if (glm::isnan(position.x) || glm::isnan(position.y) || glm::isnan(position.z)) {
if (shouldLogError(now)) {
qCDebug(avatars) << "Discard nan AvatarData::position; displayName = '" << _displayName << "'";
}
return maxAvailableSize;
}
setPosition(position);
setLocalPosition(position);
// rotation (NOTE: This needs to become a quaternion to save two bytes)
float yaw, pitch, roll;
@ -515,11 +478,18 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
}
return maxAvailableSize;
}
if (_bodyYaw != yaw || _bodyPitch != pitch || _bodyRoll != roll) {
// TODO is this safe? will the floats not exactly match?
// Andrew says:
// Yes, there is a possibility that the transmitted will not quite match the extracted despite being originally
// extracted from the exact same quaternion. I followed the code through and it appears the risk is that the
// avatar's SkeletonModel might fall into the CPU expensive part of Model::updateClusterMatrices() when otherwise it
// would not have required it. However, we know we can update many simultaneously animating avatars, and most
// avatars will be moving constantly anyway, so I don't think we need to worry.
if (getBodyYaw() != yaw || getBodyPitch() != pitch || getBodyRoll() != roll) {
_hasNewJointRotations = true;
_bodyYaw = yaw;
_bodyPitch = pitch;
_bodyRoll = roll;
glm::vec3 eulerAngles(pitch, yaw, roll);
setLocalOrientation(glm::quat(glm::radians(eulerAngles)));
}
// scale
@ -581,21 +551,17 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
_headData->_isEyeTrackerConnected = oneAtBit(bitItems, IS_EYE_TRACKER_CONNECTED);
bool hasReferential = oneAtBit(bitItems, HAS_REFERENTIAL);
// Referential
if (hasReferential) {
Referential* ref = new Referential(sourceBuffer, this);
if (_referential == NULL ||
ref->version() != _referential->version()) {
changeReferential(ref);
} else {
delete ref;
}
_referential->update();
} else if (_referential != NULL) {
changeReferential(NULL);
const int sizeOfPackedUuid = 16;
QByteArray referentialAsBytes((const char*)sourceBuffer, sizeOfPackedUuid);
_parentID = QUuid::fromRfc4122(referentialAsBytes);
sourceBuffer += sizeOfPackedUuid;
memcpy(&_parentJointIndex, sourceBuffer, sizeof(_parentJointIndex));
sourceBuffer += sizeof(_parentJointIndex);
} else {
_parentID = QUuid();
}
if (_headData->_isFaceTrackerConnected) {
float leftEyeBlink, rightEyeBlink, averageLoudness, browAudioLift;
minPossibleSize += sizeof(leftEyeBlink) + sizeof(rightEyeBlink) + sizeof(averageLoudness) + sizeof(browAudioLift);
@ -788,19 +754,10 @@ int AvatarData::getReceiveRate() const {
return lrint(1.0f / _averageBytesReceived.getEventDeltaAverage());
}
bool AvatarData::hasReferential() {
return _referential != NULL;
}
std::shared_ptr<Transform> AvatarData::getRecordingBasis() const {
return _recordingBasis;
}
void AvatarData::changeReferential(Referential* ref) {
delete _referential;
_referential = ref;
}
void AvatarData::setRawJointData(QVector<JointData> data) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setRawJointData", Q_ARG(QVector<JointData>, data));
@ -1437,14 +1394,6 @@ void AvatarData::clearRecordingBasis() {
_recordingBasis.reset();
}
Transform AvatarData::getTransform() const {
Transform result;
result.setRotation(getOrientation());
result.setTranslation(getPosition());
result.setScale(getTargetScale());
return result;
}
static const QString JSON_AVATAR_BASIS = QStringLiteral("basisTransform");
static const QString JSON_AVATAR_RELATIVE = QStringLiteral("relativeTransform");
static const QString JSON_AVATAR_JOINT_ARRAY = QStringLiteral("jointArray");
@ -1495,15 +1444,17 @@ QJsonObject AvatarData::toJson() const {
}
auto recordingBasis = getRecordingBasis();
Transform avatarTransform = getTransform();
avatarTransform.setScale(getTargetScale());
if (recordingBasis) {
root[JSON_AVATAR_BASIS] = Transform::toJson(*recordingBasis);
// Find the relative transform
auto relativeTransform = recordingBasis->relativeTransform(getTransform());
auto relativeTransform = recordingBasis->relativeTransform(avatarTransform);
if (!relativeTransform.isIdentity()) {
root[JSON_AVATAR_RELATIVE] = Transform::toJson(relativeTransform);
}
} else {
root[JSON_AVATAR_RELATIVE] = Transform::toJson(getTransform());
root[JSON_AVATAR_RELATIVE] = Transform::toJson(avatarTransform);
}
auto scale = getTargetScale();
@ -1641,3 +1592,44 @@ void AvatarData::fromFrame(const QByteArray& frameData, AvatarData& result) {
#endif
result.fromJson(doc.object());
}
float AvatarData::getBodyYaw() const {
glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation()));
return eulerAngles.y;
}
void AvatarData::setBodyYaw(float bodyYaw) {
glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation()));
eulerAngles.y = bodyYaw;
setOrientation(glm::quat(glm::radians(eulerAngles)));
}
float AvatarData::getBodyPitch() const {
glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation()));
return eulerAngles.x;
}
void AvatarData::setBodyPitch(float bodyPitch) {
glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation()));
eulerAngles.x = bodyPitch;
setOrientation(glm::quat(glm::radians(eulerAngles)));
}
float AvatarData::getBodyRoll() const {
glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation()));
return eulerAngles.z;
}
void AvatarData::setBodyRoll(float bodyRoll) {
glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation()));
eulerAngles.z = bodyRoll;
setOrientation(glm::quat(glm::radians(eulerAngles)));
}
void AvatarData::setPosition(const glm::vec3 position) {
SpatiallyNestable::setPosition(position);
}
void AvatarData::setOrientation(const glm::quat orientation) {
SpatiallyNestable::setOrientation(orientation);
}

View file

@ -51,12 +51,12 @@ typedef unsigned long long quint64;
#include <Node.h>
#include <RegisteredMetaTypes.h>
#include <SimpleMovingAverage.h>
#include <SpatiallyNestable.h>
#include "AABox.h"
#include "HandData.h"
#include "HeadData.h"
#include "PathUtils.h"
#include "Referential.h"
using AvatarSharedPointer = std::shared_ptr<AvatarData>;
using AvatarWeakPointer = std::weak_ptr<AvatarData>;
@ -135,7 +135,7 @@ class AttachmentData;
class Transform;
using TransformPointer = std::shared_ptr<Transform>;
class AvatarData : public QObject {
class AvatarData : public QObject, public SpatiallyNestable {
Q_OBJECT
Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition)
@ -177,10 +177,7 @@ public:
virtual bool isMyAvatar() const { return false; }
const QUuid& getSessionUUID() const { return _sessionUUID; }
const glm::vec3& getPosition() const;
virtual void setPosition(const glm::vec3 position, bool overideReferential = false);
const QUuid& getSessionUUID() const { return getID(); }
glm::vec3 getHandPosition() const;
void setHandPosition(const glm::vec3& handPosition);
@ -196,16 +193,16 @@ public:
/// \return number of bytes parsed
virtual int parseDataFromBuffer(const QByteArray& buffer);
// Body Rotation (degrees)
float getBodyYaw() const { return _bodyYaw; }
void setBodyYaw(float bodyYaw) { _bodyYaw = bodyYaw; }
float getBodyPitch() const { return _bodyPitch; }
void setBodyPitch(float bodyPitch) { _bodyPitch = bodyPitch; }
float getBodyRoll() const { return _bodyRoll; }
void setBodyRoll(float bodyRoll) { _bodyRoll = bodyRoll; }
// Body Rotation (degrees)
float getBodyYaw() const;
void setBodyYaw(float bodyYaw);
float getBodyPitch() const;
void setBodyPitch(float bodyPitch);
float getBodyRoll() const;
void setBodyRoll(float bodyRoll);
glm::quat getOrientation() const;
virtual void setOrientation(const glm::quat& orientation, bool overideReferential = false);
virtual void setPosition(glm::vec3 position);
virtual void setOrientation(glm::quat orientation);
void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time.
void startCapture(); // start/end of the period in which the latest values are about to be captured for camera, etc.
@ -239,8 +236,8 @@ public:
// Scale
float getTargetScale() const;
void setTargetScale(float targetScale, bool overideReferential = false);
void setClampedTargetScale(float targetScale, bool overideReferential = false);
void setTargetScale(float targetScale);
void setClampedTargetScale(float targetScale);
// Hand State
Q_INVOKABLE void setHandState(char s) { _handState = s; }
@ -326,7 +323,6 @@ public:
void setOwningAvatarMixer(const QWeakPointer<Node>& owningAvatarMixer) { _owningAvatarMixer = owningAvatarMixer; }
const AABox& getLocalAABox() const { return _localAABox; }
const Referential* getReferential() const { return _referential; }
int getUsecsSinceLastUpdate() const { return _averageBytesReceived.getUsecsSinceLastEvent(); }
int getAverageBytesReceivedPerSecond() const;
@ -338,13 +334,14 @@ public:
bool shouldDie() const { return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS; }
Transform getTransform() const;
void clearRecordingBasis();
TransformPointer getRecordingBasis() const;
void setRecordingBasis(TransformPointer recordingBasis = TransformPointer());
QJsonObject toJson() const;
void fromJson(const QJsonObject& json);
glm::vec3 getClientGlobalPosition() { return _globalPosition; }
public slots:
void sendAvatarDataPacket();
void sendIdentityPacket();
@ -352,24 +349,10 @@ public slots:
void setBillboardFromNetworkReply();
void setJointMappingsFromNetworkReply();
void setSessionUUID(const QUuid& sessionUUID) { _sessionUUID = sessionUUID; }
bool hasReferential();
void setSessionUUID(const QUuid& sessionUUID) { setID(sessionUUID); }
protected:
QUuid _sessionUUID;
glm::vec3 _position = START_LOCATION;
glm::vec3 _handPosition;
Referential* _referential;
// Body rotation
float _bodyYaw; // degrees
float _bodyPitch; // degrees
float _bodyRoll; // degrees
glm::vec3 _nextPosition {};
glm::quat _nextOrientation {};
bool _nextAllowed {true};
// Body scale
float _targetScale;
@ -411,7 +394,6 @@ protected:
/// Loads the joint indices, names from the FST file (if any)
virtual void updateJointMappings();
void changeReferential(Referential* ref);
glm::vec3 _velocity;
glm::vec3 _targetVelocity;
@ -426,6 +408,11 @@ protected:
// During playback, it holds the origin from which to play the relative positions in the clip
TransformPointer _recordingBasis;
// _globalPosition is sent along with localPosition + parent because the avatar-mixer doesn't know
// where Entities are located. This is currently only used by the mixer to decide how often to send
// updates about one avatar to another.
glm::vec3 _globalPosition;
private:
friend void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar);
static QUrl _defaultFullAvatarModelUrl;

View file

@ -65,7 +65,10 @@ AvatarSharedPointer AvatarHashMap::newOrExistingAvatar(const QUuid& sessionUUID,
AvatarSharedPointer AvatarHashMap::findAvatar(const QUuid& sessionUUID) {
QReadLocker locker(&_hashLock);
return _avatarHash.value(sessionUUID);
if (_avatarHash.contains(sessionUUID)) {
return _avatarHash.value(sessionUUID);
}
return nullptr;
}
void AvatarHashMap::processAvatarDataPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {

View file

@ -1,109 +0,0 @@
//
// Referential.cpp
//
//
// Created by Clement on 7/30/14.
// Copyright 2014 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 <GLMHelpers.h>
#include "AvatarData.h"
#include "AvatarLogging.h"
#include "Referential.h"
Referential::Referential(Type type, AvatarData* avatar) :
_type(type),
_version(0),
_isValid(true),
_avatar(avatar)
{
if (_avatar == NULL) {
_isValid = false;
return;
}
if (_avatar->hasReferential()) {
_version = _avatar->getReferential()->version() + 1;
}
}
Referential::Referential(const unsigned char*& sourceBuffer, AvatarData* avatar) :
_isValid(false),
_avatar(avatar)
{
// Since we can't return how many byte have been read
// We take a reference to the pointer as argument and increment the pointer ouself.
sourceBuffer += unpackReferential(sourceBuffer);
// The actual unpacking to the right referential type happens in Avatar::simulate()
// If subclassed, make sure to add a case there to unpack the new referential type correctly
}
Referential::~Referential() {
}
int Referential::packReferential(unsigned char* destinationBuffer) const {
const unsigned char* startPosition = destinationBuffer;
destinationBuffer += pack(destinationBuffer);
unsigned char* sizePosition = destinationBuffer++; // Save a spot for the extra data size
char size = packExtraData(destinationBuffer);
*sizePosition = size; // write extra data size in saved spot here
destinationBuffer += size;
return destinationBuffer - startPosition;
}
int Referential::unpackReferential(const unsigned char* sourceBuffer) {
const unsigned char* startPosition = sourceBuffer;
sourceBuffer += unpack(sourceBuffer);
char expectedSize = *sourceBuffer++;
char bytesRead = unpackExtraData(sourceBuffer, expectedSize);
_isValid = (bytesRead == expectedSize);
if (!_isValid) {
// Will occur if the new instance unpacking is of the wrong type
qCDebug(avatars) << "[ERROR] Referential extra data overflow";
}
sourceBuffer += expectedSize;
return sourceBuffer - startPosition;
}
int Referential::pack(unsigned char* destinationBuffer) const {
unsigned char* startPosition = destinationBuffer;
*destinationBuffer++ = (unsigned char)_type;
memcpy(destinationBuffer, &_version, sizeof(_version));
destinationBuffer += sizeof(_version);
destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, _translation, 0);
destinationBuffer += packOrientationQuatToBytes(destinationBuffer, _rotation);
return destinationBuffer - startPosition;
}
int Referential::unpack(const unsigned char* sourceBuffer) {
const unsigned char* startPosition = sourceBuffer;
_type = (Type)*sourceBuffer++;
if (_type < 0 || _type >= NUM_TYPES) {
_type = UNKNOWN;
}
memcpy(&_version, sourceBuffer, sizeof(_version));
sourceBuffer += sizeof(_version);
sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, _translation, 0);
sourceBuffer += unpackOrientationQuatFromBytes(sourceBuffer, _rotation);
return sourceBuffer - startPosition;
}
int Referential::packExtraData(unsigned char *destinationBuffer) const {
// Since we can't interpret that data, just store it in a buffer for later use.
memcpy(destinationBuffer, _extraDataBuffer.data(), _extraDataBuffer.size());
return _extraDataBuffer.size();
}
int Referential::unpackExtraData(const unsigned char* sourceBuffer, int size) {
_extraDataBuffer.clear();
_extraDataBuffer.append(reinterpret_cast<const char*>(sourceBuffer), size);
return size;
}

View file

@ -1,73 +0,0 @@
//
// Referential.h
//
//
// Created by Clement on 7/30/14.
// Copyright 2014 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_Referential_h
#define hifi_Referential_h
#include <glm/gtx/quaternion.hpp>
#include <glm/vec3.hpp>
class AvatarData;
/// Stores and enforce the relative position of an avatar to a given referential (ie. model, joint, ...)
class Referential {
public:
enum Type {
UNKNOWN,
MODEL,
JOINT,
AVATAR,
NUM_TYPES
};
Referential(const unsigned char*& sourceBuffer, AvatarData* avatar);
virtual ~Referential();
Type type() const { return _type; }
quint8 version() const { return _version; }
bool isValid() const { return _isValid; }
bool hasExtraData() const { return !_extraDataBuffer.isEmpty(); }
glm::vec3 getTranslation() const { return _translation; }
glm::quat getRotation() const { return _rotation; }
QByteArray getExtraData() const { return _extraDataBuffer; }
virtual void update() {}
int packReferential(unsigned char* destinationBuffer) const;
int unpackReferential(const unsigned char* sourceBuffer);
protected:
Referential(Type type, AvatarData* avatar);
// packs the base class data
int pack(unsigned char* destinationBuffer) const;
int unpack(const unsigned char* sourceBuffer);
// virtual functions that pack fthe extra data of subclasses (needs to be reimplemented in subclass)
virtual int packExtraData(unsigned char* destinationBuffer) const;
virtual int unpackExtraData(const unsigned char* sourceBuffer, int size);
Type _type;
quint8 _version;
bool _isValid;
AvatarData* _avatar;
QByteArray _extraDataBuffer;
glm::vec3 _refPosition; // position of object in world-frame
glm::quat _refRotation; // rotation of object in world-frame
glm::vec3 _lastRefDimension; // dimension of object when _translation was last computed
glm::vec3 _translation; // offset of avatar in object local-frame
glm::quat _rotation; // rotation of avatar in object local-frame
};
#endif // hifi_Referential_h

View file

@ -23,10 +23,10 @@ class ActionEndpoint : public Endpoint {
public:
ActionEndpoint(const Input& id = Input::INVALID_INPUT) : Endpoint(id) { }
virtual float peek() const { return _currentValue; }
virtual float peek() const override { return _currentValue; }
virtual void apply(float newValue, const Pointer& source) override;
virtual Pose peekPose() const { return _currentPose; }
virtual Pose peekPose() const override { return _currentPose; }
virtual void apply(const Pose& value, const Pointer& source) override;
virtual void reset() override;

View file

@ -28,9 +28,9 @@ public:
virtual Pose pose() override;
virtual void apply(const Pose& value, const Pointer& source) override { }
virtual bool writeable() const { return false; }
virtual bool readable() const { return !_read; }
virtual void reset() { _read = false; }
virtual bool writeable() const override { return false; }
virtual bool readable() const override { return !_read; }
virtual void reset() override { _read = false; }
private:
bool _read { false };

View file

@ -23,7 +23,7 @@ public:
virtual float apply(float value) const override;
virtual bool parseParameters(const QJsonValue& parameters);
virtual bool parseParameters(const QJsonValue& parameters) override;
private:
static const float DEFAULT_LAST_EMIT_TIME;

View file

@ -23,7 +23,7 @@ public:
virtual float apply(float value) const override {
return value * _scale;
}
virtual bool parseParameters(const QJsonValue& parameters);
virtual bool parseParameters(const QJsonValue& parameters) override;
private:
float _scale = 1.0f;

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();
}
#define THROTTLED_FRAMERATE 15
int Basic2DWindowOpenGLDisplayPlugin::getDesiredInterval() const {
static const int ULIMIITED_PAINT_TIMER_DELAY_MS = 1;

View file

@ -12,6 +12,8 @@
#define TARGET_FRAMERATE_Basic2DWindowOpenGL 60.0f
class QScreen;
class QAction;
class Basic2DWindowOpenGLDisplayPlugin : public WindowOpenGLDisplayPlugin {
Q_OBJECT
@ -22,9 +24,10 @@ public:
virtual float getTargetFramePeriod() override { return _inverseFrameRate; }
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;
virtual bool isVSynchronized() const override;
@ -37,7 +40,10 @@ 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 };
float _inverseFrameRate{ 1.0f }; //seconds
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,75 +6,219 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "OpenGLDisplayPlugin.h"
#include <QOpenGLContext>
#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
@ -119,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() {
@ -152,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,19 +7,11 @@
//
#include "WindowOpenGLDisplayPlugin.h"
#include <QGLWidget>
#include <QOpenGLContext>
#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());
@ -27,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());
@ -41,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() {
@ -53,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

@ -36,13 +36,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

@ -24,7 +24,9 @@
#include "../render-utils/simple_frag.h"
EntityItemPointer RenderableBoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return std::make_shared<RenderableBoxEntityItem>(entityID, properties);
EntityItemPointer entity{ new RenderableBoxEntityItem(entityID) };
entity->setProperties(properties);
return entity;
}
void RenderableBoxEntityItem::setUserData(const QString& value) {

View file

@ -20,10 +20,7 @@
class RenderableBoxEntityItem : public BoxEntityItem {
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableBoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
BoxEntityItem(entityItemID, properties)
{ }
RenderableBoxEntityItem(const EntityItemID& entityItemID) : BoxEntityItem(entityItemID) { }
virtual void render(RenderArgs* args);
virtual void setUserData(const QString& value);

View file

@ -20,7 +20,9 @@
#include "RenderableLightEntityItem.h"
EntityItemPointer RenderableLightEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return std::make_shared<RenderableLightEntityItem>(entityID, properties);
EntityItemPointer entity{ new RenderableLightEntityItem(entityID) };
entity->setProperties(properties);
return entity;
}
void RenderableLightEntityItem::render(RenderArgs* args) {

View file

@ -18,10 +18,7 @@
class RenderableLightEntityItem : public LightEntityItem {
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableLightEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
LightEntityItem(entityItemID, properties)
{ }
RenderableLightEntityItem(const EntityItemID& entityItemID) : LightEntityItem(entityItemID) { }
virtual void render(RenderArgs* args);
virtual bool supportsDetailedRayIntersection() const { return true; }

View file

@ -20,7 +20,9 @@
#include "RenderableLineEntityItem.h"
EntityItemPointer RenderableLineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return std::make_shared<RenderableLineEntityItem>(entityID, properties);
EntityItemPointer entity{ new RenderableLineEntityItem(entityID) };
entity->setProperties(properties);
return entity;
}
void RenderableLineEntityItem::updateGeometry() {

View file

@ -19,9 +19,8 @@
class RenderableLineEntityItem : public LineEntityItem {
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
LineEntityItem(entityItemID, properties),
RenderableLineEntityItem(const EntityItemID& entityItemID) :
LineEntityItem(entityItemID),
_lineVerticesID(GeometryCache::UNKNOWN_ID)
{ }

View file

@ -26,13 +26,14 @@
#include "RenderableEntityItem.h"
EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return std::make_shared<RenderableModelEntityItem>(entityID, properties);
EntityItemPointer entity{ new RenderableModelEntityItem(entityID, properties.getDimensionsInitialized()) };
entity->setProperties(properties);
return entity;
}
RenderableModelEntityItem::RenderableModelEntityItem(const EntityItemID& entityItemID,
const EntityItemProperties& properties) :
ModelEntityItem(entityItemID, properties),
_dimensionsInitialized(properties.getDimensionsInitialized())
{
RenderableModelEntityItem::RenderableModelEntityItem(const EntityItemID& entityItemID, bool dimensionsInitialized) :
ModelEntityItem(entityItemID),
_dimensionsInitialized(dimensionsInitialized) {
}
RenderableModelEntityItem::~RenderableModelEntityItem() {
@ -43,7 +44,7 @@ RenderableModelEntityItem::~RenderableModelEntityItem() {
}
}
void RenderableModelEntityItem::setDimensions(const glm::vec3& value) {
void RenderableModelEntityItem::setDimensions(const glm::vec3 value) {
_dimensionsInitialized = true;
ModelEntityItem::setDimensions(value);
}
@ -192,7 +193,7 @@ bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_p
if (_model) {
render::Item::Status::Getters statusGetters;
makeEntityItemStatusGetters(shared_from_this(), statusGetters);
makeEntityItemStatusGetters(getThisPointer(), statusGetters);
// note: we don't care if the model fails to add items, we always added our meta item and therefore we return
// true so that the system knows our meta item is in the scene!
@ -238,7 +239,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
_model->removeFromScene(scene, pendingChanges);
render::Item::Status::Getters statusGetters;
makeEntityItemStatusGetters(shared_from_this(), statusGetters);
makeEntityItemStatusGetters(getThisPointer(), statusGetters);
_model->addToScene(scene, pendingChanges, statusGetters, _showCollisionHull);
scene->enqueuePendingChanges(pendingChanges);
@ -563,3 +564,23 @@ bool RenderableModelEntityItem::contains(const glm::vec3& point) const {
return false;
}
glm::quat RenderableModelEntityItem::getJointRotation(int index) const {
if (_model) {
glm::quat result;
if (_model->getJointRotation(index, result)) {
return result;
}
}
return glm::quat();
}
glm::vec3 RenderableModelEntityItem::getJointTranslation(int index) const {
if (_model) {
glm::vec3 result;
if (_model->getJointTranslation(index, result)) {
return result;
}
}
return glm::vec3(0.0f);
}

View file

@ -24,48 +24,52 @@ class RenderableModelEntityItem : public ModelEntityItem {
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
RenderableModelEntityItem(const EntityItemID& entityItemID, bool dimensionsInitialized);
virtual ~RenderableModelEntityItem();
virtual void setDimensions(const glm::vec3& value) override;
virtual void setDimensions(const glm::vec3 value) override;
virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const;
virtual bool setProperties(const EntityItemProperties& properties);
virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override;
virtual bool setProperties(const EntityItemProperties& properties) override;
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged);
bool& somethingChanged) override;
virtual void somethingChangedNotification() {
virtual void somethingChangedNotification() override {
// FIX ME: this is overly aggressive. We only really need to simulate() if something about
// the world space transform has changed and/or if some animation is occurring.
_needsInitialSimulation = true;
}
virtual bool readyToAddToScene(RenderArgs* renderArgs = nullptr);
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override;
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override;
virtual void render(RenderArgs* args);
virtual bool supportsDetailedRayIntersection() const { return true; }
virtual void render(RenderArgs* args) override;
virtual bool supportsDetailedRayIntersection() const override { return true; }
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
bool& keepSearching, OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal,
void** intersectedObject, bool precisionPicking) const;
void** intersectedObject, bool precisionPicking) const override;
Model* getModel(EntityTreeRenderer* renderer);
virtual bool needsToCallUpdate() const;
virtual void update(const quint64& now);
virtual bool needsToCallUpdate() const override;
virtual void update(const quint64& now) override;
virtual void setCompoundShapeURL(const QString& url);
virtual void setCompoundShapeURL(const QString& url) override;
bool isReadyToComputeShape();
void computeShapeInfo(ShapeInfo& info);
virtual bool isReadyToComputeShape() override;
virtual void computeShapeInfo(ShapeInfo& info) override;
virtual bool contains(const glm::vec3& point) const;
virtual bool contains(const glm::vec3& point) const override;
// these are in the frame of this object
virtual glm::quat getJointRotation(int index) const;
virtual glm::vec3 getJointTranslation(int index) const;
private:
void remapTextures();

View file

@ -117,13 +117,15 @@ namespace render {
EntityItemPointer RenderableParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return std::make_shared<RenderableParticleEffectEntityItem>(entityID, properties);
EntityItemPointer RenderableParticleEffectEntityItem::factory(const EntityItemID& entityID,
const EntityItemProperties& properties) {
EntityItemPointer entity{ new RenderableParticleEffectEntityItem(entityID) };
entity->setProperties(properties);
return entity;
}
RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
ParticleEffectEntityItem(entityItemID, properties) {
RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const EntityItemID& entityItemID) :
ParticleEffectEntityItem(entityItemID) {
// lazy creation of particle system pipeline
if (!_untexturedPipeline && !_texturedPipeline) {
createPipelines();
@ -134,13 +136,14 @@ bool RenderableParticleEffectEntityItem::addToScene(EntityItemPointer self,
render::ScenePointer scene,
render::PendingChanges& pendingChanges) {
auto particlePayload = std::shared_ptr<ParticlePayload>(new ParticlePayload(shared_from_this()));
auto particlePayload =
std::shared_ptr<ParticlePayload>(new ParticlePayload(getThisPointer()));
particlePayload->setPipeline(_untexturedPipeline);
_renderItemId = scene->allocateID();
auto renderData = ParticlePayload::Pointer(particlePayload);
auto renderPayload = render::PayloadPointer(new ParticlePayload::Payload(renderData));
render::Item::Status::Getters statusGetters;
makeEntityItemStatusGetters(shared_from_this(), statusGetters);
makeEntityItemStatusGetters(getThisPointer(), statusGetters);
renderPayload->addStatusGetters(statusGetters);
pendingChanges.resetItem(_renderItemId, renderPayload);
_scene = scene;
@ -334,10 +337,10 @@ void RenderableParticleEffectEntityItem::createPipelines() {
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD,
destinationColorBlendArg, gpu::State::FACTOR_ALPHA,
gpu::State::BLEND_OP_ADD, gpu::State::ONE);
auto vertShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(untextured_particle_vert)));
auto fragShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(untextured_particle_frag)));
auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vertShader, fragShader));
_untexturedPipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state));
auto vertShader = gpu::Shader::createVertex(std::string(untextured_particle_vert));
auto fragShader = gpu::Shader::createPixel(std::string(untextured_particle_frag));
auto program = gpu::Shader::createProgram(vertShader, fragShader);
_untexturedPipeline = gpu::Pipeline::create(program, state);
}
if (!_texturedPipeline) {
auto state = std::make_shared<gpu::State>();
@ -349,17 +352,16 @@ void RenderableParticleEffectEntityItem::createPipelines() {
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD,
destinationColorBlendArg, gpu::State::FACTOR_ALPHA,
gpu::State::BLEND_OP_ADD, gpu::State::ONE);
auto vertShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(textured_particle_vert)));
auto vertShader = gpu::Shader::createVertex(std::string(textured_particle_vert));
gpu::ShaderPointer fragShader;
if (_additiveBlending) {
fragShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(textured_particle_frag)));
fragShader = gpu::Shader::createPixel(std::string(textured_particle_frag));
}
else {
//If we are sorting and have no additive blending, we want to discard pixels with low alpha to avoid inter-particle entity artifacts
fragShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(textured_particle_alpha_discard_frag)));
fragShader = gpu::Shader::createPixel(std::string(textured_particle_alpha_discard_frag));
}
auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vertShader, fragShader));
_texturedPipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state));
auto program = gpu::Shader::createProgram(vertShader, fragShader);
_texturedPipeline = gpu::Pipeline::create(program, state);
}
}

View file

@ -19,7 +19,7 @@ class RenderableParticleEffectEntityItem : public ParticleEffectEntityItem {
friend class ParticlePayload;
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
RenderableParticleEffectEntityItem(const EntityItemID& entityItemID);
virtual void update(const quint64& now) override;

View file

@ -23,16 +23,16 @@
#include "paintStroke_frag.h"
EntityItemPointer RenderablePolyLineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return EntityItemPointer(new RenderablePolyLineEntityItem(entityID, properties));
EntityItemPointer entity{ new RenderablePolyLineEntityItem(entityID) };
entity->setProperties(properties);
return entity;
}
RenderablePolyLineEntityItem::RenderablePolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
PolyLineEntityItem(entityItemID, properties) {
RenderablePolyLineEntityItem::RenderablePolyLineEntityItem(const EntityItemID& entityItemID) :
PolyLineEntityItem(entityItemID) {
_numVertices = 0;
_vertices = QVector<glm::vec3>(0.0f);
}
gpu::PipelinePointer RenderablePolyLineEntityItem::_pipeline;
@ -50,9 +50,9 @@ void RenderablePolyLineEntityItem::createPipeline() {
_format->setAttribute(gpu::Stream::COLOR, 0, gpu::Element::COLOR_RGBA_32, COLOR_OFFSET);
_format->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), TEXTURE_OFFSET);
auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(paintStroke_vert)));
auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(paintStroke_frag)));
gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS));
auto VS = gpu::Shader::createVertex(std::string(paintStroke_vert));
auto PS = gpu::Shader::createPixel(std::string(paintStroke_frag));
gpu::ShaderPointer program = gpu::Shader::createProgram(VS, PS);
gpu::Shader::BindingSet slotBindings;
PAINTSTROKE_GPU_SLOT = 0;
@ -64,7 +64,7 @@ void RenderablePolyLineEntityItem::createPipeline() {
state->setBlendFunction(true,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
_pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state));
_pipeline = gpu::Pipeline::create(program, state);
}
void RenderablePolyLineEntityItem::updateGeometry() {

View file

@ -26,7 +26,7 @@ class RenderablePolyLineEntityItem : public PolyLineEntityItem {
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
static void createPipeline();
RenderablePolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
RenderablePolyLineEntityItem(const EntityItemID& entityItemID);
virtual void render(RenderArgs* args);

View file

@ -50,12 +50,13 @@ gpu::PipelinePointer RenderablePolyVoxEntityItem::_pipeline = nullptr;
const float MARCHING_CUBE_COLLISION_HULL_OFFSET = 0.5;
EntityItemPointer RenderablePolyVoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return std::make_shared<RenderablePolyVoxEntityItem>(entityID, properties);
EntityItemPointer entity{ new RenderablePolyVoxEntityItem(entityID) };
entity->setProperties(properties);
return entity;
}
RenderablePolyVoxEntityItem::RenderablePolyVoxEntityItem(const EntityItemID& entityItemID,
const EntityItemProperties& properties) :
PolyVoxEntityItem(entityItemID, properties),
RenderablePolyVoxEntityItem::RenderablePolyVoxEntityItem(const EntityItemID& entityItemID) :
PolyVoxEntityItem(entityItemID),
_mesh(new model::Mesh()),
_meshDirty(true),
_xTexture(nullptr),
@ -477,8 +478,8 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
_meshLock.unlock();
if (!_pipeline) {
gpu::ShaderPointer vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(polyvox_vert)));
gpu::ShaderPointer pixelShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(polyvox_frag)));
gpu::ShaderPointer vertexShader = gpu::Shader::createVertex(std::string(polyvox_vert));
gpu::ShaderPointer pixelShader = gpu::Shader::createPixel(std::string(polyvox_frag));
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), MATERIAL_GPU_SLOT));
@ -486,14 +487,14 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
slotBindings.insert(gpu::Shader::Binding(std::string("yMap"), 1));
slotBindings.insert(gpu::Shader::Binding(std::string("zMap"), 2));
gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader));
gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader);
gpu::Shader::makeProgram(*program, slotBindings);
auto state = std::make_shared<gpu::State>();
state->setCullMode(gpu::State::CULL_BACK);
state->setDepthTest(true, true, gpu::LESS_EQUAL);
_pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state));
_pipeline = gpu::Pipeline::create(program, state);
}
gpu::Batch& batch = *args->_batch;
@ -546,12 +547,12 @@ bool RenderablePolyVoxEntityItem::addToScene(EntityItemPointer self,
render::PendingChanges& pendingChanges) {
_myItem = scene->allocateID();
auto renderItem = std::make_shared<PolyVoxPayload>(shared_from_this());
auto renderItem = std::make_shared<PolyVoxPayload>(getThisPointer());
auto renderData = PolyVoxPayload::Pointer(renderItem);
auto renderPayload = std::make_shared<PolyVoxPayload::Payload>(renderData);
render::Item::Status::Getters statusGetters;
makeEntityItemStatusGetters(shared_from_this(), statusGetters);
makeEntityItemStatusGetters(getThisPointer(), statusGetters);
renderPayload->addStatusGetters(statusGetters);
pendingChanges.resetItem(_myItem, renderPayload);

View file

@ -44,8 +44,7 @@ namespace render {
class RenderablePolyVoxEntityItem : public PolyVoxEntityItem {
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderablePolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
RenderablePolyVoxEntityItem(const EntityItemID& entityItemID);
virtual ~RenderablePolyVoxEntityItem();

View file

@ -29,7 +29,9 @@ static const float SPHERE_ENTITY_SCALE = 0.5f;
EntityItemPointer RenderableSphereEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return std::make_shared<RenderableSphereEntityItem>(entityID, properties);
EntityItemPointer entity{ new RenderableSphereEntityItem(entityID) };
entity->setProperties(properties);
return entity;
}
void RenderableSphereEntityItem::setUserData(const QString& value) {

View file

@ -20,10 +20,7 @@
class RenderableSphereEntityItem : public SphereEntityItem {
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableSphereEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
SphereEntityItem(entityItemID, properties)
{ }
RenderableSphereEntityItem(const EntityItemID& entityItemID) : SphereEntityItem(entityItemID) { }
virtual void render(RenderArgs* args);
virtual void setUserData(const QString& value);

View file

@ -22,7 +22,9 @@
#include "GLMHelpers.h"
EntityItemPointer RenderableTextEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return std::make_shared<RenderableTextEntityItem>(entityID, properties);
EntityItemPointer entity{ new RenderableTextEntityItem(entityID) };
entity->setProperties(properties);
return entity;
}
void RenderableTextEntityItem::render(RenderArgs* args) {

View file

@ -22,10 +22,7 @@ const int FIXED_FONT_POINT_SIZE = 40;
class RenderableTextEntityItem : public TextEntityItem {
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableTextEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
TextEntityItem(entityItemID, properties)
{ }
RenderableTextEntityItem(const EntityItemID& entityItemID) : TextEntityItem(entityItemID) { }
~RenderableTextEntityItem() { delete _textRenderer; }
virtual void render(RenderArgs* args);

View file

@ -31,11 +31,13 @@ const float DPI = 30.47f;
const float METERS_TO_INCHES = 39.3701f;
EntityItemPointer RenderableWebEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return std::make_shared<RenderableWebEntityItem>(entityID, properties);
EntityItemPointer entity{ new RenderableWebEntityItem(entityID) };
entity->setProperties(properties);
return entity;
}
RenderableWebEntityItem::RenderableWebEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
WebEntityItem(entityItemID, properties) {
RenderableWebEntityItem::RenderableWebEntityItem(const EntityItemID& entityItemID) :
WebEntityItem(entityItemID) {
qDebug() << "Created web entity " << getID();
}

View file

@ -22,8 +22,7 @@ class QObject;
class RenderableWebEntityItem : public WebEntityItem {
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableWebEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
RenderableWebEntityItem(const EntityItemID& entityItemID);
~RenderableWebEntityItem();
virtual void render(RenderArgs* args);

View file

@ -26,7 +26,9 @@
static const float SPHERE_ENTITY_SCALE = 0.5f;
EntityItemPointer RenderableZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return std::make_shared<RenderableZoneEntityItem>(entityID, properties);
EntityItemPointer entity{ new RenderableZoneEntityItem(entityID) };
entity->setProperties(properties);
return entity;
}
template<typename Lambda>
@ -115,7 +117,7 @@ void RenderableZoneEntityItem::render(RenderArgs* args) {
render::PendingChanges pendingChanges;
_model->removeFromScene(scene, pendingChanges);
render::Item::Status::Getters statusGetters;
makeEntityItemStatusGetters(shared_from_this(), statusGetters);
makeEntityItemStatusGetters(getThisPointer(), statusGetters);
_model->addToScene(scene, pendingChanges, false);
scene->enqueuePendingChanges(pendingChanges);
@ -209,7 +211,7 @@ bool RenderableZoneEntityItem::addToScene(EntityItemPointer self, std::shared_pt
auto renderPayload = std::make_shared<RenderableZoneEntityItemMeta::Payload>(renderData);
render::Item::Status::Getters statusGetters;
makeEntityItemStatusGetters(shared_from_this(), statusGetters);
makeEntityItemStatusGetters(getThisPointer(), statusGetters);
renderPayload->addStatusGetters(statusGetters);
pendingChanges.resetItem(_myMetaItem, renderPayload);

View file

@ -21,10 +21,10 @@ class RenderableZoneEntityItem : public ZoneEntityItem {
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
ZoneEntityItem(entityItemID, properties),
_model(NULL),
_needsInitialSimulation(true)
RenderableZoneEntityItem(const EntityItemID& entityItemID) :
ZoneEntityItem(entityItemID),
_model(NULL),
_needsInitialSimulation(true)
{ }
virtual bool setProperties(const EntityItemProperties& properties);

View file

@ -0,0 +1,83 @@
//
// BoundingBoxRelatedProperties.cpp
// libraries/entities/src
//
// Created by Seth Alves on 2015-9-24
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "EntityItemProperties.h"
#include "BoundingBoxRelatedProperties.h"
#include "EntityTree.h"
BoundingBoxRelatedProperties::BoundingBoxRelatedProperties(EntityItemPointer entity) :
position(entity->getPosition()),
rotation(entity->getRotation()),
registrationPoint(entity->getRegistrationPoint()),
dimensions(entity->getDimensions()),
parentID(entity->getParentID()) {
}
BoundingBoxRelatedProperties::BoundingBoxRelatedProperties(EntityItemPointer entity,
const EntityItemProperties& propertiesWithUpdates) :
BoundingBoxRelatedProperties(entity) {
if (propertiesWithUpdates.parentIDChanged()) {
parentID = propertiesWithUpdates.getParentID();
}
bool parentFound = false;
if (parentID != UNKNOWN_ENTITY_ID) {
EntityTreePointer tree = entity->getTree();
EntityItemPointer parentZone = tree->findEntityByID(parentID);
if (parentZone) {
parentFound = true;
glm::vec3 localPosition = propertiesWithUpdates.containsPositionChange() ?
propertiesWithUpdates.getPosition() :
entity->getLocalPosition();
glm::quat localRotation = propertiesWithUpdates.rotationChanged() ?
propertiesWithUpdates.getRotation() :
entity->getLocalOrientation();
const Transform parentTransform = parentZone->getTransformToCenter();
Transform parentDescaled(parentTransform.getRotation(), glm::vec3(1.0f), parentTransform.getTranslation());
Transform localTransform(localRotation, glm::vec3(1.0f), localPosition);
Transform result;
Transform::mult(result, parentDescaled, localTransform);
position = result.getTranslation();
rotation = result.getRotation();
}
}
if (!parentFound) {
if (propertiesWithUpdates.containsPositionChange()) {
position = propertiesWithUpdates.getPosition();
}
if (propertiesWithUpdates.rotationChanged()) {
rotation = propertiesWithUpdates.getRotation();
}
}
if (propertiesWithUpdates.registrationPointChanged()) {
registrationPoint = propertiesWithUpdates.getRegistrationPoint();
}
if (propertiesWithUpdates.dimensionsChanged()) {
dimensions = propertiesWithUpdates.getDimensions();
}
}
AACube BoundingBoxRelatedProperties::getMaximumAACube() const {
// see EntityItem::getMaximumAACube for comments which explain the following.
glm::vec3 scaledRegistrationPoint = (dimensions * registrationPoint);
glm::vec3 registrationRemainder = (dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - registrationPoint));
glm::vec3 furthestExtentFromRegistration = glm::max(scaledRegistrationPoint, registrationRemainder);
float radius = glm::length(furthestExtentFromRegistration);
glm::vec3 minimumCorner = position - glm::vec3(radius, radius, radius);
return AACube(minimumCorner, radius * 2.0f);
}

View file

@ -0,0 +1,30 @@
//
// BoundingBoxRelatedProperties.h
// libraries/entities/src
//
// Created by Seth Alves on 2015-9-24
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "EntityItem.h"
#ifndef hifi_BoundingBoxRelatedProperties_h
#define hifi_BoundingBoxRelatedProperties_h
class BoundingBoxRelatedProperties {
public:
BoundingBoxRelatedProperties(EntityItemPointer entity);
BoundingBoxRelatedProperties(EntityItemPointer entity, const EntityItemProperties& propertiesWithUpdates);
AACube getMaximumAACube() const;
glm::vec3 position;
glm::quat rotation;
glm::vec3 registrationPoint;
glm::vec3 dimensions;
EntityItemID parentID;
};
#endif // hifi_BoundingBoxRelatedProperties_h

View file

@ -21,15 +21,13 @@
#include "EntityTreeElement.h"
EntityItemPointer BoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItemPointer result { new BoxEntityItem(entityID, properties) };
return result;
EntityItemPointer entity { new BoxEntityItem(entityID) };
entity->setProperties(properties);
return entity;
}
BoxEntityItem::BoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID)
{
BoxEntityItem::BoxEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) {
_type = EntityTypes::Box;
setProperties(properties);
}
EntityItemProperties BoxEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {

View file

@ -18,7 +18,7 @@ class BoxEntityItem : public EntityItem {
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
BoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
BoxEntityItem(const EntityItemID& entityItemID);
ALLOW_INSTANTIATION // This class can be instantiated

View file

@ -36,8 +36,8 @@ int EntityItem::_maxActionsDataSize = 800;
quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND;
EntityItem::EntityItem(const EntityItemID& entityItemID) :
SpatiallyNestable(NestableTypes::Entity, entityItemID),
_type(EntityTypes::Unknown),
_id(entityItemID),
_lastSimulated(0),
_lastUpdated(0),
_lastEdited(0),
@ -45,7 +45,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) :
_lastEditedFromRemoteInRemoteTime(0),
_created(UNKNOWN_CREATED_TIME),
_changedOnServer(0),
_transform(),
_glowLevel(ENTITY_ITEM_DEFAULT_GLOW_LEVEL),
_localRenderAlpha(ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA),
_density(ENTITY_ITEM_DEFAULT_DENSITY),
@ -79,9 +78,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) :
_simulated(false)
{
// explicitly set transform parts to set dirty flags used by batch rendering
_transform.setTranslation(ENTITY_ITEM_DEFAULT_POSITION);
_transform.setRotation(ENTITY_ITEM_DEFAULT_ROTATION);
_transform.setScale(ENTITY_ITEM_DEFAULT_DIMENSIONS);
setScale(ENTITY_ITEM_DEFAULT_DIMENSIONS);
quint64 now = usecTimestampNow();
_lastSimulated = now;
_lastUpdated = now;
@ -134,6 +131,8 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
requestedProperties += PROP_HREF;
requestedProperties += PROP_DESCRIPTION;
requestedProperties += PROP_ACTION_DATA;
requestedProperties += PROP_PARENT_ID;
requestedProperties += PROP_PARENT_JOINT_INDEX;
return requestedProperties;
}
@ -240,8 +239,8 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
// PROP_CUSTOM_PROPERTIES_INCLUDED,
APPEND_ENTITY_PROPERTY(PROP_SIMULATION_OWNER, _simulationOwner.toByteArray());
APPEND_ENTITY_PROPERTY(PROP_POSITION, getPosition());
APPEND_ENTITY_PROPERTY(PROP_ROTATION, getRotation());
APPEND_ENTITY_PROPERTY(PROP_POSITION, getLocalPosition());
APPEND_ENTITY_PROPERTY(PROP_ROTATION, getLocalOrientation());
APPEND_ENTITY_PROPERTY(PROP_VELOCITY, getVelocity());
APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, getAngularVelocity());
APPEND_ENTITY_PROPERTY(PROP_ACCELERATION, getAcceleration());
@ -268,7 +267,8 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
APPEND_ENTITY_PROPERTY(PROP_HREF, getHref());
APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, getDescription());
APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, getActionData());
APPEND_ENTITY_PROPERTY(PROP_PARENT_ID, getParentID());
APPEND_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, getParentJointIndex());
appendSubclassData(packetData, params, entityTreeElementExtraEncodeData,
requestedProperties,
@ -722,6 +722,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_DESCRIPTION, QString, setDescription);
READ_ENTITY_PROPERTY(PROP_ACTION_DATA, QByteArray, setActionData);
READ_ENTITY_PROPERTY(PROP_PARENT_ID, QUuid, setParentID);
READ_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex);
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, somethingChanged);
@ -1044,9 +1047,9 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper
properties._type = getType();
COPY_ENTITY_PROPERTY_TO_PROPERTIES(simulationOwner, getSimulationOwner);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(position, getPosition);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(position, getLocalPosition);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(dimensions, getDimensions); // NOTE: radius is obsolete
COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotation, getRotation);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotation, getLocalOrientation);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(density, getDensity);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(velocity, getVelocity);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(gravity, getGravity);
@ -1074,6 +1077,8 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper
COPY_ENTITY_PROPERTY_TO_PROPERTIES(href, getHref);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(description, getDescription);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(actionData, getActionData);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentID, getParentID);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentJointIndex, getParentJointIndex);
properties._defaultSettings = false;
@ -1082,9 +1087,9 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper
void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) const {
// a TerseUpdate includes the transform and its derivatives
properties._position = getPosition();
properties._position = getLocalPosition();
properties._velocity = _velocity;
properties._rotation = getRotation();
properties._rotation = getLocalOrientation();
properties._angularVelocity = _angularVelocity;
properties._acceleration = _acceleration;
@ -1136,6 +1141,8 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(href, setHref);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(description, setDescription);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(actionData, setActionData);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentID, setParentID);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentJointIndex, setParentJointIndex);
if (somethingChanged) {
uint64_t now = usecTimestampNow();
@ -1185,11 +1192,11 @@ const Transform EntityItem::getTransformToCenter() const {
return result;
}
void EntityItem::setDimensions(const glm::vec3& value) {
void EntityItem::setDimensions(const glm::vec3 value) {
if (value.x <= 0.0f || value.y <= 0.0f || value.z <= 0.0f) {
return;
}
_transform.setScale(value);
setScale(value);
requiresRecalcBoxes();
}
@ -1315,9 +1322,8 @@ void EntityItem::updatePosition(const glm::vec3& value) {
if (shouldSuppressLocationEdits()) {
return;
}
if (getPosition() != value) {
setPosition(value);
_dirtyFlags |= Simulation::DIRTY_POSITION;
if (getLocalPosition() != value) {
setLocalPosition(value);
}
}
@ -1332,9 +1338,16 @@ void EntityItem::updateRotation(const glm::quat& rotation) {
if (shouldSuppressLocationEdits()) {
return;
}
if (getRotation() != rotation) {
setRotation(rotation);
if (getLocalOrientation() != rotation) {
setLocalOrientation(rotation);
_dirtyFlags |= Simulation::DIRTY_ROTATION;
forEachDescendant([&](SpatiallyNestablePointer object) {
if (object->getNestableType() == NestableTypes::Entity) {
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
entity->_dirtyFlags |= Simulation::DIRTY_ROTATION;
entity->_dirtyFlags |= Simulation::DIRTY_POSITION;
}
});
}
}
@ -1523,7 +1536,6 @@ bool EntityItem::addAction(EntitySimulation* simulation, EntityActionPointer act
}
bool EntityItem::addActionInternal(EntitySimulation* simulation, EntityActionPointer action) {
assertLocked();
assert(action);
assert(simulation);
auto actionOwnerEntity = action->getOwnerEntity().lock();
@ -1579,7 +1591,6 @@ bool EntityItem::removeAction(EntitySimulation* simulation, const QUuid& actionI
}
bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* simulation) {
assertWriteLocked();
_previouslyDeletedActions.insert(actionID, usecTimestampNow());
if (_objectActions.contains(actionID)) {
if (!simulation) {
@ -1625,7 +1636,6 @@ bool EntityItem::clearActions(EntitySimulation* simulation) {
void EntityItem::deserializeActions() {
assertUnlocked();
withWriteLock([&] {
deserializeActionsInternal();
});
@ -1633,8 +1643,6 @@ void EntityItem::deserializeActions() {
void EntityItem::deserializeActionsInternal() {
assertWriteLocked();
quint64 now = usecTimestampNow();
if (!_element) {
@ -1676,7 +1684,7 @@ void EntityItem::deserializeActionsInternal() {
action->locallyAddedButNotYetReceived = false;
} else {
auto actionFactory = DependencyManager::get<EntityActionFactoryInterface>();
EntityItemPointer entity = shared_from_this();
EntityItemPointer entity = getThisPointer();
EntityActionPointer action = actionFactory->factoryBA(entity, serializedAction);
if (action) {
entity->addActionInternal(simulation, action);
@ -1717,7 +1725,6 @@ void EntityItem::deserializeActionsInternal() {
}
void EntityItem::checkWaitingToRemove(EntitySimulation* simulation) {
assertLocked();
foreach(QUuid actionID, _actionsToRemove) {
removeActionInternal(actionID, simulation);
}
@ -1725,14 +1732,12 @@ void EntityItem::checkWaitingToRemove(EntitySimulation* simulation) {
}
void EntityItem::setActionData(QByteArray actionData) {
assertUnlocked();
withWriteLock([&] {
setActionDataInternal(actionData);
});
}
void EntityItem::setActionDataInternal(QByteArray actionData) {
assertWriteLocked();
if (_allActionsDataCache != actionData) {
_allActionsDataCache = actionData;
deserializeActionsInternal();
@ -1741,8 +1746,6 @@ void EntityItem::setActionDataInternal(QByteArray actionData) {
}
void EntityItem::serializeActions(bool& success, QByteArray& result) const {
assertLocked();
if (_objectActions.size() == 0) {
success = true;
result.clear();
@ -1785,7 +1788,6 @@ const QByteArray EntityItem::getActionDataInternal() const {
const QByteArray EntityItem::getActionData() const {
QByteArray result;
assertUnlocked();
if (_actionDataDirty) {
withWriteLock([&] {
@ -1839,3 +1841,8 @@ QList<EntityActionPointer> EntityItem::getActionsOfType(EntityActionType typeToG
return result;
}
void EntityItem::locationChanged() {
requiresRecalcBoxes();
SpatiallyNestable::locationChanged(); // tell all the children, also
}

Some files were not shown because too many files have changed in this diff Show more