Merge branch 'master' of github.com:highfidelity/hifi into no-fly-zones

This commit is contained in:
Seth Alves 2016-05-19 09:49:44 -07:00
commit 74520f5c92
110 changed files with 1200 additions and 1070 deletions

View file

@ -6,7 +6,7 @@ Licensed under the Apache License version 2.0 (the "License");
You may not use this software except in compliance with the License.
You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
This software includes third-party software.
This software includes third-party and other platform software.
Please see each individual software license for additional details.
This software is distributed "as-is" without any warranties, conditions, or representations whether express or implied, including without limitation the implied warranties and conditions of merchantability, merchantable quality, fitness for a particular purpose, performance, durability, title, non-infringement, and those arising from statute or from custom or usage of trade or course of dealing.

View file

@ -139,7 +139,7 @@ if (WIN32)
endif()
# link required hifi libraries
link_hifi_libraries(shared octree gpu gl procedural model render
link_hifi_libraries(shared octree gpu gl gpu-gl procedural model render
recording fbx networking model-networking entities avatars
audio audio-client animation script-engine physics
render-utils entities-renderer ui auto-updater

View file

@ -76,7 +76,6 @@ QtObject {
readonly property string forward: "Forward";
readonly property string frameTimer: "Show Timer";
readonly property string fullscreenMirror: "Mirror";
readonly property string glowWhenSpeaking: "Glow When Speaking";
readonly property string help: "Help...";
readonly property string increaseAvatarSize: "Increase Avatar Size";
readonly property string independentMode: "Independent Mode";

View file

@ -1,20 +0,0 @@
#version 120
//
// glow_add.frag
// fragment shader
//
// Created by Andrzej Kapolka on 8/14/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// the texture containing the original color
uniform sampler2D originalTexture;
void main(void) {
vec4 color = texture2D(originalTexture, gl_TexCoord[0].st);
gl_FragColor = color * (1.0 + color.a);
}

View file

@ -1,23 +0,0 @@
#version 120
//
// glow_add_separate.frag
// fragment shader
//
// Created by Andrzej Kapolka on 8/14/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// the texture containing the original color
uniform sampler2D originalTexture;
// the texture containing the blurred color
uniform sampler2D blurredTexture;
void main(void) {
vec4 blurred = texture2D(blurredTexture, gl_TexCoord[0].st);
gl_FragColor = blurred * blurred.a + texture2D(originalTexture, gl_TexCoord[0].st) * (1.0 + blurred.a * 0.5);
}

View file

@ -60,7 +60,7 @@
#include <FramebufferCache.h>
#include <gpu/Batch.h>
#include <gpu/Context.h>
#include <gpu/GLBackend.h>
#include <gpu/gl/GLBackend.h>
#include <HFActionEvent.h>
#include <HFBackEvent.h>
#include <InfoView.h>
@ -349,19 +349,14 @@ public:
};
#endif
enum CustomEventTypes {
Lambda = QEvent::User + 1,
Paint = Lambda + 1,
};
class LambdaEvent : public QEvent {
std::function<void()> _fun;
public:
LambdaEvent(const std::function<void()> & fun) :
QEvent(static_cast<QEvent::Type>(Lambda)), _fun(fun) {
QEvent(static_cast<QEvent::Type>(Application::Lambda)), _fun(fun) {
}
LambdaEvent(std::function<void()> && fun) :
QEvent(static_cast<QEvent::Type>(Lambda)), _fun(fun) {
QEvent(static_cast<QEvent::Type>(Application::Lambda)), _fun(fun) {
}
void call() const { _fun(); }
};
@ -1057,18 +1052,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
connect(this, &Application::applicationStateChanged, this, &Application::activeChanged);
qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0);
_idleTimer = new QTimer(this);
connect(_idleTimer, &QTimer::timeout, [=] {
idle(usecTimestampNow());
});
connect(this, &Application::beforeAboutToQuit, [=] {
disconnect(_idleTimer);
});
// Setting the interval to zero forces this to get called whenever there are no messages
// in the queue, which can be pretty damn frequent. Hence the idle function has a bunch
// of logic to abort early if it's being called too often.
_idleTimer->start(0);
// After all of the constructor is completed, then set firstRun to false.
Setting::Handle<bool> firstRun{ Settings::firstRun, true };
firstRun.set(false);
@ -1262,8 +1245,7 @@ void Application::initializeGL() {
_isGLInitialized = true;
}
// Where the gpuContext is initialized and where the TRUE Backend is created and assigned
gpu::Context::init<gpu::GLBackend>();
gpu::Context::init<gpu::gl::GLBackend>();
_gpuContext = std::make_shared<gpu::Context>();
// The gpu context can make child contexts for transfers, so
// we need to restore primary rendering context
@ -1441,23 +1423,15 @@ void Application::initializeUi() {
});
}
void Application::paintGL() {
updateHeartbeat();
// Some plugins process message events, potentially leading to
// re-entering a paint event. don't allow further processing if this
// happens
if (_inPaint) {
// Some plugins process message events, allowing paintGL to be called reentrantly.
if (_inPaint || _aboutToQuit) {
return;
}
_inPaint = true;
Finally clearFlagLambda([this] { _inPaint = false; });
// paintGL uses a queued connection, so we can get messages from the queue even after we've quit
// and the plugins have shutdown
if (_aboutToQuit) {
return;
}
_inPaint = true;
Finally clearFlag([this] { _inPaint = false; });
_frameCount++;
_frameCounter.increment();
@ -1815,13 +1789,30 @@ bool Application::event(QEvent* event) {
return false;
}
if ((int)event->type() == (int)Lambda) {
static_cast<LambdaEvent*>(event)->call();
static bool justPresented = false;
if ((int)event->type() == (int)Present) {
if (justPresented) {
justPresented = false;
// If presentation is hogging the main thread, repost as low priority to avoid hanging the GUI.
// This has the effect of allowing presentation to exceed the paint budget by X times and
// only dropping every (1/X) frames, instead of every ceil(X) frames.
// (e.g. at a 60FPS target, painting for 17us would fall to 58.82FPS instead of 30FPS).
removePostedEvents(this, Present);
postEvent(this, new QEvent(static_cast<QEvent::Type>(Present)), Qt::LowEventPriority);
return true;
}
idle();
return true;
} else if ((int)event->type() == (int)Paint) {
justPresented = true;
paintGL();
return true;
}
if ((int)event->type() == (int)Paint) {
paintGL();
if ((int)event->type() == (int)Lambda) {
static_cast<LambdaEvent*>(event)->call();
return true;
}
@ -2599,72 +2590,63 @@ bool Application::acceptSnapshot(const QString& urlString) {
static uint32_t _renderedFrameIndex { INVALID_FRAME };
void Application::idle(uint64_t now) {
// NOTICE NOTICE NOTICE NOTICE
// Do not insert new code between here and the PROFILE_RANGE declaration
// unless you know exactly what you're doing. This idle function can be
// called thousands per second or more, so any additional work that's done
// here will have a serious impact on CPU usage. Only add code after all
// the thottling logic, i.e. after PROFILE_RANGE
// NOTICE NOTICE NOTICE NOTICE
updateHeartbeat();
if (_aboutToQuit || _inPaint) {
return; // bail early, nothing to do here.
}
auto displayPlugin = getActiveDisplayPlugin();
// depending on whether we're throttling or not.
// Once rendering is off on another thread we should be able to have Application::idle run at start(0) in
// perpetuity and not expect events to get backed up.
bool isThrottled = displayPlugin->isThrottled();
// Only run simulation code if more than the targetFramePeriod have passed since last time we ran
// This attempts to lock the simulation at 60 updates per second, regardless of framerate
float timeSinceLastUpdateUs = (float)_lastTimeUpdated.nsecsElapsed() / NSECS_PER_USEC;
float secondsSinceLastUpdate = timeSinceLastUpdateUs / USECS_PER_SECOND;
if (isThrottled && (timeSinceLastUpdateUs / USECS_PER_MSEC) < THROTTLED_SIM_FRAME_PERIOD_MS) {
// Throttling both rendering and idle
return; // bail early, we're throttled and not enough time has elapsed
}
auto presentCount = displayPlugin->presentCount();
if (presentCount < _renderedFrameIndex) {
_renderedFrameIndex = INVALID_FRAME;
}
// Don't saturate the main thread with rendering and simulation,
// unless display plugin has increased by at least one frame
if (_renderedFrameIndex == INVALID_FRAME || presentCount > _renderedFrameIndex) {
// Record what present frame we're on
_renderedFrameIndex = presentCount;
// request a paint, get to it as soon as possible: high priority
postEvent(this, new QEvent(static_cast<QEvent::Type>(Paint)), Qt::HighEventPriority);
} else {
// there's no use in simulating or rendering faster then the present rate.
void Application::idle() {
// idle is called on a queued connection, so make sure we should be here.
if (_inPaint || _aboutToQuit) {
return;
}
// NOTICE NOTICE NOTICE NOTICE
// do NOT add new code above this line unless you want it to be executed potentially
// thousands of times per second
// NOTICE NOTICE NOTICE NOTICE
auto displayPlugin = getActiveDisplayPlugin();
PROFILE_RANGE(__FUNCTION__);
#ifdef DEBUG_PAINT_DELAY
static uint64_t paintDelaySamples{ 0 };
static uint64_t paintDelayUsecs{ 0 };
paintDelayUsecs += displayPlugin->getPaintDelayUsecs();
static const int PAINT_DELAY_THROTTLE = 1000;
if (++paintDelaySamples % PAINT_DELAY_THROTTLE == 0) {
qCDebug(interfaceapp).nospace() <<
"Paint delay (" << paintDelaySamples << " samples): " <<
(float)paintDelaySamples / paintDelayUsecs << "us";
}
#endif
float msecondsSinceLastUpdate = (float)_lastTimeUpdated.nsecsElapsed() / NSECS_PER_USEC / USECS_PER_MSEC;
// Throttle if requested
if (displayPlugin->isThrottled() && (msecondsSinceLastUpdate < THROTTLED_SIM_FRAME_PERIOD_MS)) {
return;
}
// Sync up the _renderedFrameIndex
_renderedFrameIndex = displayPlugin->presentCount();
// Request a paint ASAP
postEvent(this, new QEvent(static_cast<QEvent::Type>(Paint)), Qt::HighEventPriority + 1);
// Update the deadlock watchdog
updateHeartbeat();
auto offscreenUi = DependencyManager::get<OffscreenUi>();
// These tasks need to be done on our first idle, because we don't want the showing of
// overlay subwindows to do a showDesktop() until after the first time through
static bool firstIdle = true;
if (firstIdle) {
firstIdle = false;
auto offscreenUi = DependencyManager::get<OffscreenUi>();
connect(offscreenUi.data(), &OffscreenUi::showDesktop, this, &Application::showDesktop);
_overlayConductor.setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Overlays));
} else {
// FIXME: AvatarInputs are positioned incorrectly if instantiated before the first paint
AvatarInputs::getInstance()->update();
}
PROFILE_RANGE(__FUNCTION__);
float secondsSinceLastUpdate = msecondsSinceLastUpdate / MSECS_PER_SECOND;
// If the offscreen Ui has something active that is NOT the root, then assume it has keyboard focus.
auto offscreenUi = DependencyManager::get<OffscreenUi>();
if (_keyboardDeviceHasFocus && offscreenUi && offscreenUi->getWindow()->activeFocusItem() != offscreenUi->getRootItem()) {
_keyboardMouseDevice->pluginFocusOutEvent();
_keyboardDeviceHasFocus = false;
@ -2680,7 +2662,6 @@ void Application::idle(uint64_t now) {
checkChangeCursor();
Stats::getInstance()->updateStats();
AvatarInputs::getInstance()->update();
_simCounter.increment();

View file

@ -33,6 +33,7 @@
#include <PhysicalEntitySimulation.h>
#include <PhysicsEngine.h>
#include <plugins/Forward.h>
#include <plugins/DisplayPlugin.h>
#include <ScriptEngine.h>
#include <ShapeManager.h>
#include <SimpleMovingAverage.h>
@ -93,6 +94,12 @@ class Application : public QApplication, public AbstractViewStateInterface, publ
friend class PluginContainerProxy;
public:
enum Event {
Present = DisplayPlugin::Present,
Paint = Present + 1,
Lambda = Paint + 1
};
// FIXME? Empty methods, do we still need them?
static void initPlugins();
static void shutdownPlugins();
@ -281,7 +288,6 @@ public slots:
private slots:
void showDesktop();
void clearDomainOctreeDetails();
void idle(uint64_t now);
void aboutToQuit();
void resettingDomain();
@ -320,6 +326,7 @@ private:
void cleanupBeforeQuit();
void idle();
void update(float deltaTime);
// Various helper functions called during update()
@ -497,7 +504,6 @@ private:
int _avatarAttachmentRequest = 0;
bool _settingsLoaded { false };
QTimer* _idleTimer { nullptr };
bool _fakedMouseEvent { false };

View file

@ -500,7 +500,7 @@ Menu::Menu() {
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderSensorToWorldMatrix, 0, false,
avatar, SLOT(setEnableDebugDrawSensorToWorldMatrix(bool)));
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::KeyboardMotorControl,
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ActionMotorControl,
Qt::CTRL | Qt::SHIFT | Qt::Key_K, true, avatar, SLOT(updateMotionBehaviorFromMenu()),
UNSPECIFIED_POSITION, "Developer");

View file

@ -111,12 +111,11 @@ namespace MenuOption {
const QString Forward = "Forward";
const QString FrameTimer = "Show Timer";
const QString FullscreenMirror = "Mirror";
const QString GlowWhenSpeaking = "Glow When Speaking";
const QString Help = "Help...";
const QString IncreaseAvatarSize = "Increase Avatar Size";
const QString IndependentMode = "Independent Mode";
const QString InputMenu = "Avatar>Input Devices";
const QString KeyboardMotorControl = "Enable Keyboard Motor Control";
const QString ActionMotorControl = "Enable Default Motor Control";
const QString LeapMotionOnHMD = "Leap Motion on HMD";
const QString LoadScript = "Open and Run Script File...";
const QString LoadScriptURL = "Open and Run Script from URL...";

View file

@ -59,9 +59,10 @@ using namespace std;
const glm::vec3 DEFAULT_UP_DIRECTION(0.0f, 1.0f, 0.0f);
const float DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES = 30.0f;
const float MAX_WALKING_SPEED = 2.5f; // human walking speed
const float MAX_BOOST_SPEED = 0.5f * MAX_WALKING_SPEED; // keyboard motor gets additive boost below this speed
const float MIN_AVATAR_SPEED = 0.05f; // speed is set to zero below this
const float MAX_WALKING_SPEED = 2.6f; // human walking speed
const float MAX_BOOST_SPEED = 0.5f * MAX_WALKING_SPEED; // action motor gets additive boost below this speed
const float MIN_AVATAR_SPEED = 0.05f;
const float MIN_AVATAR_SPEED_SQUARED = MIN_AVATAR_SPEED * MIN_AVATAR_SPEED; // speed is set to zero below this
const float YAW_SPEED_DEFAULT = 120.0f; // degrees/sec
const float PITCH_SPEED_DEFAULT = 90.0f; // degrees/sec
@ -69,8 +70,7 @@ const float PITCH_SPEED_DEFAULT = 90.0f; // degrees/sec
// TODO: normalize avatar speed for standard avatar size, then scale all motion logic
// to properly follow avatar size.
float MAX_AVATAR_SPEED = 30.0f;
float MAX_KEYBOARD_MOTOR_SPEED = MAX_AVATAR_SPEED;
float DEFAULT_KEYBOARD_MOTOR_TIMESCALE = 0.25f;
float MAX_ACTION_MOTOR_SPEED = MAX_AVATAR_SPEED;
float MIN_SCRIPTED_MOTOR_TIMESCALE = 0.005f;
float DEFAULT_SCRIPTED_MOTOR_TIMESCALE = 1.0e6f;
const int SCRIPTED_MOTOR_CAMERA_FRAME = 0;
@ -86,13 +86,13 @@ MyAvatar::MyAvatar(RigPointer rig) :
Avatar(rig),
_wasPushing(false),
_isPushing(false),
_isBeingPushed(false),
_isBraking(false),
_boomLength(ZOOM_DEFAULT),
_yawSpeed(YAW_SPEED_DEFAULT),
_pitchSpeed(PITCH_SPEED_DEFAULT),
_thrust(0.0f),
_keyboardMotorVelocity(0.0f),
_keyboardMotorTimescale(DEFAULT_KEYBOARD_MOTOR_TIMESCALE),
_actionMotorVelocity(0.0f),
_scriptedMotorVelocity(0.0f),
_scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE),
_scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME),
@ -246,7 +246,6 @@ void MyAvatar::reset(bool andRecenter) {
_follow.deactivate();
_skeletonModel->reset();
getHead()->reset();
_targetVelocity = glm::vec3(0.0f);
setThrust(glm::vec3(0.0f));
if (andRecenter) {
@ -1177,8 +1176,46 @@ controller::Pose MyAvatar::getRightHandControllerPoseInAvatarFrame() const {
return getRightHandControllerPoseInWorldFrame().transform(invAvatarMatrix);
}
void MyAvatar::updateMotors() {
_characterController.clearMotors();
glm::quat motorRotation;
if (_motionBehaviors & AVATAR_MOTION_ACTION_MOTOR_ENABLED) {
if (_characterController.getState() == CharacterController::State::Hover) {
motorRotation = getHead()->getCameraOrientation();
} else {
motorRotation = getOrientation();
}
const float DEFAULT_MOTOR_TIMESCALE = 0.2f;
const float INVALID_MOTOR_TIMESCALE = 1.0e6f;
if (_isPushing || _isBraking || !_isBeingPushed) {
_characterController.addMotor(_actionMotorVelocity, motorRotation, DEFAULT_MOTOR_TIMESCALE, INVALID_MOTOR_TIMESCALE);
} else {
// _isBeingPushed must be true --> disable action motor by giving it a long timescale,
// otherwise it's attempt to "stand in in place" could defeat scripted motor/thrusts
_characterController.addMotor(_actionMotorVelocity, motorRotation, INVALID_MOTOR_TIMESCALE);
}
}
if (_motionBehaviors & AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED) {
if (_scriptedMotorFrame == SCRIPTED_MOTOR_CAMERA_FRAME) {
motorRotation = getHead()->getCameraOrientation() * glm::angleAxis(PI, Vectors::UNIT_Y);
} else if (_scriptedMotorFrame == SCRIPTED_MOTOR_AVATAR_FRAME) {
motorRotation = getOrientation() * glm::angleAxis(PI, Vectors::UNIT_Y);
} else {
// world-frame
motorRotation = glm::quat();
}
_characterController.addMotor(_scriptedMotorVelocity, motorRotation, _scriptedMotorTimescale);
}
// legacy support for 'MyAvatar::applyThrust()', which has always been implemented as a
// short-lived linearAcceleration
_characterController.setLinearAcceleration(_thrust);
_thrust = Vectors::ZERO;
}
void MyAvatar::prepareForPhysicsSimulation() {
relayDriveKeysToCharacterController();
updateMotors();
bool success;
glm::vec3 parentVelocity = getParentVelocity(success);
@ -1188,7 +1225,6 @@ void MyAvatar::prepareForPhysicsSimulation() {
}
_characterController.setParentVelocity(parentVelocity);
_characterController.setTargetVelocity(getTargetVelocity());
_characterController.setPositionAndOrientation(getPosition(), getOrientation());
if (qApp->isHMDMode()) {
bool hasDriveInput = fabsf(_driveKeys[TRANSLATE_X]) > 0.0f || fabsf(_driveKeys[TRANSLATE_Z]) > 0.0f;
@ -1201,11 +1237,17 @@ void MyAvatar::prepareForPhysicsSimulation() {
void MyAvatar::harvestResultsFromPhysicsSimulation(float deltaTime) {
glm::vec3 position = getPosition();
glm::quat orientation = getOrientation();
_characterController.getPositionAndOrientation(position, orientation);
if (_characterController.isEnabled()) {
_characterController.getPositionAndOrientation(position, orientation);
}
nextAttitude(position, orientation);
_bodySensorMatrix = _follow.postPhysicsUpdate(*this, _bodySensorMatrix);
setVelocity(_characterController.getLinearVelocity() + _characterController.getFollowVelocity());
if (_characterController.isEnabled()) {
setVelocity(_characterController.getLinearVelocity() + _characterController.getFollowVelocity());
} else {
setVelocity(getVelocity() + _characterController.getFollowVelocity());
}
}
QString MyAvatar::getScriptedMotorFrame() const {
@ -1245,7 +1287,7 @@ void MyAvatar::setScriptedMotorFrame(QString frame) {
}
void MyAvatar::clearScriptableSettings() {
_scriptedMotorVelocity = glm::vec3(0.0f);
_scriptedMotorVelocity = Vectors::ZERO;
_scriptedMotorTimescale = DEFAULT_SCRIPTED_MOTOR_TIMESCALE;
}
@ -1510,163 +1552,97 @@ void MyAvatar::updateOrientation(float deltaTime) {
}
}
glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVelocity, bool isHovering) {
if (! (_motionBehaviors & AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED)) {
return localVelocity;
}
// compute motor efficiency
// The timescale of the motor is the approximate time it takes for the motor to
// accomplish its intended localVelocity. A short timescale makes the motor strong,
// and a long timescale makes it weak. The value of timescale to use depends
// on what the motor is doing:
//
// (1) braking --> short timescale (aggressive motor assertion)
// (2) pushing --> medium timescale (mild motor assertion)
// (3) inactive --> long timescale (gentle friction for low speeds)
const float MIN_KEYBOARD_MOTOR_TIMESCALE = 0.125f;
const float MAX_KEYBOARD_MOTOR_TIMESCALE = 0.4f;
const float MIN_KEYBOARD_BRAKE_SPEED = 0.3f;
float timescale = MAX_KEYBOARD_MOTOR_TIMESCALE;
bool isThrust = (glm::length2(_thrust) > EPSILON);
if (_isPushing || isThrust ||
(_scriptedMotorTimescale < MAX_KEYBOARD_MOTOR_TIMESCALE &&
(_motionBehaviors & AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED))) {
// we don't want to brake if something is pushing the avatar around
timescale = _keyboardMotorTimescale;
void MyAvatar::updateActionMotor(float deltaTime) {
bool thrustIsPushing = (glm::length2(_thrust) > EPSILON);
bool scriptedMotorIsPushing = (_motionBehaviors & AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED)
&& _scriptedMotorTimescale < MAX_CHARACTER_MOTOR_TIMESCALE;
_isBeingPushed = thrustIsPushing || scriptedMotorIsPushing;
if (_isPushing || _isBeingPushed) {
// we don't want the motor to brake if a script is pushing the avatar around
// (we assume the avatar is driving itself via script)
_isBraking = false;
} else {
float speed = glm::length(localVelocity);
_isBraking = _wasPushing || (_isBraking && speed > MIN_KEYBOARD_BRAKE_SPEED);
if (_isBraking) {
timescale = MIN_KEYBOARD_MOTOR_TIMESCALE;
}
float speed = glm::length(_actionMotorVelocity);
const float MIN_ACTION_BRAKE_SPEED = 0.1f;
_isBraking = _wasPushing || (_isBraking && speed > MIN_ACTION_BRAKE_SPEED);
}
_wasPushing = _isPushing || isThrust;
_isPushing = false;
float motorEfficiency = glm::clamp(deltaTime / timescale, 0.0f, 1.0f);
glm::vec3 newLocalVelocity = localVelocity;
// compute action input
glm::vec3 front = (_driveKeys[TRANSLATE_Z]) * IDENTITY_FRONT;
glm::vec3 right = (_driveKeys[TRANSLATE_X]) * IDENTITY_RIGHT;
// FIXME how do I implement step translation as well?
float keyboardInput = fabsf(_driveKeys[TRANSLATE_Z]) + fabsf(_driveKeys[TRANSLATE_X]) + fabsf(_driveKeys[TRANSLATE_Y]);
if (keyboardInput) {
// Compute keyboard input
glm::vec3 front = (_driveKeys[TRANSLATE_Z]) * IDENTITY_FRONT;
glm::vec3 right = (_driveKeys[TRANSLATE_X]) * IDENTITY_RIGHT;
glm::vec3 direction = front + right;
CharacterController::State state = _characterController.getState();
if (state == CharacterController::State::Hover) {
// we're flying --> support vertical motion
glm::vec3 up = (_driveKeys[TRANSLATE_Y]) * IDENTITY_UP;
direction += up;
}
glm::vec3 direction = front + right + up;
float directionLength = glm::length(direction);
_wasPushing = _isPushing;
float directionLength = glm::length(direction);
_isPushing = directionLength > EPSILON;
//qCDebug(interfaceapp, "direction = (%.5f, %.5f, %.5f)", direction.x, direction.y, direction.z);
// Compute motor magnitude
if (directionLength > EPSILON) {
direction /= directionLength;
if (isHovering) {
// we're flying --> complex acceleration curve with high max speed
float motorSpeed = glm::length(_keyboardMotorVelocity);
float finalMaxMotorSpeed = getUniformScale() * 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 = getUniformScale() * MAX_BOOST_SPEED;
if (motorSpeed < maxBoostSpeed) {
// an active keyboard motor should never be slower than this
float boostCoefficient = (maxBoostSpeed - motorSpeed) / maxBoostSpeed;
motorSpeed += MIN_AVATAR_SPEED * boostCoefficient;
motorEfficiency += (1.0f - motorEfficiency) * boostCoefficient;
} else if (motorSpeed > finalMaxMotorSpeed) {
motorSpeed = finalMaxMotorSpeed;
}
_keyboardMotorVelocity = motorSpeed * direction;
} else {
// we're using a floor --> simple exponential decay toward target walk speed
const float WALK_ACCELERATION_TIMESCALE = 0.7f; // seconds to decrease delta to 1/e
_keyboardMotorVelocity = MAX_WALKING_SPEED * direction;
motorEfficiency = glm::clamp(deltaTime / WALK_ACCELERATION_TIMESCALE, 0.0f, 1.0f);
}
_isPushing = true;
}
newLocalVelocity = localVelocity + motorEfficiency * (_keyboardMotorVelocity - localVelocity);
// normalize direction
if (_isPushing) {
direction /= directionLength;
} else {
_keyboardMotorVelocity = glm::vec3(0.0f);
newLocalVelocity = (1.0f - motorEfficiency) * localVelocity;
if (!isHovering && !_wasPushing) {
float speed = glm::length(newLocalVelocity);
if (speed > MIN_AVATAR_SPEED) {
// add small constant friction to help avatar drift to a stop sooner at low speeds
const float CONSTANT_FRICTION_DECELERATION = MIN_AVATAR_SPEED / 0.20f;
newLocalVelocity *= (speed - timescale * CONSTANT_FRICTION_DECELERATION) / speed;
direction = Vectors::ZERO;
}
if (state == CharacterController::State::Hover) {
// we're flying --> complex acceleration curve that builds on top of current motor speed and caps at some max speed
float motorSpeed = glm::length(_actionMotorVelocity);
float finalMaxMotorSpeed = getUniformScale() * MAX_ACTION_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 = getUniformScale() * MAX_BOOST_SPEED;
if (_isPushing) {
if (motorSpeed < maxBoostSpeed) {
// an active action motor should never be slower than this
float boostCoefficient = (maxBoostSpeed - motorSpeed) / maxBoostSpeed;
motorSpeed += MIN_AVATAR_SPEED * boostCoefficient;
} else if (motorSpeed > finalMaxMotorSpeed) {
motorSpeed = finalMaxMotorSpeed;
}
}
_actionMotorVelocity = motorSpeed * direction;
} else {
// we're interacting with a floor --> simple horizontal speed and exponential decay
_actionMotorVelocity = MAX_WALKING_SPEED * direction;
}
float boomChange = _driveKeys[ZOOM];
_boomLength += 2.0f * _boomLength * boomChange + boomChange * boomChange;
_boomLength = glm::clamp<float>(_boomLength, ZOOM_MIN, ZOOM_MAX);
return newLocalVelocity;
}
glm::vec3 MyAvatar::applyScriptedMotor(float deltaTime, const glm::vec3& localVelocity) {
// NOTE: localVelocity is in camera-frame because that's the frame of the default avatar motor
if (! (_motionBehaviors & AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED)) {
return localVelocity;
}
glm::vec3 deltaVelocity(0.0f);
if (_scriptedMotorFrame == SCRIPTED_MOTOR_CAMERA_FRAME) {
// camera frame
deltaVelocity = _scriptedMotorVelocity - localVelocity;
} else if (_scriptedMotorFrame == SCRIPTED_MOTOR_AVATAR_FRAME) {
// avatar frame
glm::quat rotation = glm::inverse(getHead()->getCameraOrientation()) * getOrientation();
deltaVelocity = rotation * _scriptedMotorVelocity - localVelocity;
} else {
// world-frame
glm::quat rotation = glm::inverse(getHead()->getCameraOrientation());
deltaVelocity = rotation * _scriptedMotorVelocity - localVelocity;
}
float motorEfficiency = glm::clamp(deltaTime / _scriptedMotorTimescale, 0.0f, 1.0f);
return localVelocity + motorEfficiency * deltaVelocity;
}
void MyAvatar::updatePosition(float deltaTime) {
// rotate velocity into camera frame
glm::quat rotation = getHead()->getCameraOrientation();
glm::vec3 localVelocity = glm::inverse(rotation) * _targetVelocity;
bool isHovering = _characterController.getState() == CharacterController::State::Hover;
glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isHovering);
newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity);
// rotate back into world-frame
_targetVelocity = rotation * newLocalVelocity;
_targetVelocity += _thrust * deltaTime;
_thrust = glm::vec3(0.0f);
// cap avatar speed
float speed = glm::length(_targetVelocity);
if (speed > MAX_AVATAR_SPEED) {
_targetVelocity *= MAX_AVATAR_SPEED / speed;
speed = MAX_AVATAR_SPEED;
if (_motionBehaviors & AVATAR_MOTION_ACTION_MOTOR_ENABLED) {
updateActionMotor(deltaTime);
}
if (speed > MIN_AVATAR_SPEED && !_characterController.isEnabled()) {
// update position ourselves
applyPositionDelta(deltaTime * _targetVelocity);
vec3 velocity = getVelocity();
const float MOVING_SPEED_THRESHOLD_SQUARED = 0.0001f; // 0.01 m/s
if (!_characterController.isEnabled()) {
// _characterController is not in physics simulation but it can still compute its target velocity
updateMotors();
_characterController.computeNewVelocity(deltaTime, velocity);
float speed2 = glm::length2(velocity);
if (speed2 > MIN_AVATAR_SPEED_SQUARED) {
// update position ourselves
applyPositionDelta(deltaTime * velocity);
}
measureMotionDerivatives(deltaTime);
} // else physics will move avatar later
// update _moving flag based on speed
const float MOVING_SPEED_THRESHOLD = 0.01f;
_moving = speed > MOVING_SPEED_THRESHOLD;
_moving = speed2 > MOVING_SPEED_THRESHOLD_SQUARED;
} else {
// physics physics simulation updated elsewhere
float speed2 = glm::length2(velocity);
_moving = speed2 > MOVING_SPEED_THRESHOLD_SQUARED;
}
// capture the head rotation, in sensor space, when the user first indicates they would like to move/fly.
if (!_hoverReferenceCameraFacingIsCaptured && (fabs(_driveKeys[TRANSLATE_Z]) > 0.1f || fabs(_driveKeys[TRANSLATE_X]) > 0.1f)) {
@ -1813,10 +1789,10 @@ void MyAvatar::updateMotionBehaviorFromMenu() {
}
Menu* menu = Menu::getInstance();
if (menu->isOptionChecked(MenuOption::KeyboardMotorControl)) {
_motionBehaviors |= AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED;
if (menu->isOptionChecked(MenuOption::ActionMotorControl)) {
_motionBehaviors |= AVATAR_MOTION_ACTION_MOTOR_ENABLED;
} else {
_motionBehaviors &= ~AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED;
_motionBehaviors &= ~AVATAR_MOTION_ACTION_MOTOR_ENABLED;
}
if (menu->isOptionChecked(MenuOption::ScriptedMotorControl)) {
_motionBehaviors |= AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED;

View file

@ -218,6 +218,7 @@ public:
MyCharacterController* getCharacterController() { return &_characterController; }
const MyCharacterController* getCharacterController() const { return &_characterController; }
void updateMotors();
void prepareForPhysicsSimulation();
void harvestResultsFromPhysicsSimulation(float deltaTime);
@ -350,6 +351,7 @@ private:
float _driveKeys[MAX_DRIVE_KEYS];
bool _wasPushing;
bool _isPushing;
bool _isBeingPushed;
bool _isBraking;
float _boomLength;
@ -358,9 +360,8 @@ private:
glm::vec3 _thrust; // impulse accumulator for outside sources
glm::vec3 _keyboardMotorVelocity; // target local-frame velocity of avatar (keyboard)
float _keyboardMotorTimescale; // timescale for avatar to achieve its target velocity
glm::vec3 _scriptedMotorVelocity; // target local-frame velocity of avatar (script)
glm::vec3 _actionMotorVelocity; // target local-frame velocity of avatar (default controller actions)
glm::vec3 _scriptedMotorVelocity; // target local-frame velocity of avatar (analog script)
float _scriptedMotorTimescale; // timescale for avatar to achieve its target velocity
int _scriptedMotorFrame;
quint32 _motionBehaviors;
@ -384,8 +385,7 @@ private:
// private methods
void updateOrientation(float deltaTime);
glm::vec3 applyKeyboardMotor(float deltaTime, const glm::vec3& velocity, bool isHovering);
glm::vec3 applyScriptedMotor(float deltaTime, const glm::vec3& velocity);
void updateActionMotor(float deltaTime);
void updatePosition(float deltaTime);
void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency);
void initHeadBones();

View file

@ -23,7 +23,6 @@ AddressBarDialog::AddressBarDialog(QQuickItem* parent) : OffscreenQmlDialog(pare
auto addressManager = DependencyManager::get<AddressManager>();
connect(addressManager.data(), &AddressManager::lookupResultIsOffline, this, &AddressBarDialog::displayAddressOfflineMessage);
connect(addressManager.data(), &AddressManager::lookupResultIsNotFound, this, &AddressBarDialog::displayAddressNotFoundMessage);
connect(addressManager.data(), &AddressManager::lookupResultsFinished, this, &AddressBarDialog::hide);
connect(addressManager.data(), &AddressManager::goBackPossible, this, [this] (bool isPossible) {
if (isPossible != _backEnabled) {
_backEnabled = isPossible;
@ -40,10 +39,6 @@ AddressBarDialog::AddressBarDialog(QQuickItem* parent) : OffscreenQmlDialog(pare
_forwardEnabled = !(DependencyManager::get<AddressManager>()->getForwardStack().isEmpty());
}
void AddressBarDialog::hide() {
((QQuickItem*)parent())->setEnabled(false);
}
void AddressBarDialog::loadAddress(const QString& address) {
qDebug() << "Called LoadAddress with address " << address;
if (!address.isEmpty()) {

View file

@ -33,7 +33,6 @@ signals:
protected:
void displayAddressOfflineMessage();
void displayAddressNotFoundMessage();
void hide();
Q_INVOKABLE void loadAddress(const QString& address);
Q_INVOKABLE void loadHome();

View file

@ -13,12 +13,12 @@
#include <avatar/AvatarManager.h>
#include <GLMHelpers.h>
#include <gpu/GLBackendShared.h>
#include <FramebufferCache.h>
#include <GLMHelpers.h>
#include <OffscreenUi.h>
#include <CursorManager.h>
#include <PerfStat.h>
#include <gl/Config.h>
#include "AudioClient.h"
#include "audio/AudioScope.h"
@ -55,7 +55,6 @@ ApplicationOverlay::~ApplicationOverlay() {
// Renders the overlays either to a texture or to the screen
void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
PROFILE_RANGE(__FUNCTION__);
CHECK_GL_ERROR();
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()");
buildFramebufferObject();
@ -89,8 +88,6 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
});
renderArgs->_batch = nullptr; // so future users of renderArgs don't try to use our batch
CHECK_GL_ERROR();
}
void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) {
@ -295,10 +292,6 @@ gpu::TexturePointer ApplicationOverlay::acquireOverlay() {
return gpu::TexturePointer();
}
auto result = _overlayFramebuffer->getRenderBuffer(0);
auto textureId = gpu::GLBackend::getTextureID(result, false);
if (!textureId) {
qDebug() << "Missing texture";
}
_overlayFramebuffer->setRenderBuffer(0, gpu::TexturePointer());
return result;
}

View file

@ -20,14 +20,12 @@ Overlay::Overlay() :
_renderItemID(render::Item::INVALID_ITEM_ID),
_isLoaded(true),
_alpha(DEFAULT_ALPHA),
_glowLevel(0.0f),
_pulse(0.0f),
_pulseMax(0.0f),
_pulseMin(0.0f),
_pulsePeriod(1.0f),
_pulseDirection(1.0f),
_lastPulseUpdate(usecTimestampNow()),
_glowLevelPulse(0.0f),
_alphaPulse(0.0f),
_colorPulse(0.0f),
_color(DEFAULT_OVERLAY_COLOR),
@ -40,14 +38,12 @@ Overlay::Overlay(const Overlay* overlay) :
_renderItemID(render::Item::INVALID_ITEM_ID),
_isLoaded(overlay->_isLoaded),
_alpha(overlay->_alpha),
_glowLevel(overlay->_glowLevel),
_pulse(overlay->_pulse),
_pulseMax(overlay->_pulseMax),
_pulseMin(overlay->_pulseMin),
_pulsePeriod(overlay->_pulsePeriod),
_pulseDirection(overlay->_pulseDirection),
_lastPulseUpdate(usecTimestampNow()),
_glowLevelPulse(overlay->_glowLevelPulse),
_alphaPulse(overlay->_alphaPulse),
_colorPulse(overlay->_colorPulse),
_color(overlay->_color),
@ -69,10 +65,6 @@ void Overlay::setProperties(const QVariantMap& properties) {
if (properties["alpha"].isValid()) {
setAlpha(properties["alpha"].toFloat());
}
if (properties["glowLevel"].isValid()) {
setGlowLevel(properties["glowLevel"].toFloat());
}
if (properties["pulseMax"].isValid()) {
setPulseMax(properties["pulseMax"].toFloat());
@ -86,10 +78,6 @@ void Overlay::setProperties(const QVariantMap& properties) {
setPulsePeriod(properties["pulsePeriod"].toFloat());
}
if (properties["glowLevelPulse"].isValid()) {
setGlowLevelPulse(properties["glowLevelPulse"].toFloat());
}
if (properties["alphaPulse"].isValid()) {
setAlphaPulse(properties["alphaPulse"].toFloat());
}
@ -118,9 +106,6 @@ QVariant Overlay::getProperty(const QString& property) {
if (property == "alpha") {
return _alpha;
}
if (property == "glowLevel") {
return _glowLevel;
}
if (property == "pulseMax") {
return _pulseMax;
}
@ -130,9 +115,6 @@ QVariant Overlay::getProperty(const QString& property) {
if (property == "pulsePeriod") {
return _pulsePeriod;
}
if (property == "glowLevelPulse") {
return _glowLevelPulse;
}
if (property == "alphaPulse") {
return _alphaPulse;
}
@ -176,16 +158,8 @@ float Overlay::getAlpha() {
return (_alphaPulse >= 0.0f) ? _alpha * pulseLevel : _alpha * (1.0f - pulseLevel);
}
float Overlay::getGlowLevel() {
if (_glowLevelPulse == 0.0f) {
return _glowLevel;
}
float pulseLevel = updatePulse();
return (_glowLevelPulse >= 0.0f) ? _glowLevel * pulseLevel : _glowLevel * (1.0f - pulseLevel);
}
// glow level travels from min to max, then max to min in one period.
// pulse travels from min to max, then max to min in one period.
float Overlay::updatePulse() {
if (_pulsePeriod <= 0.0f) {
return _pulse;
@ -196,25 +170,25 @@ float Overlay::updatePulse() {
float elapsedPeriods = elapsedSeconds / _pulsePeriod;
// we can safely remove any "full" periods, since those just rotate us back
// to our final glow level
// to our final pulse level
elapsedPeriods = fmod(elapsedPeriods, 1.0f);
_lastPulseUpdate = now;
float glowDistance = (_pulseMax - _pulseMin);
float glowDistancePerPeriod = glowDistance * 2.0f;
float pulseDistance = (_pulseMax - _pulseMin);
float pulseDistancePerPeriod = pulseDistance * 2.0f;
float glowDelta = _pulseDirection * glowDistancePerPeriod * elapsedPeriods;
float newGlow = _pulse + glowDelta;
float pulseDelta = _pulseDirection * pulseDistancePerPeriod * elapsedPeriods;
float newPulse = _pulse + pulseDelta;
float limit = (_pulseDirection > 0.0f) ? _pulseMax : _pulseMin;
float passedLimit = (_pulseDirection > 0.0f) ? (newGlow >= limit) : (newGlow <= limit);
float passedLimit = (_pulseDirection > 0.0f) ? (newPulse >= limit) : (newPulse <= limit);
if (passedLimit) {
float glowDeltaToLimit = newGlow - limit;
float glowDeltaFromLimitBack = glowDelta - glowDeltaToLimit;
glowDelta = -glowDeltaFromLimitBack;
float pulseDeltaToLimit = newPulse - limit;
float pulseDeltaFromLimitBack = pulseDelta - pulseDeltaToLimit;
pulseDelta = -pulseDeltaFromLimitBack;
_pulseDirection *= -1.0f;
}
_pulse += glowDelta;
_pulse += pulseDelta;
return _pulse;
}

View file

@ -49,7 +49,6 @@ public:
bool getVisible() const { return _visible; }
xColor getColor();
float getAlpha();
float getGlowLevel();
Anchor getAnchor() const { return _anchor; }
float getPulseMax() const { return _pulseMax; }
@ -57,7 +56,6 @@ public:
float getPulsePeriod() const { return _pulsePeriod; }
float getPulseDirection() const { return _pulseDirection; }
float getGlowLevelPulse() const { return _glowLevelPulse; }
float getColorPulse() const { return _colorPulse; }
float getAlphaPulse() const { return _alphaPulse; }
@ -65,7 +63,6 @@ public:
void setVisible(bool visible) { _visible = visible; }
void setColor(const xColor& color) { _color = color; }
void setAlpha(float alpha) { _alpha = alpha; }
void setGlowLevel(float value) { _glowLevel = value; }
void setAnchor(Anchor anchor) { _anchor = anchor; }
void setPulseMax(float value) { _pulseMax = value; }
@ -73,8 +70,6 @@ public:
void setPulsePeriod(float value) { _pulsePeriod = value; }
void setPulseDirection(float value) { _pulseDirection = value; }
void setGlowLevelPulse(float value) { _glowLevelPulse = value; }
void setColorPulse(float value) { _colorPulse = value; }
void setAlphaPulse(float value) { _alphaPulse = value; }
@ -92,7 +87,6 @@ protected:
bool _isLoaded;
float _alpha;
float _glowLevel;
float _pulse;
float _pulseMax;
@ -101,7 +95,6 @@ protected:
float _pulseDirection;
quint64 _lastPulseUpdate;
float _glowLevelPulse; // ratio of the pulse to the glow level
float _alphaPulse; // ratio of the pulse to the alpha
float _colorPulse; // ratio of the pulse to the color

View file

@ -1,3 +1,3 @@
set(TARGET_NAME animation)
setup_hifi_library(Network Script)
link_hifi_libraries(shared gpu model fbx)
link_hifi_libraries(shared model fbx)

View file

@ -65,11 +65,11 @@ using AvatarHash = QHash<QUuid, AvatarSharedPointer>;
using AvatarDataSequenceNumber = uint16_t;
// avatar motion behaviors
const quint32 AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED = 1U << 0;
const quint32 AVATAR_MOTION_ACTION_MOTOR_ENABLED = 1U << 0;
const quint32 AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED = 1U << 1;
const quint32 AVATAR_MOTION_DEFAULTS =
AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED |
AVATAR_MOTION_ACTION_MOTOR_ENABLED |
AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED;
// these bits will be expanded as features are exposed

View file

@ -1,6 +1,6 @@
set(TARGET_NAME display-plugins)
setup_hifi_library(OpenGL)
link_hifi_libraries(shared plugins gl ui)
link_hifi_libraries(shared plugins gl gpu-gl ui)
target_opengl()

View file

@ -17,7 +17,7 @@
#include <QtGui/QImage>
#include <gl/QOpenGLContextWrapper.h>
#include <gpu/Texture.h>
#include <gl/GLWidget.h>
#include <NumericalConstants.h>
#include <DependencyManager.h>
@ -26,7 +26,6 @@
#include <gl/Config.h>
#include <gl/GLEscrow.h>
#include <GLMHelpers.h>
#include <gpu/GLBackend.h>
#include <CursorManager.h>
#include "CompositorHelper.h"
@ -629,14 +628,15 @@ uint32_t OpenGLDisplayPlugin::getSceneTextureId() const {
if (!_currentSceneTexture) {
return 0;
}
return gpu::GLBackend::getTextureID(_currentSceneTexture, false);
return _currentSceneTexture->getHardwareId();
}
uint32_t OpenGLDisplayPlugin::getOverlayTextureId() const {
if (!_currentOverlayTexture) {
return 0;
}
return gpu::GLBackend::getTextureID(_currentOverlayTexture, false);
return _currentOverlayTexture->getHardwareId();
}
void OpenGLDisplayPlugin::eyeViewport(Eye eye) const {

View file

@ -16,7 +16,6 @@
#include <GLMHelpers.h>
#include <plugins/PluginContainer.h>
#include <gpu/GLBackend.h>
#include <CursorManager.h>
#include <gl/GLWidget.h>
#include <shared/NsightHelpers.h>

View file

@ -13,7 +13,6 @@
#include <QtWidgets/QApplication>
#include <QtWidgets/QDesktopWidget>
#include <gpu/GLBackend.h>
#include <ViewFrustum.h>
#include <MatrixStack.h>
#include <plugins/PluginContainer.h>

View file

@ -1,7 +1,7 @@
set(TARGET_NAME entities-renderer)
AUTOSCRIBE_SHADER_LIB(gpu model render render-utils)
setup_hifi_library(Widgets Network Script)
link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils gl)
link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils)
target_bullet()

View file

@ -13,6 +13,7 @@
#include <QEventLoop>
#include <QScriptSyntaxCheckResult>
#include <QThreadPool>
#include <ColorUtils.h>
#include <AbstractScriptingServicesInterface.h>
@ -77,9 +78,30 @@ EntityTreeRenderer::~EntityTreeRenderer() {
int EntityTreeRenderer::_entitiesScriptEngineCount = 0;
void EntityTreeRenderer::setupEntitiesScriptEngine() {
QSharedPointer<ScriptEngine> oldEngine = _entitiesScriptEngine; // save the old engine through this function, so the EntityScriptingInterface doesn't have problems with it.
_entitiesScriptEngine = QSharedPointer<ScriptEngine>(new ScriptEngine(NO_SCRIPT, QString("Entities %1").arg(++_entitiesScriptEngineCount)), &QObject::deleteLater);
void entitiesScriptEngineDeleter(ScriptEngine* engine) {
class WaitRunnable : public QRunnable {
public:
WaitRunnable(ScriptEngine* engine) : _engine(engine) {}
virtual void run() override {
_engine->waitTillDoneRunning();
_engine->deleteLater();
}
private:
ScriptEngine* _engine;
};
// Wait for the scripting thread from the thread pool to avoid hanging the main thread
QThreadPool::globalInstance()->start(new WaitRunnable(engine));
}
void EntityTreeRenderer::resetEntitiesScriptEngine() {
// Keep a ref to oldEngine until newEngine is ready so EntityScriptingInterface has something to use
auto oldEngine = _entitiesScriptEngine;
auto newEngine = new ScriptEngine(NO_SCRIPT, QString("Entities %1").arg(++_entitiesScriptEngineCount));
_entitiesScriptEngine = QSharedPointer<ScriptEngine>(newEngine, entitiesScriptEngineDeleter);
_scriptingServices->registerScriptEngineWithApplicationServices(_entitiesScriptEngine.data());
_entitiesScriptEngine->runInThread();
DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(_entitiesScriptEngine.data());
@ -87,16 +109,16 @@ void EntityTreeRenderer::setupEntitiesScriptEngine() {
void EntityTreeRenderer::clear() {
leaveAllEntities();
if (_entitiesScriptEngine) {
// Unload and stop the engine here (instead of in its deleter) to
// avoid marshalling unload signals back to this thread
_entitiesScriptEngine->unloadAllEntityScripts();
_entitiesScriptEngine->stop();
}
if (_wantScripts && !_shuttingDown) {
// NOTE: you can't actually need to delete it here because when we call setupEntitiesScriptEngine it will
// assign a new instance to our shared pointer, which will deref the old instance and ultimately call
// the custom deleter which calls deleteLater
setupEntitiesScriptEngine();
resetEntitiesScriptEngine();
}
auto scene = _viewState->getMain3DScene();
@ -125,7 +147,7 @@ void EntityTreeRenderer::init() {
entityTree->setFBXService(this);
if (_wantScripts) {
setupEntitiesScriptEngine();
resetEntitiesScriptEngine();
}
forceRecheckEntities(); // setup our state to force checking our inside/outsideness of entities

View file

@ -128,7 +128,7 @@ protected:
}
private:
void setupEntitiesScriptEngine();
void resetEntitiesScriptEngine();
void addEntityToScene(EntityItemPointer entity);
bool findBestZoneAndMaybeContainingEntities(const glm::vec3& avatarPosition, QVector<EntityItemID>* entitiesContainingAvatar);

View file

@ -162,6 +162,19 @@ void RenderableModelEntityItem::remapTextures() {
}
}
void RenderableModelEntityItem::doInitialModelSimulation() {
_model->setScaleToFit(true, getDimensions());
_model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
_model->setRotation(getRotation());
_model->setTranslation(getPosition());
{
PerformanceTimer perfTimer("_model->simulate");
_model->simulate(0.0f);
}
_needsInitialSimulation = false;
}
// TODO: we need a solution for changes to the postion/rotation/etc of a model...
// this current code path only addresses that in this setup case... not the changing/moving case
bool RenderableModelEntityItem::readyToAddToScene(RenderArgs* renderArgs) {
@ -172,22 +185,12 @@ bool RenderableModelEntityItem::readyToAddToScene(RenderArgs* renderArgs) {
getModel(renderer);
}
if (renderArgs && _model && _needsInitialSimulation && _model->isActive() && _model->isLoaded()) {
_model->setScaleToFit(true, getDimensions());
_model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
_model->setRotation(getRotation());
_model->setTranslation(getPosition());
// make sure to simulate so everything gets set up correctly for rendering
{
PerformanceTimer perfTimer("_model->simulate");
_model->simulate(0.0f);
}
_needsInitialSimulation = false;
doInitialModelSimulation();
_model->renderSetup(renderArgs);
}
bool ready = !_needsInitialSimulation && _model && _model->readyToAddToScene(renderArgs);
return ready;
return ready;
}
class RenderableModelEntityItemMeta {
@ -348,18 +351,7 @@ void RenderableModelEntityItem::updateModelBounds() {
_model->getRotation() != getRotation() ||
_model->getRegistrationPoint() != getRegistrationPoint())
&& _model->isActive() && _dimensionsInitialized) {
_model->setScaleToFit(true, dimensions);
_model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
_model->setRotation(getRotation());
_model->setTranslation(getPosition());
// make sure to simulate so everything gets set up correctly for rendering
{
PerformanceTimer perfTimer("_model->simulate");
_model->simulate(0.0f);
}
_needsInitialSimulation = false;
doInitialModelSimulation();
_needsJointSimulation = false;
}
}
@ -592,8 +584,7 @@ bool RenderableModelEntityItem::isReadyToComputeShape() {
if (_needsInitialSimulation) {
// the _model's offset will be wrong until _needsInitialSimulation is false
PerformanceTimer perfTimer("_model->simulate");
_model->simulate(0.0f);
_needsInitialSimulation = false;
doInitialModelSimulation();
}
return true;
@ -807,6 +798,29 @@ void RenderableModelEntityItem::locationChanged(bool tellPhysics) {
if (_model && _model->isActive()) {
_model->setRotation(getRotation());
_model->setTranslation(getPosition());
void* key = (void*)this;
std::weak_ptr<RenderableModelEntityItem> weakSelf =
std::static_pointer_cast<RenderableModelEntityItem>(getThisPointer());
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [weakSelf]() {
auto self = weakSelf.lock();
if (!self) {
return;
}
render::ItemID myMetaItem = self->getMetaRenderItem();
if (myMetaItem == render::Item::INVALID_ITEM_ID) {
return;
}
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
render::PendingChanges pendingChanges;
pendingChanges.updateItem(myMetaItem);
scene->enqueuePendingChanges(pendingChanges);
});
}
}

View file

@ -38,6 +38,8 @@ public:
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override;
void doInitialModelSimulation();
virtual bool readyToAddToScene(RenderArgs* renderArgs = nullptr);
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;
@ -87,6 +89,8 @@ public:
bool hasRenderAnimation() const { return !_renderAnimationProperties.getURL().isEmpty(); }
const QString& getRenderAnimationURL() const { return _renderAnimationProperties.getURL(); }
render::ItemID getMetaRenderItem() { return _myMetaItem; }
private:
QVariantMap parseTexturesToMap(QString textures);
void remapTextures();

View file

@ -1,6 +1,6 @@
set(TARGET_NAME entities)
setup_hifi_library(Network Script)
link_hifi_libraries(avatars shared audio octree gpu model fbx networking animation)
link_hifi_libraries(avatars shared audio octree model fbx networking animation)
target_bullet()

View file

@ -36,9 +36,6 @@ EntityItemProperties BoxEntityItem::getProperties(EntityPropertyFlags desiredPro
properties._color = getXColor();
properties._colorChanged = false;
properties._glowLevel = getGlowLevel();
properties._glowLevelChanged = false;
return properties;
}

View file

@ -46,7 +46,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) :
_lastEditedFromRemoteInRemoteTime(0),
_created(UNKNOWN_CREATED_TIME),
_changedOnServer(0),
_glowLevel(ENTITY_ITEM_DEFAULT_GLOW_LEVEL),
_localRenderAlpha(ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA),
_density(ENTITY_ITEM_DEFAULT_DENSITY),
_volumeMultiplier(1.0f),
@ -1116,7 +1115,6 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper
COPY_ENTITY_PROPERTY_TO_PROPERTIES(registrationPoint, getRegistrationPoint);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(angularVelocity, getLocalAngularVelocity);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(angularDamping, getAngularDamping);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(glowLevel, getGlowLevel);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(localRenderAlpha, getLocalRenderAlpha);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(visible, getVisible);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionless, getCollisionless);
@ -1211,7 +1209,6 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(scriptTimestamp, setScriptTimestamp);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionSoundURL, setCollisionSoundURL);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(glowLevel, setGlowLevel);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(localRenderAlpha, setLocalRenderAlpha);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(visible, setVisible);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(locked, setLocked);

View file

@ -186,9 +186,6 @@ public:
inline const glm::vec3 getDimensions() const { return getScale(); }
virtual void setDimensions(const glm::vec3& value);
float getGlowLevel() const { return _glowLevel; }
void setGlowLevel(float glowLevel) { _glowLevel = glowLevel; }
float getLocalRenderAlpha() const { return _localRenderAlpha; }
void setLocalRenderAlpha(float localRenderAlpha) { _localRenderAlpha = localRenderAlpha; }
@ -460,7 +457,6 @@ protected:
mutable bool _recalcMinAACube = true;
mutable bool _recalcMaxAACube = true;
float _glowLevel;
float _localRenderAlpha;
float _density = ENTITY_ITEM_DEFAULT_DENSITY; // kg/m^3
// NOTE: _volumeMultiplier is used to allow some mass properties code exist in the EntityItem base class

View file

@ -38,10 +38,8 @@ _idSet(false),
_lastEdited(0),
_type(EntityTypes::Unknown),
_glowLevel(0.0f),
_localRenderAlpha(1.0f),
_glowLevelChanged(false),
_localRenderAlphaChanged(false),
_defaultSettings(true),
@ -547,7 +545,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localRotation);
// FIXME - I don't think these properties are supported any more
//COPY_PROPERTY_TO_QSCRIPTVALUE(glowLevel);
//COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha);
return properties;
@ -587,7 +584,6 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitterShouldTrail , bool, setEmitterShouldTrail);
COPY_PROPERTY_FROM_QSCRIPTVALUE(modelURL, QString, setModelURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE(compoundShapeURL, QString, setCompoundShapeURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE(glowLevel, float, setGlowLevel);
COPY_PROPERTY_FROM_QSCRIPTVALUE(localRenderAlpha, float, setLocalRenderAlpha);
COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionless, bool, setCollisionless);
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(ignoreForCollisions, bool, setCollisionless, getCollisionless); // legacy support
@ -1485,7 +1481,6 @@ void EntityItemProperties::markAllChanged() {
_alphaChanged = true;
_modelURLChanged = true;
_compoundShapeURLChanged = true;
_glowLevelChanged = true;
_localRenderAlphaChanged = true;
_isSpotlightChanged = true;
_collisionlessChanged = true;

View file

@ -221,9 +221,7 @@ public:
bool containsPositionChange() const { return _positionChanged; }
bool containsDimensionsChange() const { return _dimensionsChanged; }
float getGlowLevel() const { return _glowLevel; }
float getLocalRenderAlpha() const { return _localRenderAlpha; }
void setGlowLevel(float value) { _glowLevel = value; _glowLevelChanged = true; }
void setLocalRenderAlpha(float value) { _localRenderAlpha = value; _localRenderAlphaChanged = true; }
static bool encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties,
@ -234,7 +232,6 @@ public:
static bool decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes,
EntityItemID& entityID, EntityItemProperties& properties);
bool glowLevelChanged() const { return _glowLevelChanged; }
bool localRenderAlphaChanged() const { return _localRenderAlphaChanged; }
void clearID() { _id = UNKNOWN_ENTITY_ID; _idSet = false; }
@ -290,9 +287,7 @@ private:
EntityTypes::EntityType _type;
void setType(const QString& typeName) { _type = EntityTypes::getEntityTypeFromName(typeName); }
float _glowLevel;
float _localRenderAlpha;
bool _glowLevelChanged;
bool _localRenderAlphaChanged;
bool _defaultSettings;
bool _dimensionsInitialized = true; // Only false if creating an entity localy with no dimensions properties

View file

@ -31,7 +31,6 @@ const QUuid ENTITY_ITEM_DEFAULT_SIMULATOR_ID = QUuid();
const float ENTITY_ITEM_DEFAULT_ALPHA = 1.0f;
const float ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA = 1.0f;
const float ENTITY_ITEM_DEFAULT_GLOW_LEVEL = 0.0f;
const bool ENTITY_ITEM_DEFAULT_VISIBLE = true;
const QString ENTITY_ITEM_DEFAULT_SCRIPT = QString("");

View file

@ -53,10 +53,6 @@ EntityItemProperties LineEntityItem::getProperties(EntityPropertyFlags desiredPr
COPY_ENTITY_PROPERTY_TO_PROPERTIES(linePoints, getLinePoints);
properties._glowLevel = getGlowLevel();
properties._glowLevelChanged = false;
return properties;
}

View file

@ -58,7 +58,6 @@ EntityItemProperties ModelEntityItem::getProperties(EntityPropertyFlags desiredP
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(modelURL, getModelURL);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(glowLevel, getGlowLevel);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(jointRotationsSet, getJointRotationsSet);

View file

@ -304,7 +304,6 @@ EntityItemProperties ParticleEffectEntityItem::getProperties(EntityPropertyFlags
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(glowLevel, getGlowLevel);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType); // FIXME - this doesn't appear to get used
COPY_ENTITY_PROPERTY_TO_PROPERTIES(maxParticles, getMaxParticles);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lifespan, getLifespan);
@ -343,7 +342,6 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(glowLevel, setGlowLevel);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, updateShapeType);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(maxParticles, setMaxParticles);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifespan, setLifespan);

View file

@ -58,9 +58,6 @@ EntityItemProperties PolyLineEntityItem::getProperties(EntityPropertyFlags desir
COPY_ENTITY_PROPERTY_TO_PROPERTIES(normals, getNormals);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(strokeWidths, getStrokeWidths);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures);
properties._glowLevel = getGlowLevel();
properties._glowLevelChanged = false;
return properties;
}

View file

@ -23,7 +23,6 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTreePointer tree,
_foundOld(false),
_foundNew(false),
_removeOld(false),
_dontMove(false), // assume we'll be moving
_changeTime(usecTimestampNow()),
_oldEntityCube(),
_newEntityCube(),
@ -43,32 +42,23 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTreePointer tree,
_oldEntityCube = _existingEntity->getQueryAACube();
_oldEntityBox = _oldEntityCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); // clamp to domain bounds
// If our new properties don't have bounds details (no change to position, etc) or if this containing element would
// be the best fit for our new properties, then just do the new portion of the store pass, since the change path will
// be the same for both parts of the update
bool oldElementBestFit = _containingElement->bestFitBounds(newQueryAACube);
_newEntityCube = newQueryAACube;
_newEntityBox = _newEntityCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); // clamp to domain bounds
// set oldElementBestFit true if the entity was in the correct element before this operator was run.
bool oldElementBestFit = _containingElement->bestFitBounds(_oldEntityBox);
// For some reason we've seen a case where the original containing element isn't a best fit for the old properties
// in this case we want to move it, even if the properties haven't changed.
if (!oldElementBestFit) {
_newEntityCube = _oldEntityCube;
_oldEntityBox = _existingEntity->getElement()->getAACube();
_removeOld = true; // our properties are going to move us, so remember this for later processing
if (_wantDebug) {
qCDebug(entities) << " **** UNUSUAL CASE **** no changes, but not best fit... consider it a move.... **";
}
} else {
_foundOld = true;
_newEntityCube = _oldEntityCube;
_dontMove = true;
if (_wantDebug) {
qCDebug(entities) << " **** TYPICAL NO MOVE CASE **** oldElementBestFit:" << oldElementBestFit;
qCDebug(entities) << " **** UNUSUAL CASE **** not best fit.... **";
}
}
_newEntityBox = _newEntityCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); // clamp to domain bounds
if (_wantDebug) {
qCDebug(entities) << " _entityItemID:" << _entityItemID;
qCDebug(entities) << " _containingElementCube:" << _containingElementCube;

View file

@ -37,7 +37,6 @@ private:
bool _foundOld;
bool _foundNew;
bool _removeOld;
bool _dontMove;
quint64 _changeTime;
AACube _oldEntityCube;

View file

@ -1,3 +1,3 @@
set(TARGET_NAME fbx)
setup_hifi_library()
link_hifi_libraries(shared gpu model networking octree)
link_hifi_libraries(shared model networking)

View file

@ -12,47 +12,21 @@
#ifndef hifi_gpu_GPUConfig_h
#define hifi_gpu_GPUConfig_h
#define GL_GLEXT_PROTOTYPES 1
#define GPU_CORE 1
#define GPU_LEGACY 0
#define GPU_CORE_41 410
#define GPU_CORE_43 430
#define GPU_CORE_MINIMUM GPU_CORE_41
#if defined(__APPLE__)
#include <GL/glew.h>
#define GPU_FEATURE_PROFILE GPU_CORE
#define GPU_INPUT_PROFILE GPU_CORE_41
#if defined(__APPLE__)
#include <OpenGL/gl.h>
#include <OpenGL/glext.h>
#elif defined(WIN32)
#include <GL/glew.h>
#endif
#if defined(WIN32)
#include <GL/wglew.h>
#define GPU_FEATURE_PROFILE GPU_CORE
#define GPU_INPUT_PROFILE GPU_CORE_43
#else
#include <GL/glew.h>
#define GPU_FEATURE_PROFILE GPU_CORE
#define GPU_INPUT_PROFILE GPU_CORE_43
#endif
#if (GPU_INPUT_PROFILE == GPU_CORE_43)
// Deactivate SSBO for now, we've run into some issues
// on GL 4.3 capable GPUs not behaving as expected
//#define GPU_SSBO_DRAW_CALL_INFO
#endif
#endif // hifi_gpu_GPUConfig_h

View file

@ -19,6 +19,8 @@
#include "GLWidget.h"
#include "GLHelpers.h"
#define MINIMUM_GL_VERSION 410
OpenGLVersionChecker::OpenGLVersionChecker(int& argc, char** argv) :
QApplication(argc, argv)
{
@ -58,8 +60,8 @@ QJsonObject OpenGLVersionChecker::checkVersion(bool& valid, bool& override) {
QStringList versionParts = glVersion.split(QRegularExpression("[\\.\\s]"));
int majorNumber = versionParts[0].toInt();
int minorNumber = versionParts[1].toInt();
int minimumMajorNumber = GPU_CORE_MINIMUM / 100;
int minimumMinorNumber = (GPU_CORE_MINIMUM - minimumMajorNumber * 100) / 10;
int minimumMajorNumber = MINIMUM_GL_VERSION / 100;
int minimumMinorNumber = (MINIMUM_GL_VERSION - minimumMajorNumber * 100) / 10;
valid = (majorNumber > minimumMajorNumber
|| (majorNumber == minimumMajorNumber && minorNumber >= minimumMinorNumber));

View file

@ -13,6 +13,17 @@
#include <QOpenGLContext>
uint32_t QOpenGLContextWrapper::currentContextVersion() {
QOpenGLContext* context = QOpenGLContext::currentContext();
if (!context) {
return 0;
}
auto format = context->format();
auto version = (format.majorVersion() << 8) + format.minorVersion();
return version;
}
QOpenGLContext* QOpenGLContextWrapper::currentContext() {
return QOpenGLContext::currentContext();
}

View file

@ -12,6 +12,8 @@
#ifndef hifi_QOpenGLContextWrapper_h
#define hifi_QOpenGLContextWrapper_h
#include <stdint.h>
class QOpenGLContext;
class QSurface;
class QSurfaceFormat;
@ -30,6 +32,7 @@ public:
void moveToThread(QThread* thread);
static QOpenGLContext* currentContext();
static uint32_t currentContextVersion();
QOpenGLContext* getContext() {
return _context;

View file

@ -0,0 +1,8 @@
set(TARGET_NAME gpu-gl)
AUTOSCRIBE_SHADER_LIB(gpu)
setup_hifi_library()
link_hifi_libraries(shared gl gpu)
GroupSources("src")
target_glew()
target_opengl()

View file

@ -8,112 +8,133 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackendShared.h"
#include "GLBackend.h"
#include <mutex>
#include <queue>
#include <list>
#include <functional>
#include <glm/gtc/type_ptr.hpp>
#include <GPUIdent.h>
#include <NumericalConstants.h>
#if defined(NSIGHT_FOUND)
#include "nvToolsExt.h"
#endif
#include <GPUIdent.h>
#include <NumericalConstants.h>
#include "GLBackendShared.h"
using namespace gpu;
using namespace gpu::gl;
GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
{
(&::gpu::GLBackend::do_draw),
(&::gpu::GLBackend::do_drawIndexed),
(&::gpu::GLBackend::do_drawInstanced),
(&::gpu::GLBackend::do_drawIndexedInstanced),
(&::gpu::GLBackend::do_multiDrawIndirect),
(&::gpu::GLBackend::do_multiDrawIndexedIndirect),
(&::gpu::gl::GLBackend::do_draw),
(&::gpu::gl::GLBackend::do_drawIndexed),
(&::gpu::gl::GLBackend::do_drawInstanced),
(&::gpu::gl::GLBackend::do_drawIndexedInstanced),
(&::gpu::gl::GLBackend::do_multiDrawIndirect),
(&::gpu::gl::GLBackend::do_multiDrawIndexedIndirect),
(&::gpu::GLBackend::do_setInputFormat),
(&::gpu::GLBackend::do_setInputBuffer),
(&::gpu::GLBackend::do_setIndexBuffer),
(&::gpu::GLBackend::do_setIndirectBuffer),
(&::gpu::gl::GLBackend::do_setInputFormat),
(&::gpu::gl::GLBackend::do_setInputBuffer),
(&::gpu::gl::GLBackend::do_setIndexBuffer),
(&::gpu::gl::GLBackend::do_setIndirectBuffer),
(&::gpu::GLBackend::do_setModelTransform),
(&::gpu::GLBackend::do_setViewTransform),
(&::gpu::GLBackend::do_setProjectionTransform),
(&::gpu::GLBackend::do_setViewportTransform),
(&::gpu::GLBackend::do_setDepthRangeTransform),
(&::gpu::gl::GLBackend::do_setModelTransform),
(&::gpu::gl::GLBackend::do_setViewTransform),
(&::gpu::gl::GLBackend::do_setProjectionTransform),
(&::gpu::gl::GLBackend::do_setViewportTransform),
(&::gpu::gl::GLBackend::do_setDepthRangeTransform),
(&::gpu::GLBackend::do_setPipeline),
(&::gpu::GLBackend::do_setStateBlendFactor),
(&::gpu::GLBackend::do_setStateScissorRect),
(&::gpu::gl::GLBackend::do_setPipeline),
(&::gpu::gl::GLBackend::do_setStateBlendFactor),
(&::gpu::gl::GLBackend::do_setStateScissorRect),
(&::gpu::GLBackend::do_setUniformBuffer),
(&::gpu::GLBackend::do_setResourceTexture),
(&::gpu::gl::GLBackend::do_setUniformBuffer),
(&::gpu::gl::GLBackend::do_setResourceTexture),
(&::gpu::GLBackend::do_setFramebuffer),
(&::gpu::GLBackend::do_clearFramebuffer),
(&::gpu::GLBackend::do_blit),
(&::gpu::GLBackend::do_generateTextureMips),
(&::gpu::gl::GLBackend::do_setFramebuffer),
(&::gpu::gl::GLBackend::do_clearFramebuffer),
(&::gpu::gl::GLBackend::do_blit),
(&::gpu::gl::GLBackend::do_generateTextureMips),
(&::gpu::GLBackend::do_beginQuery),
(&::gpu::GLBackend::do_endQuery),
(&::gpu::GLBackend::do_getQuery),
(&::gpu::gl::GLBackend::do_beginQuery),
(&::gpu::gl::GLBackend::do_endQuery),
(&::gpu::gl::GLBackend::do_getQuery),
(&::gpu::GLBackend::do_resetStages),
(&::gpu::gl::GLBackend::do_resetStages),
(&::gpu::GLBackend::do_runLambda),
(&::gpu::gl::GLBackend::do_runLambda),
(&::gpu::GLBackend::do_startNamedCall),
(&::gpu::GLBackend::do_stopNamedCall),
(&::gpu::gl::GLBackend::do_startNamedCall),
(&::gpu::gl::GLBackend::do_stopNamedCall),
(&::gpu::GLBackend::do_glActiveBindTexture),
(&::gpu::gl::GLBackend::do_glActiveBindTexture),
(&::gpu::GLBackend::do_glUniform1i),
(&::gpu::GLBackend::do_glUniform1f),
(&::gpu::GLBackend::do_glUniform2f),
(&::gpu::GLBackend::do_glUniform3f),
(&::gpu::GLBackend::do_glUniform4f),
(&::gpu::GLBackend::do_glUniform3fv),
(&::gpu::GLBackend::do_glUniform4fv),
(&::gpu::GLBackend::do_glUniform4iv),
(&::gpu::GLBackend::do_glUniformMatrix4fv),
(&::gpu::gl::GLBackend::do_glUniform1i),
(&::gpu::gl::GLBackend::do_glUniform1f),
(&::gpu::gl::GLBackend::do_glUniform2f),
(&::gpu::gl::GLBackend::do_glUniform3f),
(&::gpu::gl::GLBackend::do_glUniform4f),
(&::gpu::gl::GLBackend::do_glUniform3fv),
(&::gpu::gl::GLBackend::do_glUniform4fv),
(&::gpu::gl::GLBackend::do_glUniform4iv),
(&::gpu::gl::GLBackend::do_glUniformMatrix4fv),
(&::gpu::GLBackend::do_glColor4f),
(&::gpu::gl::GLBackend::do_glColor4f),
(&::gpu::GLBackend::do_pushProfileRange),
(&::gpu::GLBackend::do_popProfileRange),
(&::gpu::gl::GLBackend::do_pushProfileRange),
(&::gpu::gl::GLBackend::do_popProfileRange),
};
extern std::function<uint32(const Texture& texture)> TEXTURE_ID_RESOLVER;
void GLBackend::init() {
static std::once_flag once;
std::call_once(once, [] {
TEXTURE_ID_RESOLVER = [](const Texture& texture)->uint32 {
auto object = Backend::getGPUObject<GLBackend::GLTexture>(texture);
if (!object) {
return 0;
}
if (object->getSyncState() != GLTexture::Idle) {
if (object->_downsampleSource) {
return object->_downsampleSource->_texture;
}
return 0;
}
return object->_texture;
};
QString vendor{ (const char*)glGetString(GL_VENDOR) };
QString renderer{ (const char*)glGetString(GL_RENDERER) };
qCDebug(gpulogging) << "GL Version: " << QString((const char*) glGetString(GL_VERSION));
qCDebug(gpulogging) << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION));
qCDebug(gpulogging) << "GL Vendor: " << vendor;
qCDebug(gpulogging) << "GL Renderer: " << renderer;
qCDebug(gpugllogging) << "GL Version: " << QString((const char*) glGetString(GL_VERSION));
qCDebug(gpugllogging) << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION));
qCDebug(gpugllogging) << "GL Vendor: " << vendor;
qCDebug(gpugllogging) << "GL Renderer: " << renderer;
GPUIdent* gpu = GPUIdent::getInstance(vendor, renderer);
// From here on, GPUIdent::getInstance()->getMumble() should efficiently give the same answers.
qCDebug(gpulogging) << "GPU:";
qCDebug(gpulogging) << "\tcard:" << gpu->getName();
qCDebug(gpulogging) << "\tdriver:" << gpu->getDriver();
qCDebug(gpulogging) << "\tdedicated memory:" << gpu->getMemory() << "MB";
qCDebug(gpugllogging) << "GPU:";
qCDebug(gpugllogging) << "\tcard:" << gpu->getName();
qCDebug(gpugllogging) << "\tdriver:" << gpu->getDriver();
qCDebug(gpugllogging) << "\tdedicated memory:" << gpu->getMemory() << "MB";
glewExperimental = true;
GLenum err = glewInit();
glGetError(); // clear the potential error from glewExperimental
if (GLEW_OK != err) {
// glewInit failed, something is seriously wrong.
qCDebug(gpulogging, "Error: %s\n", glewGetErrorString(err));
qCDebug(gpugllogging, "Error: %s\n", glewGetErrorString(err));
}
qCDebug(gpulogging, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
qCDebug(gpugllogging, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
#if defined(Q_OS_WIN)
if (wglewGetExtension("WGL_EXT_swap_control")) {
int swapInterval = wglGetSwapIntervalEXT();
qCDebug(gpulogging, "V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF"));
qCDebug(gpugllogging, "V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF"));
}
#endif
@ -121,7 +142,7 @@ void GLBackend::init() {
// TODO: Write the correct code for Linux...
/* if (wglewGetExtension("WGL_EXT_swap_control")) {
int swapInterval = wglGetSwapIntervalEXT();
qCDebug(gpulogging, "V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF"));
qCDebug(gpugllogging, "V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF"));
}*/
#endif
});
@ -316,47 +337,6 @@ void GLBackend::render(Batch& batch) {
_stereo._enable = savedStereo;
}
bool GLBackend::checkGLError(const char* name) {
GLenum error = glGetError();
if (!error) {
return false;
}
else {
switch (error) {
case GL_INVALID_ENUM:
qCDebug(gpulogging) << "GLBackend::" << name << ": An unacceptable value is specified for an enumerated argument.The offending command is ignored and has no other side effect than to set the error flag.";
break;
case GL_INVALID_VALUE:
qCDebug(gpulogging) << "GLBackend" << name << ": A numeric argument is out of range.The offending command is ignored and has no other side effect than to set the error flag";
break;
case GL_INVALID_OPERATION:
qCDebug(gpulogging) << "GLBackend" << name << ": The specified operation is not allowed in the current state.The offending command is ignored and has no other side effect than to set the error flag..";
break;
case GL_INVALID_FRAMEBUFFER_OPERATION:
qCDebug(gpulogging) << "GLBackend" << name << ": The framebuffer object is not complete.The offending command is ignored and has no other side effect than to set the error flag.";
break;
case GL_OUT_OF_MEMORY:
qCDebug(gpulogging) << "GLBackend" << name << ": There is not enough memory left to execute the command.The state of the GL is undefined, except for the state of the error flags, after this error is recorded.";
break;
case GL_STACK_UNDERFLOW:
qCDebug(gpulogging) << "GLBackend" << name << ": An attempt has been made to perform an operation that would cause an internal stack to underflow.";
break;
case GL_STACK_OVERFLOW:
qCDebug(gpulogging) << "GLBackend" << name << ": An attempt has been made to perform an operation that would cause an internal stack to overflow.";
break;
}
return true;
}
}
bool GLBackend::checkGLErrorDebug(const char* name) {
#ifdef DEBUG
return checkGLError(name);
#else
Q_UNUSED(name);
return false;
#endif
}
void GLBackend::syncCache() {
syncTransformStateCache();

View file

@ -19,18 +19,46 @@
#include <list>
#include <array>
#include <QtCore/QLoggingCategory>
#include <gl/Config.h>
#include "Context.h"
#include <gpu/Forward.h>
#include <gpu/Context.h>
namespace gpu {
#define GPU_CORE 1
#define GPU_LEGACY 0
#define GPU_CORE_41 410
#define GPU_CORE_43 430
#define GPU_CORE_MINIMUM GPU_CORE_41
#define GPU_FEATURE_PROFILE GPU_CORE
#if defined(__APPLE__)
#define GPU_INPUT_PROFILE GPU_CORE_41
#else
#define GPU_INPUT_PROFILE GPU_CORE_43
#endif
#if (GPU_INPUT_PROFILE == GPU_CORE_43)
// Deactivate SSBO for now, we've run into some issues
// on GL 4.3 capable GPUs not behaving as expected
//#define GPU_SSBO_DRAW_CALL_INFO
#endif
namespace gpu { namespace gl {
class GLTextureTransferHelper;
class GLBackend : public Backend {
// Context Backend static interface required
friend class Context;
friend class gpu::Context;
static void init();
static Backend* createBackend();
static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings);
@ -54,11 +82,6 @@ public:
// Just avoid using it, it's ugly and will break performances
virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage);
static bool checkGLError(const char* name = nullptr);
// Only checks in debug builds
static bool checkGLErrorDebug(const char* name = nullptr);
static void checkGLStackStable(std::function<void()> f);
@ -72,7 +95,7 @@ public:
GLBuffer(const Buffer& buffer, GLBuffer* original = nullptr);
~GLBuffer();
void transfer();
virtual void transfer();
private:
bool getNextTransferBlock(GLintptr& outOffset, GLsizeiptr& outSize, size_t& currentPage) const;
@ -626,6 +649,9 @@ protected:
};
};
} }
Q_DECLARE_LOGGING_CATEGORY(gpugllogging)
#endif

View file

@ -8,9 +8,11 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackend.h"
#include "GLBackendShared.h"
using namespace gpu;
using namespace gpu::gl;
GLuint allocateSingleBuffer() {
GLuint result;

View file

@ -8,9 +8,11 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackend.h"
#include "GLBackendShared.h"
using namespace gpu;
using namespace gpu::gl;
void GLBackend::do_setInputFormat(Batch& batch, size_t paramOffset) {
Stream::FormatPointer format = batch._streamFormats.get(batch._params[paramOffset]._uint);

View file

@ -8,13 +8,14 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <qimage.h>
#include "GLBackend.h"
#include <QtGui/QImage>
#include "GPULogging.h"
#include "GLBackendShared.h"
using namespace gpu;
using namespace gpu::gl;
GLBackend::GLFramebuffer::GLFramebuffer() {}
@ -97,19 +98,6 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe
unit++;
}
}
#if (GPU_FEATURE_PROFILE == GPU_LEGACY)
// for reasons that i don't understand yet, it seems that on mac gl, a fbo must have a color buffer...
else {
GLuint renderBuffer = 0;
glGenRenderbuffers(1, &renderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, framebuffer.getWidth(), framebuffer.getHeight());
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer);
(void) CHECK_GL_ERROR();
}
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
#endif
object->_colorStamps = framebuffer.getColorStamps();
}
@ -157,19 +145,19 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe
result = true;
break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT :
qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT.";
qCDebug(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT.";
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT :
qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT.";
qCDebug(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT.";
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER :
qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER.";
qCDebug(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER.";
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER :
qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER.";
qCDebug(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER.";
break;
case GL_FRAMEBUFFER_UNSUPPORTED :
qCDebug(gpulogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_UNSUPPORTED.";
qCDebug(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_UNSUPPORTED.";
break;
}
if (!result && object->_fbo) {
@ -354,26 +342,26 @@ void GLBackend::do_blit(Batch& batch, size_t paramOffset) {
}
void GLBackend::downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) {
auto readFBO = gpu::GLBackend::getFramebufferID(srcFramebuffer);
auto readFBO = getFramebufferID(srcFramebuffer);
if (srcFramebuffer && readFBO) {
if ((srcFramebuffer->getWidth() < (region.x + region.z)) || (srcFramebuffer->getHeight() < (region.y + region.w))) {
qCDebug(gpulogging) << "GLBackend::downloadFramebuffer : srcFramebuffer is too small to provide the region queried";
qCDebug(gpugllogging) << "GLBackend::downloadFramebuffer : srcFramebuffer is too small to provide the region queried";
return;
}
}
if ((destImage.width() < region.z) || (destImage.height() < region.w)) {
qCDebug(gpulogging) << "GLBackend::downloadFramebuffer : destImage is too small to receive the region of the framebuffer";
qCDebug(gpugllogging) << "GLBackend::downloadFramebuffer : destImage is too small to receive the region of the framebuffer";
return;
}
GLenum format = GL_BGRA;
if (destImage.format() != QImage::Format_ARGB32) {
qCDebug(gpulogging) << "GLBackend::downloadFramebuffer : destImage format must be FORMAT_ARGB32 to receive the region of the framebuffer";
qCDebug(gpugllogging) << "GLBackend::downloadFramebuffer : destImage format must be FORMAT_ARGB32 to receive the region of the framebuffer";
return;
}
glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(srcFramebuffer));
glBindFramebuffer(GL_READ_FRAMEBUFFER, getFramebufferID(srcFramebuffer));
glReadPixels(region.x, region.y, region.z, region.w, format, GL_UNSIGNED_BYTE, destImage.bits());
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);

View file

@ -8,11 +8,11 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackend.h"
#include "GLBackendShared.h"
#include "Format.h"
using namespace gpu;
using namespace gpu::gl;
GLBackend::GLPipeline::GLPipeline() :
_program(nullptr),
@ -157,7 +157,6 @@ void GLBackend::resetPipelineStage() {
void GLBackend::releaseUniformBuffer(uint32_t slot) {
#if (GPU_FEATURE_PROFILE == GPU_CORE)
auto& buf = _uniform._buffers[slot];
if (buf) {
auto* object = Backend::getGPUObject<GLBackend::GLBuffer>(*buf);
@ -168,7 +167,6 @@ void GLBackend::releaseUniformBuffer(uint32_t slot) {
}
buf.reset();
}
#endif
}
void GLBackend::resetUniformStage() {
@ -186,7 +184,6 @@ void GLBackend::do_setUniformBuffer(Batch& batch, size_t paramOffset) {
#if (GPU_FEATURE_PROFILE == GPU_CORE)
if (!uniformBuffer) {
releaseUniformBuffer(slot);
return;
@ -208,21 +205,6 @@ void GLBackend::do_setUniformBuffer(Batch& batch, size_t paramOffset) {
releaseResourceTexture(slot);
return;
}
#else
// because we rely on the program uniform mechanism we need to have
// the program bound, thank you MacOSX Legacy profile.
updatePipeline();
GLfloat* data = (GLfloat*) (uniformBuffer->getData() + rangeStart);
glUniform4fv(slot, rangeSize / sizeof(GLfloat[4]), data);
// NOT working so we ll stick to the uniform float array until we move to core profile
// GLuint bo = getBufferID(*uniformBuffer);
//glUniformBufferEXT(_shader._program, slot, bo);
(void) CHECK_GL_ERROR();
#endif
}
void GLBackend::releaseResourceTexture(uint32_t slot) {

View file

@ -8,10 +8,11 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackend.h"
#include "GLBackendShared.h"
using namespace gpu;
using namespace gpu::gl;
GLBackend::GLQuery::GLQuery() {}
@ -64,12 +65,7 @@ void GLBackend::do_beginQuery(Batch& batch, size_t paramOffset) {
auto query = batch._queries.get(batch._params[paramOffset]._uint);
GLQuery* glquery = syncGPUObject(*query);
if (glquery) {
#if (GPU_FEATURE_PROFILE == GPU_LEGACY)
// (EXT_TIMER_QUERY)
glBeginQuery(GL_TIME_ELAPSED_EXT, glquery->_qo);
#else
glBeginQuery(GL_TIME_ELAPSED, glquery->_qo);
#endif
glBeginQuery(GL_TIME_ELAPSED, glquery->_qo);
(void)CHECK_GL_ERROR();
}
}
@ -78,12 +74,7 @@ void GLBackend::do_endQuery(Batch& batch, size_t paramOffset) {
auto query = batch._queries.get(batch._params[paramOffset]._uint);
GLQuery* glquery = syncGPUObject(*query);
if (glquery) {
#if (GPU_FEATURE_PROFILE == GPU_LEGACY)
// (EXT_TIMER_QUERY)
glEndQuery(GL_TIME_ELAPSED_EXT);
#else
glEndQuery(GL_TIME_ELAPSED);
#endif
glEndQuery(GL_TIME_ELAPSED);
(void)CHECK_GL_ERROR();
}
}
@ -92,18 +83,11 @@ void GLBackend::do_getQuery(Batch& batch, size_t paramOffset) {
auto query = batch._queries.get(batch._params[paramOffset]._uint);
GLQuery* glquery = syncGPUObject(*query);
if (glquery) {
#if (GPU_FEATURE_PROFILE == GPU_LEGACY)
// (EXT_TIMER_QUERY)
#if !defined(Q_OS_LINUX)
glGetQueryObjectui64vEXT(glquery->_qo, GL_QUERY_RESULT, &glquery->_result);
#endif
#else
glGetQueryObjectui64v(glquery->_qo, GL_QUERY_RESULT_AVAILABLE, &glquery->_result);
if (glquery->_result == GL_TRUE) {
glGetQueryObjectui64v(glquery->_qo, GL_QUERY_RESULT, &glquery->_result);
query->triggerReturnHandler(glquery->_result);
}
#endif
glGetQueryObjectui64v(glquery->_qo, GL_QUERY_RESULT_AVAILABLE, &glquery->_result);
if (glquery->_result == GL_TRUE) {
glGetQueryObjectui64v(glquery->_qo, GL_QUERY_RESULT, &glquery->_result);
query->triggerReturnHandler(glquery->_result);
}
(void)CHECK_GL_ERROR();
}
}

View file

@ -8,10 +8,11 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackend.h"
#include "GLBackendShared.h"
#include "Format.h"
using namespace gpu;
using namespace gpu::gl;
GLBackend::GLShader::GLShader()
{
@ -30,14 +31,14 @@ GLBackend::GLShader::~GLShader() {
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject) {
if (shaderSource.empty()) {
qCDebug(gpulogging) << "GLShader::compileShader - no GLSL shader source code ? so failed to create";
qCDebug(gpugllogging) << "GLShader::compileShader - no GLSL shader source code ? so failed to create";
return false;
}
// Create the shader object
GLuint glshader = glCreateShader(shaderDomain);
if (!glshader) {
qCDebug(gpulogging) << "GLShader::compileShader - failed to create the gl shader object";
qCDebug(gpugllogging) << "GLShader::compileShader - failed to create the gl shader object";
return false;
}
@ -79,12 +80,12 @@ bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const s
}
*/
qCWarning(gpulogging) << "GLShader::compileShader - failed to compile the gl shader object:";
qCWarning(gpugllogging) << "GLShader::compileShader - failed to compile the gl shader object:";
for (auto s : srcstr) {
qCWarning(gpulogging) << s;
qCWarning(gpugllogging) << s;
}
qCWarning(gpulogging) << "GLShader::compileShader - errors:";
qCWarning(gpulogging) << temp;
qCWarning(gpugllogging) << "GLShader::compileShader - errors:";
qCWarning(gpugllogging) << temp;
delete[] temp;
glDeleteShader(glshader);
@ -96,7 +97,7 @@ bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const s
// so far so good, program is almost done, need to link:
GLuint glprogram = glCreateProgram();
if (!glprogram) {
qCDebug(gpulogging) << "GLShader::compileShader - failed to create the gl shader & gl program object";
qCDebug(gpugllogging) << "GLShader::compileShader - failed to create the gl shader & gl program object";
return false;
}
@ -124,8 +125,8 @@ bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const s
char* temp = new char[infoLength];
glGetProgramInfoLog(glprogram, infoLength, NULL, temp);
qCDebug(gpulogging) << "GLShader::compileShader - failed to LINK the gl program object :";
qCDebug(gpulogging) << temp;
qCDebug(gpugllogging) << "GLShader::compileShader - failed to LINK the gl program object :";
qCDebug(gpugllogging) << temp;
/*
filestream.open("debugshader.glsl.info.txt");
@ -152,7 +153,7 @@ GLuint compileProgram(const std::vector<GLuint>& glshaders) {
// A brand new program:
GLuint glprogram = glCreateProgram();
if (!glprogram) {
qCDebug(gpulogging) << "GLShader::compileProgram - failed to create the gl program object";
qCDebug(gpugllogging) << "GLShader::compileProgram - failed to create the gl program object";
return 0;
}
@ -185,8 +186,8 @@ GLuint compileProgram(const std::vector<GLuint>& glshaders) {
char* temp = new char[infoLength];
glGetProgramInfoLog(glprogram, infoLength, NULL, temp);
qCDebug(gpulogging) << "GLShader::compileProgram - failed to LINK the gl program object :";
qCDebug(gpulogging) << temp;
qCDebug(gpugllogging) << "GLShader::compileProgram - failed to LINK the gl program object :";
qCDebug(gpugllogging) << temp;
/*
filestream.open("debugshader.glsl.info.txt");
@ -264,7 +265,7 @@ void makeProgramBindings(GLBackend::GLShader::ShaderObject& shaderObject) {
GLint linked = 0;
glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
if (!linked) {
qCDebug(gpulogging) << "GLShader::makeBindings - failed to link after assigning slotBindings?";
qCDebug(gpugllogging) << "GLShader::makeBindings - failed to link after assigning slotBindings?";
}
// now assign the ubo binding, then DON't relink!
@ -358,7 +359,7 @@ GLBackend::GLShader* compileBackendProgram(const Shader& program) {
if (object) {
shaderGLObjects.push_back(object->_shaderObjects[version].glshader);
} else {
qCDebug(gpulogging) << "GLShader::compileBackendProgram - One of the shaders of the program is not compiled?";
qCDebug(gpugllogging) << "GLShader::compileBackendProgram - One of the shaders of the program is not compiled?";
return nullptr;
}
}
@ -559,19 +560,9 @@ ElementResource getFormatFromGLUniform(GLenum gltype) {
int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,
Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers
#if (GPU_FEATURE_PROFILE == GPU_LEGACY)
, Shader::SlotSet& fakeBuffers
#endif
) {
Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers) {
GLint uniformsCount = 0;
#if (GPU_FEATURE_PROFILE == GPU_LEGACY)
GLint currentProgram = 0;
glGetIntegerv(GL_CURRENT_PROGRAM, &currentProgram);
glUseProgram(glprogram);
#endif
glGetProgramiv(glprogram, GL_ACTIVE_UNIFORMS, &uniformsCount);
for (int i = 0; i < uniformsCount; i++) {
@ -604,15 +595,6 @@ int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,
}
if (elementResource._resource == Resource::BUFFER) {
#if (GPU_FEATURE_PROFILE == GPU_LEGACY)
// if in legacy profile, we fake the uniform buffer with an array
// this is where we detect it assuming it's explicitely assinged a binding
auto requestedBinding = slotBindings.find(std::string(sname));
if (requestedBinding != slotBindings.end()) {
// found one buffer!
fakeBuffers.insert(Shader::Slot(sname, location, elementResource._element, elementResource._resource));
}
#endif
uniforms.insert(Shader::Slot(sname, location, elementResource._element, elementResource._resource));
} else {
// For texture/Sampler, the location is the actual binding value
@ -623,11 +605,7 @@ int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,
if (requestedBinding != slotBindings.end()) {
if (binding != (*requestedBinding)._location) {
binding = (*requestedBinding)._location;
#if (GPU_FEATURE_PROFILE == GPU_LEGACY)
glUniform1i(location, binding);
#else
glProgramUniform1i(glprogram, location, binding);
#endif
}
}
@ -637,10 +615,6 @@ int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,
}
}
#if (GPU_FEATURE_PROFILE == GPU_LEGACY)
glUseProgram(currentProgram);
#endif
return uniformsCount;
}

View file

@ -1,14 +1,60 @@
//
// Created by Bradley Austin Davis on 2016/04/03
// Created by Bradley Austin Davis on 2016/05/14
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackendShared.h"
using namespace gpu;
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(gpugllogging)
Q_LOGGING_CATEGORY(gpugllogging, "hifi.gpu.gl")
namespace gpu { namespace gl {
bool checkGLError(const char* name) {
GLenum error = glGetError();
if (!error) {
return false;
} else {
switch (error) {
case GL_INVALID_ENUM:
qCDebug(gpugllogging) << "GLBackend::" << name << ": An unacceptable value is specified for an enumerated argument.The offending command is ignored and has no other side effect than to set the error flag.";
break;
case GL_INVALID_VALUE:
qCDebug(gpugllogging) << "GLBackend" << name << ": A numeric argument is out of range.The offending command is ignored and has no other side effect than to set the error flag";
break;
case GL_INVALID_OPERATION:
qCDebug(gpugllogging) << "GLBackend" << name << ": The specified operation is not allowed in the current state.The offending command is ignored and has no other side effect than to set the error flag..";
break;
case GL_INVALID_FRAMEBUFFER_OPERATION:
qCDebug(gpugllogging) << "GLBackend" << name << ": The framebuffer object is not complete.The offending command is ignored and has no other side effect than to set the error flag.";
break;
case GL_OUT_OF_MEMORY:
qCDebug(gpugllogging) << "GLBackend" << name << ": There is not enough memory left to execute the command.The state of the GL is undefined, except for the state of the error flags, after this error is recorded.";
break;
case GL_STACK_UNDERFLOW:
qCDebug(gpugllogging) << "GLBackend" << name << ": An attempt has been made to perform an operation that would cause an internal stack to underflow.";
break;
case GL_STACK_OVERFLOW:
qCDebug(gpugllogging) << "GLBackend" << name << ": An attempt has been made to perform an operation that would cause an internal stack to overflow.";
break;
}
return true;
}
}
bool checkGLErrorDebug(const char* name) {
#ifdef DEBUG
return checkGLError(name);
#else
Q_UNUSED(name);
return false;
#endif
}
GLTexelFormat GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) {
GLTexelFormat texel = { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE };
@ -43,7 +89,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
texel.internalFormat = GL_DEPTH24_STENCIL8;
break;
default:
qCDebug(gpulogging) << "Unknown combination of texel format";
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
break;
}
@ -58,7 +104,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
texel.internalFormat = GL_RG8;
break;
default:
qCDebug(gpulogging) << "Unknown combination of texel format";
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
break;
@ -81,7 +127,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
texel.internalFormat = GL_COMPRESSED_SRGB;
break;
default:
qCDebug(gpulogging) << "Unknown combination of texel format";
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
break;
@ -123,7 +169,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
break;
case gpu::COMPRESSED_SRGBA:
texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA;
break;
// FIXME: WE will want to support this later
@ -144,13 +190,13 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
*/
default:
qCDebug(gpulogging) << "Unknown combination of texel format";
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
break;
}
default:
qCDebug(gpulogging) << "Unknown combination of texel format";
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
return texel;
} else {
@ -286,7 +332,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
texel.internalFormat = GL_DEPTH24_STENCIL8;
break;
default:
qCDebug(gpulogging) << "Unknown combination of texel format";
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
break;
@ -302,7 +348,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
texel.internalFormat = GL_RG8;
break;
default:
qCDebug(gpulogging) << "Unknown combination of texel format";
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
break;
@ -329,7 +375,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
texel.internalFormat = GL_COMPRESSED_SRGB;
break;
default:
qCDebug(gpulogging) << "Unknown combination of texel format";
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
break;
}
@ -411,14 +457,16 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA;
break;
default:
qCDebug(gpulogging) << "Unknown combination of texel format";
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
break;
}
default:
qCDebug(gpulogging) << "Unknown combination of texel format";
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
return texel;
}
}
} }

View file

@ -12,11 +12,10 @@
#define hifi_gpu_GLBackend_Shared_h
#include <gl/Config.h>
#include <gpu/Forward.h>
#include <gpu/Format.h>
#include <QDebug>
#include "GPULogging.h"
#include "GLBackend.h"
namespace gpu { namespace gl {
static const GLenum _primitiveToGLmode[gpu::NUM_PRIMITIVES] = {
GL_POINTS,
@ -59,10 +58,11 @@ public:
static GLTexelFormat evalGLTexelFormat(const gpu::Element& dstFormat, const gpu::Element& srcFormat);
};
// Stupid preprocessor trick to turn the line macro into a string
#define CHECK_GL_ERROR_HELPER(x) #x
// FIXME doesn't build on Linux or Mac. Hmmmm
// #define CHECK_GL_ERROR() gpu::GLBackend::checkGLErrorDebug(__FUNCTION__ ":" CHECK_GL_ERROR_HELPER(__LINE__))
#define CHECK_GL_ERROR() gpu::GLBackend::checkGLErrorDebug(__FUNCTION__)
bool checkGLError(const char* name = nullptr);
bool checkGLErrorDebug(const char* name = nullptr);
} }
#define CHECK_GL_ERROR() gpu::gl::checkGLErrorDebug(__FUNCTION__)
#endif

View file

@ -8,11 +8,11 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackend.h"
#include "GLBackendShared.h"
#include "Format.h"
using namespace gpu;
using namespace gpu::gl;
GLBackend::GLState::GLState()
{}

View file

@ -8,16 +8,19 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GPULogging.h"
#include "GLBackend.h"
#include <unordered_set>
#include <unordered_map>
#include <QtCore/QThread>
#include "GLBackendShared.h"
#include "GLBackendTextureTransfer.h"
using namespace gpu;
using namespace gpu::gl;
GLenum gpuToGLTextureType(const Texture& texture) {
switch (texture.getType()) {
@ -408,7 +411,7 @@ void GLBackend::GLTexture::transfer() const {
break;
default:
qCWarning(gpulogging) << __FUNCTION__ << " case for Texture Type " << _gpuTexture.getType() << " not supported";
qCWarning(gpugllogging) << __FUNCTION__ << " case for Texture Type " << _gpuTexture.getType() << " not supported";
break;
}
}
@ -449,7 +452,7 @@ void GLBackend::GLTexture::postTransfer() {
break;
default:
qCWarning(gpulogging) << __FUNCTION__ << " case for Texture Type " << _gpuTexture.getType() << " not supported";
qCWarning(gpugllogging) << __FUNCTION__ << " case for Texture Type " << _gpuTexture.getType() << " not supported";
break;
}
}

View file

@ -5,17 +5,20 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackendTextureTransfer.h"
#include "GLBackendShared.h"
#ifdef THREADED_TEXTURE_TRANSFER
#include <gl/OffscreenGLCanvas.h>
#include <gl/QOpenGLContextWrapper.h>
#endif
#include "GLBackendShared.h"
using namespace gpu;
using namespace gpu::gl;
#include "GLBackend.h"
GLTextureTransferHelper::GLTextureTransferHelper() {
#ifdef THREADED_TEXTURE_TRANSFER

View file

@ -10,6 +10,7 @@
#include <QSharedPointer>
#include <GenericQueueThread.h>
#include "GLBackendShared.h"
#include "GLBackend.h"
#ifdef Q_OS_WIN
#define THREADED_TEXTURE_TRANSFER
@ -17,7 +18,7 @@
class OffscreenGLCanvas;
namespace gpu {
namespace gpu { namespace gl {
struct TextureTransferPackage {
std::weak_ptr<Texture> texture;
@ -41,4 +42,4 @@ private:
QSharedPointer<OffscreenGLCanvas> _canvas;
};
}
} }

View file

@ -8,11 +8,11 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackend.h"
#include "GLBackendShared.h"
#include "Format.h"
using namespace gpu;
using namespace gpu::gl;
// Transform Stage
void GLBackend::do_setModelTransform(Batch& batch, size_t paramOffset) {

View file

@ -1,7 +1,4 @@
set(TARGET_NAME gpu)
AUTOSCRIBE_SHADER_LIB(gpu)
setup_hifi_library()
link_hifi_libraries(shared gl)
target_glew()
target_opengl()
link_hifi_libraries(shared)

View file

@ -31,6 +31,7 @@ namespace gpu {
using int8 = int8_t;
using Byte = uint8;
using Size = size_t;
using Offset = size_t;
using Offsets = std::vector<Offset>;
@ -80,6 +81,11 @@ namespace gpu {
using Textures = std::vector<TexturePointer>;
class TextureView;
using TextureViews = std::vector<TextureView>;
namespace gl {
class GLBuffer;
class GLBackend;
}
}
#endif

View file

@ -208,7 +208,7 @@ protected:
Sysmem _sysmem;
// FIXME find a more generic way to do this.
friend class GLBackend;
friend class gl::GLBackend;
friend class BufferView;
};

View file

@ -884,3 +884,12 @@ Vec3u Texture::evalMipDimensions(uint16 level) const {
dimensions >>= level;
return glm::max(dimensions, Vec3u(1));
}
std::function<uint32(const gpu::Texture& texture)> TEXTURE_ID_RESOLVER;
uint32 Texture::getHardwareId() const {
if (TEXTURE_ID_RESOLVER) {
return TEXTURE_ID_RESOLVER(*this);
}
return 0;
}

View file

@ -449,6 +449,8 @@ public:
const GPUObjectPointer gpuObject {};
uint32 getHardwareId() const;
protected:
std::unique_ptr< Storage > _storage;

View file

@ -1,4 +1,4 @@
set(TARGET_NAME model-networking)
setup_hifi_library()
link_hifi_libraries(shared networking gpu model fbx)
link_hifi_libraries(shared networking model fbx)

View file

@ -147,8 +147,14 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
if (!handleUsername(lookupUrl.authority())) {
// we're assuming this is either a network address or global place name
// check if it is a network address first
bool hostChanged;
if (handleNetworkAddress(lookupUrl.host()
+ (lookupUrl.port() == -1 ? "" : ":" + QString::number(lookupUrl.port())), trigger)) {
+ (lookupUrl.port() == -1 ? "" : ":" + QString::number(lookupUrl.port())), trigger, hostChanged)) {
// If the host changed then we have already saved to history
if (hostChanged) {
trigger = Internal;
}
// if we were not passed a path, use the index path
auto path = lookupUrl.path();
@ -170,13 +176,13 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
}
return true;
} else if (lookupUrl.toString().startsWith('/')) {
qCDebug(networking) << "Going to relative path" << lookupUrl.path();
// if this is a relative path then handle it as a relative viewpoint
handlePath(lookupUrl.path(), trigger, true);
emit lookupResultsFinished();
return true;
}
@ -290,9 +296,13 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const
const QString PLACE_NAME_KEY = "name";
QString placeName = rootMap[PLACE_NAME_KEY].toString();
if (!placeName.isEmpty()) {
setHost(placeName, trigger);
if (setHost(placeName, trigger)) {
trigger = LookupTrigger::Internal;
}
} else {
setHost(domainIDString, trigger);
if (setHost(domainIDString, trigger)) {
trigger = LookupTrigger::Internal;
}
}
// check if we had a path to override the path returned
@ -310,7 +320,7 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const
if (!returnedPath.isEmpty()) {
if (shouldFaceViewpoint) {
// try to parse this returned path as a viewpoint, that's the only thing it could be for now
if (!handleViewpoint(returnedPath, shouldFaceViewpoint)) {
if (!handleViewpoint(returnedPath, shouldFaceViewpoint, trigger)) {
qCDebug(networking) << "Received a location path that was could not be handled as a viewpoint -"
<< returnedPath;
}
@ -394,7 +404,7 @@ void AddressManager::attemptDomainIDLookup(const QString& lookupString, const QS
QByteArray(), NULL, requestParams);
}
bool AddressManager::handleNetworkAddress(const QString& lookupString, LookupTrigger trigger) {
bool AddressManager::handleNetworkAddress(const QString& lookupString, LookupTrigger trigger, bool& hostChanged) {
const QString IP_ADDRESS_REGEX_STRING = "^((?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}"
"(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))(?::(\\d{1,5}))?$";
@ -412,7 +422,7 @@ bool AddressManager::handleNetworkAddress(const QString& lookupString, LookupTri
}
emit lookupResultsFinished();
setDomainInfo(domainIPString, domainPort, trigger);
hostChanged = setDomainInfo(domainIPString, domainPort, trigger);
return true;
}
@ -429,11 +439,13 @@ bool AddressManager::handleNetworkAddress(const QString& lookupString, LookupTri
}
emit lookupResultsFinished();
setDomainInfo(domainHostname, domainPort, trigger);
hostChanged = setDomainInfo(domainHostname, domainPort, trigger);
return true;
}
hostChanged = false;
return false;
}
@ -446,7 +458,7 @@ bool AddressManager::handleDomainID(const QString& host) {
}
void AddressManager::handlePath(const QString& path, LookupTrigger trigger, bool wasPathOnly) {
if (!handleViewpoint(path, false, wasPathOnly)) {
if (!handleViewpoint(path, false, trigger, wasPathOnly)) {
qCDebug(networking) << "User entered path could not be handled as a viewpoint - " << path <<
"- wll attempt to ask domain-server to resolve.";
@ -463,7 +475,7 @@ void AddressManager::handlePath(const QString& path, LookupTrigger trigger, bool
}
}
bool AddressManager::handleViewpoint(const QString& viewpointString, bool shouldFace,
bool AddressManager::handleViewpoint(const QString& viewpointString, bool shouldFace, LookupTrigger trigger,
bool definitelyPathOnly, const QString& pathString) {
const QString FLOAT_REGEX_STRING = "([-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?)";
const QString SPACED_COMMA_REGEX_STRING = "\\s*,\\s*";
@ -491,8 +503,9 @@ bool AddressManager::handleViewpoint(const QString& viewpointString, bool should
// before moving to a new host thanks to the information in the same lookup URL.
if (definitelyPathOnly || (!pathString.isEmpty() && pathString != _newHostLookupPath)) {
addCurrentAddressToHistory(LookupTrigger::UserInput);
if (definitelyPathOnly || (!pathString.isEmpty() && pathString != _newHostLookupPath)
|| trigger == Back || trigger == Forward) {
addCurrentAddressToHistory(trigger);
}
if (!isNaN(newPosition.x) && !isNaN(newPosition.y) && !isNaN(newPosition.z)) {
@ -500,6 +513,8 @@ bool AddressManager::handleViewpoint(const QString& viewpointString, bool should
QRegExp orientationRegex(QUAT_REGEX_STRING);
bool orientationChanged = false;
// we may also have an orientation
if (viewpointString[positionRegex.matchedLength() - 1] == QChar('/')
&& orientationRegex.indexIn(viewpointString, positionRegex.matchedLength() - 1) != -1) {
@ -511,14 +526,13 @@ bool AddressManager::handleViewpoint(const QString& viewpointString, bool should
if (!isNaN(newOrientation.x) && !isNaN(newOrientation.y) && !isNaN(newOrientation.z)
&& !isNaN(newOrientation.w)) {
emit locationChangeRequired(newPosition, true, newOrientation, shouldFace);
return true;
orientationChanged = true;
} else {
qCDebug(networking) << "Orientation parsed from lookup string is invalid. Will not use for location change.";
}
}
emit locationChangeRequired(newPosition, false, newOrientation, shouldFace);
emit locationChangeRequired(newPosition, orientationChanged, newOrientation, shouldFace);
} else {
qCDebug(networking) << "Could not jump to position from lookup string because it has an invalid value.";
@ -545,24 +559,27 @@ bool AddressManager::handleUsername(const QString& lookupString) {
return false;
}
void AddressManager::setHost(const QString& host, LookupTrigger trigger, quint16 port) {
bool AddressManager::setHost(const QString& host, LookupTrigger trigger, quint16 port) {
if (host != _host || port != _port) {
_port = port;
// if the host is being changed we should store current address in the history
addCurrentAddressToHistory(trigger);
_port = port;
if (host != _host) {
_host = host;
emit hostChanged(_host);
}
return true;
}
return false;
}
void AddressManager::setDomainInfo(const QString& hostname, quint16 port, LookupTrigger trigger) {
setHost(hostname, trigger, port);
bool AddressManager::setDomainInfo(const QString& hostname, quint16 port, LookupTrigger trigger) {
bool hostChanged = setHost(hostname, trigger, port);
_rootPlaceID = QUuid();
@ -571,6 +588,8 @@ void AddressManager::setDomainInfo(const QString& hostname, quint16 port, Lookup
DependencyManager::get<NodeList>()->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::HandleAddress);
emit possibleDomainChangeRequired(hostname, port);
return hostChanged;
}
void AddressManager::goToUser(const QString& username) {
@ -599,14 +618,7 @@ void AddressManager::copyPath() {
void AddressManager::addCurrentAddressToHistory(LookupTrigger trigger) {
// if we're cold starting and this is called for the first address (from settings) we don't do anything
if (trigger != LookupTrigger::StartupFromSettings) {
if (trigger == LookupTrigger::UserInput) {
// anyime the user has manually looked up an address we know we should clear the forward stack
_forwardStack.clear();
emit goForwardPossible(false);
}
if (trigger != LookupTrigger::StartupFromSettings && trigger != LookupTrigger::DomainPathResponse) {
if (trigger == LookupTrigger::Back) {
// we're about to push to the forward stack
// if it's currently empty emit our signal to say that going forward is now possible
@ -618,9 +630,16 @@ void AddressManager::addCurrentAddressToHistory(LookupTrigger trigger) {
// and do not but it into the back stack
_forwardStack.push(currentAddress());
} else {
if (trigger == LookupTrigger::UserInput) {
// anyime the user has manually looked up an address we know we should clear the forward stack
_forwardStack.clear();
emit goForwardPossible(false);
}
// we're about to push to the back stack
// if it's currently empty emit our signal to say that going forward is now possible
if (_forwardStack.size() == 0) {
// if it's currently empty emit our signal to say that going backward is now possible
if (_backStack.size() == 0) {
emit goBackPossible(true);
}

View file

@ -46,7 +46,9 @@ public:
UserInput,
Back,
Forward,
StartupFromSettings
StartupFromSettings,
DomainPathResponse,
Internal
};
bool isConnected();
@ -77,7 +79,7 @@ public slots:
// we currently expect this to be called from NodeList once handleLookupString has been called with a path
bool goToViewpointForPath(const QString& viewpointString, const QString& pathString)
{ return handleViewpoint(viewpointString, false, false, pathString); }
{ return handleViewpoint(viewpointString, false, DomainPathResponse, false, pathString); }
void goBack();
void goForward();
@ -114,18 +116,20 @@ private slots:
void handleAPIResponse(QNetworkReply& requestReply);
void handleAPIError(QNetworkReply& errorReply);
void goToAddressFromObject(const QVariantMap& addressMap, const QNetworkReply& reply);
private:
void setHost(const QString& host, LookupTrigger trigger, quint16 port = 0);
void setDomainInfo(const QString& hostname, quint16 port, LookupTrigger trigger);
void goToAddressFromObject(const QVariantMap& addressMap, const QNetworkReply& reply);
// Set host and port, and return `true` if it was changed.
bool setHost(const QString& host, LookupTrigger trigger, quint16 port = 0);
bool setDomainInfo(const QString& hostname, quint16 port, LookupTrigger trigger);
const JSONCallbackParameters& apiCallbackParameters();
bool handleUrl(const QUrl& lookupUrl, LookupTrigger trigger = UserInput);
bool handleNetworkAddress(const QString& lookupString, LookupTrigger trigger);
bool handleNetworkAddress(const QString& lookupString, LookupTrigger trigger, bool& hostChanged);
void handlePath(const QString& path, LookupTrigger trigger, bool wasPathOnly = false);
bool handleViewpoint(const QString& viewpointString, bool shouldFace = false,
bool handleViewpoint(const QString& viewpointString, bool shouldFace, LookupTrigger trigger,
bool definitelyPathOnly = false, const QString& pathString = QString());
bool handleUsername(const QString& lookupString);
bool handleDomainID(const QString& host);

View file

@ -202,7 +202,7 @@ AssetUpload* AssetClient::createUpload(const QByteArray& data) {
}
MessageID AssetClient::getAsset(const QString& hash, DataOffset start, DataOffset end,
ReceivedAssetCallback callback, ProgressCallback progressCallback) {
ReceivedAssetCallback callback, ProgressCallback progressCallback) {
Q_ASSERT(QThread::currentThread() == thread());
if (hash.length() != SHA256_HASH_HEX_LENGTH) {
@ -238,8 +238,6 @@ MessageID AssetClient::getAsset(const QString& hash, DataOffset start, DataOffse
callback(false, AssetServerError::NoError, QByteArray());
return INVALID_MESSAGE_ID;
}
}
MessageID AssetClient::getAssetInfo(const QString& hash, GetInfoCallback callback) {

View file

@ -106,9 +106,13 @@ void AssetRequest::start() {
int start = 0, end = _info.size;
auto assetClient = DependencyManager::get<AssetClient>();
auto that = QPointer<AssetRequest>(this); // Used to track the request's lifetime
_assetRequestID = assetClient->getAsset(_hash, start, end,
[this, start, end](bool responseReceived, AssetServerError serverError, const QByteArray& data) {
[this, that, start, end](bool responseReceived, AssetServerError serverError, const QByteArray& data) {
if (!that) {
// If the request is dead, return
return;
}
_assetRequestID = AssetClient::INVALID_MESSAGE_ID;
if (!responseReceived) {
@ -148,7 +152,11 @@ void AssetRequest::start() {
_state = Finished;
emit finished(this);
}, [this](qint64 totalReceived, qint64 total) {
}, [this, that](qint64 totalReceived, qint64 total) {
if (!that) {
// If the request is dead, return
return;
}
emit progress(totalReceived, total);
});
});

View file

@ -46,6 +46,20 @@ protected:
btRigidBody* _me;
};
CharacterController::CharacterMotor::CharacterMotor(const glm::vec3& vel, const glm::quat& rot, float horizTimescale, float vertTimescale) {
velocity = glmToBullet(vel);
rotation = glmToBullet(rot);
hTimescale = horizTimescale;
if (hTimescale < MIN_CHARACTER_MOTOR_TIMESCALE) {
hTimescale = MIN_CHARACTER_MOTOR_TIMESCALE;
}
vTimescale = vertTimescale;
if (vTimescale < 0.0f) {
vTimescale = hTimescale;
} else if (vTimescale < MIN_CHARACTER_MOTOR_TIMESCALE) {
vTimescale = MIN_CHARACTER_MOTOR_TIMESCALE;
}
}
CharacterController::CharacterController() {
_halfHeight = 1.0f;
@ -173,60 +187,16 @@ void CharacterController::preStep(btCollisionWorld* collisionWorld) {
_hasSupport = checkForSupport(collisionWorld);
}
const btScalar MIN_TARGET_SPEED = 0.001f;
const btScalar MIN_TARGET_SPEED_SQUARED = MIN_TARGET_SPEED * MIN_TARGET_SPEED;
void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) {
const btScalar MIN_SPEED = 0.001f;
btVector3 actualVelocity = _rigidBody->getLinearVelocity() - _parentVelocity;
if (actualVelocity.length() < MIN_SPEED) {
actualVelocity = btVector3(0.0f, 0.0f, 0.0f);
}
btVector3 desiredVelocity = _targetVelocity;
if (desiredVelocity.length() < MIN_SPEED) {
desiredVelocity = btVector3(0.0f, 0.0f, 0.0f);
}
// decompose into horizontal and vertical components.
btVector3 actualVertVelocity = actualVelocity.dot(_currentUp) * _currentUp;
btVector3 actualHorizVelocity = actualVelocity - actualVertVelocity;
btVector3 desiredVertVelocity = desiredVelocity.dot(_currentUp) * _currentUp;
btVector3 desiredHorizVelocity = desiredVelocity - desiredVertVelocity;
btVector3 finalVelocity;
switch (_state) {
case State::Ground:
case State::Takeoff:
{
// horizontal ground control
const btScalar WALK_ACCELERATION_TIMESCALE = 0.1f;
btScalar tau = dt / WALK_ACCELERATION_TIMESCALE;
finalVelocity = tau * desiredHorizVelocity + (1.0f - tau) * actualHorizVelocity + actualVertVelocity;
}
break;
case State::InAir:
{
// horizontal air control
const btScalar IN_AIR_ACCELERATION_TIMESCALE = 2.0f;
btScalar tau = dt / IN_AIR_ACCELERATION_TIMESCALE;
finalVelocity = tau * desiredHorizVelocity + (1.0f - tau) * actualHorizVelocity + actualVertVelocity;
}
break;
case State::Hover:
{
// vertical and horizontal air control
const btScalar FLY_ACCELERATION_TIMESCALE = 0.2f;
btScalar tau = dt / FLY_ACCELERATION_TIMESCALE;
finalVelocity = tau * desiredVelocity + (1.0f - tau) * actualVelocity;
}
break;
}
_rigidBody->setLinearVelocity(finalVelocity + _parentVelocity);
btVector3 velocity = _rigidBody->getLinearVelocity() - _parentVelocity;
computeNewVelocity(dt, velocity);
_rigidBody->setLinearVelocity(velocity + _parentVelocity);
// Dynamicaly compute a follow velocity to move this body toward the _followDesiredBodyTransform.
// Rather then add this velocity to velocity the RigidBody, we explicitly teleport the RigidBody towards its goal.
// Rather than add this velocity to velocity the RigidBody, we explicitly teleport the RigidBody towards its goal.
// This mirrors the computation done in MyAvatar::FollowHelper::postPhysicsUpdate().
const float MINIMUM_TIME_REMAINING = 0.005f;
@ -397,10 +367,6 @@ void CharacterController::getPositionAndOrientation(glm::vec3& position, glm::qu
}
}
void CharacterController::setTargetVelocity(const glm::vec3& velocity) {
_targetVelocity = glmToBullet(velocity);
}
void CharacterController::setParentVelocity(const glm::vec3& velocity) {
_parentVelocity = glmToBullet(velocity);
}
@ -442,6 +408,122 @@ glm::vec3 CharacterController::getVelocityChange() const {
return velocity;
}
void CharacterController::clearMotors() {
_motors.clear();
}
void CharacterController::addMotor(const glm::vec3& velocity, const glm::quat& rotation, float horizTimescale, float vertTimescale) {
_motors.push_back(CharacterController::CharacterMotor(velocity, rotation, horizTimescale, vertTimescale));
}
void CharacterController::applyMotor(int index, btScalar dt, btVector3& worldVelocity, std::vector<btVector3>& velocities, std::vector<btScalar>& weights) {
assert(index < (int)(_motors.size()));
CharacterController::CharacterMotor& motor = _motors[index];
if (motor.hTimescale >= MAX_CHARACTER_MOTOR_TIMESCALE && motor.vTimescale >= MAX_CHARACTER_MOTOR_TIMESCALE) {
// nothing to do
return;
}
// rotate into motor-frame
btVector3 axis = motor.rotation.getAxis();
btScalar angle = motor.rotation.getAngle();
btVector3 velocity = worldVelocity.rotate(axis, -angle);
if (_state == State::Hover || motor.hTimescale == motor.vTimescale) {
// modify velocity
btScalar tau = dt / motor.hTimescale;
if (tau > 1.0f) {
tau = 1.0f;
}
velocity += (motor.velocity - velocity) * tau;
// rotate back into world-frame
velocity = velocity.rotate(axis, angle);
// store the velocity and weight
velocities.push_back(velocity);
weights.push_back(tau);
} else {
// compute local UP
btVector3 up = _currentUp.rotate(axis, -angle);
// split velocity into horizontal and vertical components
btVector3 vVelocity = velocity.dot(up) * up;
btVector3 hVelocity = velocity - vVelocity;
btVector3 vTargetVelocity = motor.velocity.dot(up) * up;
btVector3 hTargetVelocity = motor.velocity - vTargetVelocity;
// modify each component separately
btScalar maxTau = 0.0f;
if (motor.hTimescale < MAX_CHARACTER_MOTOR_TIMESCALE) {
btScalar tau = dt / motor.hTimescale;
if (tau > 1.0f) {
tau = 1.0f;
}
maxTau = tau;
hVelocity += (hTargetVelocity - hVelocity) * tau;
}
if (motor.vTimescale < MAX_CHARACTER_MOTOR_TIMESCALE) {
btScalar tau = dt / motor.vTimescale;
if (tau > 1.0f) {
tau = 1.0f;
}
if (tau > maxTau) {
maxTau = tau;
}
vVelocity += (vTargetVelocity - vVelocity) * tau;
}
// add components back together and rotate into world-frame
velocity = (hVelocity + vVelocity).rotate(axis, angle);
// store velocity and weights
velocities.push_back(velocity);
weights.push_back(maxTau);
}
}
void CharacterController::computeNewVelocity(btScalar dt, btVector3& velocity) {
if (velocity.length2() < MIN_TARGET_SPEED_SQUARED) {
velocity = btVector3(0.0f, 0.0f, 0.0f);
}
// measure velocity changes and their weights
std::vector<btVector3> velocities;
velocities.reserve(_motors.size());
std::vector<btScalar> weights;
weights.reserve(_motors.size());
for (int i = 0; i < (int)_motors.size(); ++i) {
applyMotor(i, dt, velocity, velocities, weights);
}
assert(velocities.size() == weights.size());
// blend velocity changes according to relative weights
btScalar totalWeight = 0.0f;
for (size_t i = 0; i < weights.size(); ++i) {
totalWeight += weights[i];
}
if (totalWeight > 0.0f) {
velocity = btVector3(0.0f, 0.0f, 0.0f);
for (size_t i = 0; i < velocities.size(); ++i) {
velocity += (weights[i] / totalWeight) * velocities[i];
}
}
if (velocity.length2() < MIN_TARGET_SPEED_SQUARED) {
velocity = btVector3(0.0f, 0.0f, 0.0f);
}
// 'thrust' is applied at the very end
velocity += dt * _linearAcceleration;
_targetVelocity = velocity;
}
void CharacterController::computeNewVelocity(btScalar dt, glm::vec3& velocity) {
btVector3 btVelocity = glmToBullet(velocity);
computeNewVelocity(dt, btVelocity);
velocity = bulletToGLM(btVelocity);
}
void CharacterController::preSimulation() {
if (_enabled && _dynamicsWorld) {
quint64 now = usecTimestampNow();
@ -451,9 +533,6 @@ void CharacterController::preSimulation() {
btVector3 velocity = _rigidBody->getLinearVelocity();
_preSimulationVelocity = velocity;
btVector3 actualVertVelocity = velocity.dot(_currentUp) * _currentUp;
btVector3 actualHorizVelocity = velocity - actualVertVelocity;
// scan for distant floor
// rayStart is at center of bottom sphere
btVector3 rayStart = _characterBodyTransform.getOrigin() - _halfHeight * _currentUp;
@ -491,6 +570,8 @@ void CharacterController::preSimulation() {
}
bool jumpButtonHeld = _pendingFlags & PENDING_FLAG_JUMP;
btVector3 actualHorizVelocity = velocity - velocity.dot(_currentUp) * _currentUp;
bool flyingFast = _state == State::Hover && actualHorizVelocity.length() > (MAX_WALKING_SPEED * 0.75f);
switch (_state) {
@ -517,10 +598,17 @@ void CharacterController::preSimulation() {
case State::InAir: {
if ((velocity.dot(_currentUp) <= (JUMP_SPEED / 2.0f)) && ((_floorDistance < JUMP_PROXIMITY_THRESHOLD) || _hasSupport)) {
SET_STATE(State::Ground, "hit ground");
} else if (jumpButtonHeld && (_takeoffJumpButtonID != _jumpButtonDownCount)) {
SET_STATE(State::Hover, "double jump button");
} else if (jumpButtonHeld && (now - _jumpButtonDownStartTime) > JUMP_TO_HOVER_PERIOD) {
SET_STATE(State::Hover, "jump button held");
} else {
btVector3 desiredVelocity = _targetVelocity;
if (desiredVelocity.length2() < MIN_TARGET_SPEED_SQUARED) {
desiredVelocity = btVector3(0.0f, 0.0f, 0.0f);
}
bool vertTargetSpeedIsNonZero = desiredVelocity.dot(_currentUp) > MIN_TARGET_SPEED;
if ((jumpButtonHeld || vertTargetSpeedIsNonZero) && (_takeoffJumpButtonID != _jumpButtonDownCount)) {
SET_STATE(State::Hover, "double jump button");
} else if ((jumpButtonHeld || vertTargetSpeedIsNonZero) && (now - _jumpButtonDownStartTime) > JUMP_TO_HOVER_PERIOD) {
SET_STATE(State::Hover, "jump button held");
}
}
break;
}

View file

@ -33,6 +33,9 @@ class btDynamicsWorld;
//#define DEBUG_STATE_CHANGE
const btScalar MAX_CHARACTER_MOTOR_TIMESCALE = 60.0f; // one minute
const btScalar MIN_CHARACTER_MOTOR_TIMESCALE = 0.05f;
class CharacterController : public btCharacterControllerInterface {
public:
CharacterController();
@ -62,13 +65,21 @@ public:
virtual void jump() override;
virtual bool onGround() const override;
void clearMotors();
void addMotor(const glm::vec3& velocity, const glm::quat& rotation, float horizTimescale, float vertTimescale = -1.0f);
void applyMotor(int index, btScalar dt, btVector3& worldVelocity, std::vector<btVector3>& velocities, std::vector<btScalar>& weights);
void computeNewVelocity(btScalar dt, btVector3& velocity);
void computeNewVelocity(btScalar dt, glm::vec3& velocity);
// HACK for legacy 'thrust' feature
void setLinearAcceleration(const glm::vec3& acceleration) { _linearAcceleration = glmToBullet(acceleration); }
void preSimulation();
void postSimulation();
void setPositionAndOrientation( const glm::vec3& position, const glm::quat& orientation);
void getPositionAndOrientation(glm::vec3& position, glm::quat& rotation) const;
void setTargetVelocity(const glm::vec3& velocity);
void setParentVelocity(const glm::vec3& parentVelocity);
void setFollowParameters(const glm::mat4& desiredWorldMatrix, float timeRemaining);
float getFollowTime() const { return _followTime; }
@ -113,6 +124,16 @@ protected:
bool checkForSupport(btCollisionWorld* collisionWorld) const;
protected:
struct CharacterMotor {
CharacterMotor(const glm::vec3& vel, const glm::quat& rot, float horizTimescale, float vertTimescale = -1.0f);
btVector3 velocity { btVector3(0.0f, 0.0f, 0.0f) }; // local-frame
btQuaternion rotation; // local-to-world
btScalar hTimescale { MAX_CHARACTER_MOTOR_TIMESCALE }; // horizontal
btScalar vTimescale { MAX_CHARACTER_MOTOR_TIMESCALE }; // vertical
};
std::vector<CharacterMotor> _motors;
btVector3 _currentUp;
btVector3 _targetVelocity;
btVector3 _parentVelocity;
@ -144,6 +165,7 @@ protected:
btScalar _followTime;
btVector3 _followLinearDisplacement;
btQuaternion _followAngularDisplacement;
btVector3 _linearAcceleration;
bool _enabled;
State _state;

View file

@ -1,5 +1,6 @@
#include "DisplayPlugin.h"
#include <NumericalConstants.h>
#include <ui/Menu.h>
#include "PluginContainer.h"
@ -23,4 +24,22 @@ void DisplayPlugin::deactivate() {
Parent::deactivate();
}
int64_t DisplayPlugin::getPaintDelayUsecs() const {
std::lock_guard<std::mutex> lock(_paintDelayMutex);
return _paintDelayTimer.isValid() ? _paintDelayTimer.nsecsElapsed() / NSECS_PER_USEC : 0;
}
void DisplayPlugin::incrementPresentCount() {
#ifdef DEBUG_PAINT_DELAY
// Avoid overhead if we are not debugging
{
std::lock_guard<std::mutex> lock(_paintDelayMutex);
_paintDelayTimer.start();
}
#endif
++_presentedFrameIndex;
// Alert the app that it needs to paint a new presentation frame
qApp->postEvent(qApp, new QEvent(static_cast<QEvent::Type>(Present)), Qt::HighEventPriority);
}

View file

@ -15,6 +15,7 @@
#include <QtCore/QSize>
#include <QtCore/QPoint>
#include <QtCore/QElapsedTimer>
class QImage;
#include <GLMHelpers.h>
@ -59,6 +60,10 @@ class DisplayPlugin : public Plugin {
Q_OBJECT
using Parent = Plugin;
public:
enum Event {
Present = QEvent::User + 1
};
bool activate() override;
void deactivate() override;
virtual bool isHmd() const { return false; }
@ -156,6 +161,8 @@ public:
// Rate at which rendered frames are being skipped
virtual float droppedFrameRate() const { return -1.0f; }
uint32_t presentCount() const { return _presentedFrameIndex; }
// Time since last call to incrementPresentCount (only valid if DEBUG_PAINT_DELAY is defined)
int64_t getPaintDelayUsecs() const;
virtual void cycleDebugOutput() {}
@ -165,9 +172,11 @@ signals:
void recommendedFramebufferSizeChanged(const QSize & size);
protected:
void incrementPresentCount() { ++_presentedFrameIndex; }
void incrementPresentCount();
private:
std::atomic<uint32_t> _presentedFrameIndex;
mutable std::mutex _paintDelayMutex;
QElapsedTimer _paintDelayTimer;
};

View file

@ -1,5 +1,5 @@
set(TARGET_NAME procedural)
AUTOSCRIBE_SHADER_LIB(gpu model)
setup_hifi_library()
link_hifi_libraries(shared gpu networking model model-networking)
link_hifi_libraries(shared gpu gpu-gl networking model model-networking)

View file

@ -101,7 +101,7 @@ DeferredFragment unpackDeferredFragmentNoPosition(vec2 texcoord) {
// Unpack the normal from the map
frag.normal = normalize(frag.normalVal.xyz * 2.0 - vec3(1.0));
frag.roughness = 2.0 * frag.normalVal.a;
frag.roughness = frag.normalVal.a;
// Diffuse color and unpack the mode and the metallicness
frag.diffuse = frag.diffuseVal.xyz;

View file

@ -157,6 +157,11 @@ void Scene::updateItems(const ItemIDs& ids, UpdateFunctors& functors) {
auto updateFunctor = functors.begin();
for (auto updateID : ids) {
if (updateID == Item::INVALID_ITEM_ID) {
updateFunctor++;
continue;
}
// Access the true item
auto& item = _items[updateID];
auto oldCell = item.getCell();

View file

@ -136,10 +136,9 @@ static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName
return false;
}
ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, bool wantSignals) :
ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString) :
_scriptContents(scriptContents),
_timerFunctionMap(),
_wantSignals(wantSignals),
_fileNameString(fileNameString),
_arrayBufferClass(new ArrayBufferClass(this))
{
@ -153,7 +152,7 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam
}
ScriptEngine::~ScriptEngine() {
qCDebug(scriptengine) << "Script Engine shutting down (destructor) for script:" << getFilename();
qCDebug(scriptengine) << "Script Engine shutting down:" << getFilename();
auto scriptEngines = DependencyManager::get<ScriptEngines>();
if (scriptEngines) {
@ -161,16 +160,15 @@ ScriptEngine::~ScriptEngine() {
} else {
qCWarning(scriptengine) << "Script destroyed after ScriptEngines!";
}
waitTillDoneRunning();
}
void ScriptEngine::disconnectNonEssentialSignals() {
disconnect();
QThread* receiver;
QThread* workerThread;
// Ensure the thread should be running, and does exist
if (_isRunning && _isThreaded && (receiver = thread())) {
connect(this, &ScriptEngine::doneRunning, receiver, &QThread::quit);
if (_isRunning && _isThreaded && (workerThread = thread())) {
connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit);
connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater);
}
}
@ -229,15 +227,14 @@ void ScriptEngine::runDebuggable() {
return;
}
stopAllTimers(); // make sure all our timers are stopped if the script is ending
if (_wantSignals) {
emit scriptEnding();
emit finished(_fileNameString, this);
}
emit scriptEnding();
emit finished(_fileNameString, this);
_isRunning = false;
if (_wantSignals) {
emit runningStateChanged();
emit doneRunning();
}
emit runningStateChanged();
emit doneRunning();
timer->deleteLater();
return;
}
@ -247,9 +244,7 @@ void ScriptEngine::runDebuggable() {
if (_lastUpdate < now) {
float deltaTime = (float)(now - _lastUpdate) / (float)USECS_PER_SECOND;
if (!_isFinished) {
if (_wantSignals) {
emit update(deltaTime);
}
emit update(deltaTime);
}
}
_lastUpdate = now;
@ -270,57 +265,72 @@ void ScriptEngine::runInThread() {
}
_isThreaded = true;
QThread* workerThread = new QThread();
QString scriptEngineName = QString("Script Thread:") + getFilename();
workerThread->setObjectName(scriptEngineName);
// The thread interface cannot live on itself, and we want to move this into the thread, so
// the thread cannot have this as a parent.
QThread* workerThread = new QThread();
workerThread->setObjectName(QString("Script Thread:") + getFilename());
moveToThread(workerThread);
// NOTE: If you connect any essential signals for proper shutdown or cleanup of
// the script engine, make sure to add code to "reconnect" them to the
// disconnectNonEssentialSignals() method
// when the worker thread is started, call our engine's run..
connect(workerThread, &QThread::started, this, &ScriptEngine::run);
// tell the thread to stop when the script engine is done
connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit);
connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater);
moveToThread(workerThread);
// Starts an event loop, and emits workerThread->started()
workerThread->start();
}
void ScriptEngine::waitTillDoneRunning() {
// If the script never started running or finished running before we got here, we don't need to wait for it
auto workerThread = thread();
if (_isThreaded && workerThread) {
QString scriptName = getFilename();
auto startedWaiting = usecTimestampNow();
if (_isThreaded && workerThread) {
// We should never be waiting (blocking) on our own thread
assert(workerThread != QThread::currentThread());
// Engine should be stopped already, but be defensive
stop();
auto startedWaiting = usecTimestampNow();
while (workerThread->isRunning()) {
// NOTE: This will be called on the main application thread from stopAllScripts.
// The application thread will need to continue to process events, because
// the scripts will likely need to marshall messages across to the main thread, e.g.
// if they access Settings or Menu in any of their shutdown code. So:
// Process events for the main application thread, allowing invokeMethod calls to pass between threads.
QCoreApplication::processEvents(); // thread-safe :)
QCoreApplication::processEvents();
// If we've been waiting a second or more, then tell the script engine to stop evaluating
static const auto MAX_SCRIPT_EVALUATION_TIME = USECS_PER_SECOND;
// If the final evaluation takes too long, then tell the script engine to stop running
auto elapsedUsecs = usecTimestampNow() - startedWaiting;
static const auto MAX_SCRIPT_EVALUATION_TIME = USECS_PER_SECOND;
if (elapsedUsecs > MAX_SCRIPT_EVALUATION_TIME) {
qCDebug(scriptengine) <<
"Script " << scriptName << " has been running too long [" << elapsedUsecs << " usecs] quitting.";
abortEvaluation(); // to allow the thread to quit
workerThread->quit();
break;
if (isEvaluating()) {
qCWarning(scriptengine) << "Script Engine has been running too long, aborting:" << getFilename();
abortEvaluation();
} else {
qCWarning(scriptengine) << "Script Engine has been running too long, throwing:" << getFilename();
auto context = currentContext();
if (context) {
context->throwError("Timed out during shutdown");
}
}
// Wait for the scripting thread to stop running, as
// flooding it with aborts/exceptions will persist it longer
static const auto MAX_SCRIPT_QUITTING_TIME = 0.5 * MSECS_PER_SECOND;
if (workerThread->wait(MAX_SCRIPT_QUITTING_TIME)) {
workerThread->terminate();
}
}
// Avoid a pure busy wait
QThread::yieldCurrentThread();
}
workerThread->deleteLater();
qCDebug(scriptengine) << "Script Engine has stopped:" << getFilename();
}
}
@ -356,17 +366,13 @@ void ScriptEngine::scriptContentsAvailable(const QUrl& url, const QString& scrip
if (QRegularExpression(DEBUG_FLAG).match(scriptContents).hasMatch()) {
_debuggable = true;
}
if (_wantSignals) {
emit scriptLoaded(url.toString());
}
emit scriptLoaded(url.toString());
}
// FIXME - switch this to the new model of ScriptCache callbacks
void ScriptEngine::errorInLoadingScript(const QUrl& url) {
qCDebug(scriptengine) << "ERROR Loading file:" << url.toString() << "line:" << __LINE__;
if (_wantSignals) {
emit errorLoadingScript(_fileNameString); // ??
}
emit errorLoadingScript(_fileNameString); // ??
}
// Even though we never pass AnimVariantMap directly to and from javascript, the queued invokeMethod of
@ -783,9 +789,7 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi
--_evaluatesPending;
const auto hadUncaughtException = hadUncaughtExceptions(*this, program.fileName());
if (_wantSignals) {
emit evaluationFinished(result, hadUncaughtException);
}
emit evaluationFinished(result, hadUncaughtException);
return result;
}
@ -799,9 +803,7 @@ void ScriptEngine::run() {
}
_isRunning = true;
if (_wantSignals) {
emit runningStateChanged();
}
emit runningStateChanged();
QScriptValue result = evaluate(_scriptContents, _fileNameString);
@ -870,9 +872,7 @@ void ScriptEngine::run() {
if (_lastUpdate < now) {
float deltaTime = (float) (now - _lastUpdate) / (float) USECS_PER_SECOND;
if (!_isFinished) {
if (_wantSignals) {
emit update(deltaTime);
}
emit update(deltaTime);
}
}
_lastUpdate = now;
@ -881,10 +881,10 @@ void ScriptEngine::run() {
hadUncaughtExceptions(*this, _fileNameString);
}
qCDebug(scriptengine) << "Script Engine stopping:" << getFilename();
stopAllTimers(); // make sure all our timers are stopped if the script is ending
if (_wantSignals) {
emit scriptEnding();
}
emit scriptEnding();
if (entityScriptingInterface->getEntityPacketSender()->serversExist()) {
// release the queue of edit entity messages.
@ -902,15 +902,11 @@ void ScriptEngine::run() {
}
}
if (_wantSignals) {
emit finished(_fileNameString, this);
}
emit finished(_fileNameString, this);
_isRunning = false;
if (_wantSignals) {
emit runningStateChanged();
emit doneRunning();
}
emit runningStateChanged();
emit doneRunning();
}
// NOTE: This is private because it must be called on the same thread that created the timers, which is why
@ -943,14 +939,8 @@ void ScriptEngine::stopAllTimersForEntityScript(const EntityItemID& entityID) {
void ScriptEngine::stop() {
if (!_isFinished) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "stop");
return;
}
_isFinished = true;
if (_wantSignals) {
emit runningStateChanged();
}
emit runningStateChanged();
}
}
@ -1074,9 +1064,7 @@ QUrl ScriptEngine::resolvePath(const QString& include) const {
}
void ScriptEngine::print(const QString& message) {
if (_wantSignals) {
emit printedMessage(message);
}
emit printedMessage(message);
}
// If a callback is specified, the included files will be loaded asynchronously and the callback will be called
@ -1212,13 +1200,9 @@ void ScriptEngine::load(const QString& loadFile) {
if (_isReloading) {
auto scriptCache = DependencyManager::get<ScriptCache>();
scriptCache->deleteScript(url.toString());
if (_wantSignals) {
emit reloadScript(url.toString(), false);
}
emit reloadScript(url.toString(), false);
} else {
if (_wantSignals) {
emit loadScript(url.toString(), false);
}
emit loadScript(url.toString(), false);
}
}
@ -1307,8 +1291,23 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co
setParentURL(scriptOrURL);
}
const int SANDBOX_TIMEOUT = 0.25 * MSECS_PER_SECOND;
QScriptEngine sandbox;
QScriptValue testConstructor = sandbox.evaluate(program);
sandbox.setProcessEventsInterval(SANDBOX_TIMEOUT);
QScriptValue testConstructor;
{
QTimer timeout;
timeout.setSingleShot(true);
timeout.start(SANDBOX_TIMEOUT);
connect(&timeout, &QTimer::timeout, [&sandbox, SANDBOX_TIMEOUT]{
auto context = sandbox.currentContext();
if (context) {
// Guard against infinite loops and non-performant code
context->throwError(QString("Timed out (entity constructors are limited to %1ms)").arg(SANDBOX_TIMEOUT));
}
});
testConstructor = sandbox.evaluate(program);
}
if (hadUncaughtExceptions(sandbox, program.fileName())) {
return;
}

View file

@ -67,10 +67,7 @@ public:
class ScriptEngine : public QScriptEngine, public ScriptUser, public EntitiesScriptEngineProvider {
Q_OBJECT
public:
ScriptEngine(const QString& scriptContents = NO_SCRIPT,
const QString& fileNameString = QString(""),
bool wantSignals = true);
ScriptEngine(const QString& scriptContents = NO_SCRIPT, const QString& fileNameString = QString(""));
~ScriptEngine();
/// run the script in a dedicated thread. This will have the side effect of evalulating
@ -83,10 +80,15 @@ public:
/// run the script in the callers thread, exit when stop() is called.
void run();
void waitTillDoneRunning();
QString getFilename() const;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// NOTE - this is intended to be a public interface for Agent scripts, and local scripts, but not for EntityScripts
Q_INVOKABLE void stop();
// Stop any evaluating scripts and wait for the scripting thread to finish.
void waitTillDoneRunning();
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// NOTE - these are NOT intended to be public interfaces available to scripts, the are only Q_INVOKABLE so we can
// properly ensure they are only called on the correct thread
@ -142,10 +144,6 @@ public:
Q_INVOKABLE void requestGarbageCollection() { collectGarbage(); }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// NOTE - this is intended to be a public interface for Agent scripts, and local scripts, but not for EntityScripts
Q_INVOKABLE void stop();
bool isFinished() const { return _isFinished; } // used by Application and ScriptWidget
bool isRunning() const { return _isRunning; } // used by ScriptWidget
@ -195,7 +193,6 @@ protected:
bool _isInitialized { false };
QHash<QTimer*, CallbackData> _timerFunctionMap;
QSet<QUrl> _includedURLs;
bool _wantSignals { true };
QHash<EntityItemID, EntityScriptDetails> _entityScripts;
bool _isThreaded { false };
QScriptEngineDebugger* _debugger { nullptr };
@ -203,6 +200,7 @@ protected:
qint64 _lastUpdate;
void init();
bool evaluatePending() const { return _evaluatesPending > 0; }
void timerFired();
void stopAllTimers();

View file

@ -150,6 +150,7 @@ void ScriptEngines::shutdownScripting() {
// NOTE: typically all script engines are running. But there's at least one known exception to this, the
// "entities sandbox" which is only used to evaluate entities scripts to test their validity before using
// them. We don't need to stop scripts that aren't running.
// TODO: Scripts could be shut down faster if we spread them across a threadpool.
if (scriptEngine->isRunning()) {
qCDebug(scriptengine) << "about to shutdown script:" << scriptName;
@ -158,8 +159,7 @@ void ScriptEngines::shutdownScripting() {
// and stop. We can safely short circuit this because we know we're in the "quitting" process
scriptEngine->disconnect(this);
// Calling stop on the script engine will set it's internal _isFinished state to true, and result
// in the ScriptEngine gracefully ending it's run() method.
// Gracefully stop the engine's scripting thread
scriptEngine->stop();
// We need to wait for the engine to be done running before we proceed, because we don't
@ -171,7 +171,7 @@ void ScriptEngines::shutdownScripting() {
scriptEngine->deleteLater();
// If the script is stopped, we can remove it from our set
// Once the script is stopped, we can remove it from our set
i.remove();
}
}
@ -427,7 +427,7 @@ ScriptEngine* ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserL
return scriptEngine;
}
scriptEngine = new ScriptEngine(NO_SCRIPT, "", true);
scriptEngine = new ScriptEngine(NO_SCRIPT, "");
scriptEngine->setUserLoaded(isUserLoaded);
connect(scriptEngine, &ScriptEngine::doneRunning, this, [scriptEngine] {
scriptEngine->deleteLater();

View file

@ -234,7 +234,5 @@ void VrMenu::removeAction(QAction* action) {
QObject* menu = item->parent();
// Proxy QuickItem requests through the QML layer
QQuickMenuBase* qmlItem = reinterpret_cast<QQuickMenuBase*>(item);
bool invokeResult = QMetaObject::invokeMethod(menu, "removeItem", Qt::DirectConnection,
Q_ARG(QQuickMenuBase*, qmlItem));
Q_ASSERT(invokeResult);
QMetaObject::invokeMethod(menu, "removeItem", Qt::DirectConnection, Q_ARG(QQuickMenuBase*, qmlItem));
}

View file

@ -19,7 +19,6 @@
#include <QtGui/QScreen>
#include <gl/GLWindow.h>
#include <gl/GLWidget.h>
#include <gpu/GLBackend.h>
#include <MainWindow.h>
#include <gl/QOpenGLContextWrapper.h>

View file

@ -40,6 +40,7 @@ var DEFAULT_SOUND_DATA = {
Script.include("../../libraries/utils.js");
Agent.isAvatar = true; // This puts a robot at 0,0,0, but is currently necessary in order to use AvatarList.
Avatar.skeletonModelURL = "http://invalid-url";
function ignore() {}
function debug() { // Display the arguments not just [Object object].
//print.apply(null, [].map.call(arguments, JSON.stringify));

View file

@ -205,7 +205,7 @@
};
return generateOverlayClass(that, ABSTRACT, [
"alpha", "glowLevel", "pulseMax", "pulseMin", "pulsePeriod", "glowLevelPulse",
"alpha", "pulseMax", "pulseMin", "pulsePeriod",
"alphaPulse", "colorPulse", "visible", "anchor"
]);
})();

View file

@ -319,8 +319,6 @@ function addIndicators(modelID) {
}
models[modelID] = modelID;
} else {
Entities.editEntity(modelID, { glowLevel: 0.0 });
}
}

View file

@ -405,6 +405,9 @@ function update() {
if (!Menu.isOptionChecked("First Person")) {
return turnOffVisualization();
} // What to do? menus can be behind hand!
if (!Window.hasFocus()) { // Don't mess with other apps
return turnOffVisualization();
}
var controllerPose = Controller.getPoseValue(activeHand);
// Vive is effectively invalid when not in HMD
if (!controllerPose.valid || ((hardware === 'Vive') && !HMD.active)) {

View file

@ -63,7 +63,6 @@ var MIN_ANGULAR_SIZE = 2;
var MAX_ANGULAR_SIZE = 45;
var allowLargeModels = true;
var allowSmallModels = true;
var wantEntityGlow = false;
var SPAWN_DISTANCE = 1;
var DEFAULT_DIMENSION = 0.20;
@ -715,12 +714,11 @@ function mousePressEvent(event) {
}
}
var highlightedEntityID = null;
var mouseCapturedByTool = false;
var lastMousePosition = null;
var idleMouseTimerId = null;
var CLICK_TIME_THRESHOLD = 500 * 1000; // 500 ms
var CLICK_MOVE_DISTANCE_THRESHOLD = 8;
var CLICK_MOVE_DISTANCE_THRESHOLD = 20;
var IDLE_MOUSE_TIMEOUT = 200;
var DEFAULT_ENTITY_DRAG_DROP_DISTANCE = 2.0;
@ -781,38 +779,6 @@ function handleIdleMouse() {
idleMouseTimerId = null;
}
function highlightEntityUnderCursor(position, accurateRay) {
var pickRay = Camera.computePickRay(position.x, position.y);
var entityIntersection = Entities.findRayIntersection(pickRay, accurateRay);
if (entityIntersection.accurate) {
if (highlightedEntityID && highlightedEntityID != entityIntersection.entityID) {
selectionDisplay.unhighlightSelectable(highlightedEntityID);
highlightedEntityID = {
id: -1
};
}
var halfDiagonal = Vec3.length(entityIntersection.properties.dimensions) / 2.0;
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(),
entityIntersection.properties.position)) * 180 / 3.14;
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) && (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
if (entityIntersection.entityID && sizeOK) {
if (wantEntityGlow) {
Entities.editEntity(entityIntersection.entityID, {
glowLevel: 0.25
});
}
highlightedEntityID = entityIntersection.entityID;
selectionDisplay.highlightSelectable(entityIntersection.entityID);
}
}
}
function mouseReleaseEvent(event) {
mouseDown = false;
@ -1877,4 +1843,4 @@ entityListTool.webView.webEventReceived.connect(function(data) {
}
}
}
});
});

View file

@ -304,7 +304,7 @@ SelectionDisplay = (function() {
var previousHandleColor;
var previousHandleAlpha;
var grabberSizeCorner = 0.025;
var grabberSizeCorner = 0.025; // These get resized by updateHandleSizes().
var grabberSizeEdge = 0.015;
var grabberSizeFace = 0.025;
var grabberAlpha = 1;
@ -4320,7 +4320,7 @@ SelectionDisplay = (function() {
that.updateHandleSizes = function() {
if (selectionManager.hasSelection()) {
var diff = Vec3.subtract(selectionManager.worldPosition, Camera.getPosition());
var grabberSize = Vec3.length(diff) * GRABBER_DISTANCE_TO_SIZE_RATIO;
var grabberSize = Vec3.length(diff) * GRABBER_DISTANCE_TO_SIZE_RATIO * 2;
var dimensions = SelectionManager.worldDimensions;
var avgDimension = (dimensions.x + dimensions.y + dimensions.z) / 3;
grabberSize = Math.min(grabberSize, avgDimension / 10);
@ -4402,4 +4402,4 @@ SelectionDisplay = (function() {
return that;
}());
}());

View file

@ -3,5 +3,5 @@ AUTOSCRIBE_SHADER_LIB(gpu model render-utils)
# This is not a testcase -- just set it up as a regular hifi project
setup_hifi_project(Quick Gui OpenGL Script Widgets)
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
link_hifi_libraries(networking gl gpu procedural shared fbx model model-networking animation script-engine render render-utils )
link_hifi_libraries(networking gl gpu gpu-gl procedural shared fbx model model-networking animation script-engine render render-utils )
package_libraries_for_deployment()

View file

@ -30,7 +30,7 @@
#include <gpu/Context.h>
#include <gpu/Batch.h>
#include <gpu/Stream.h>
#include <gpu/GLBackend.h>
#include <gpu/gl/GLBackend.h>
#include <gl/QOpenGLContextWrapper.h>
#include <gl/QOpenGLDebugLoggerWrapper.h>
@ -87,7 +87,6 @@ uint32_t toCompactColor(const glm::vec4& color);
const char* VERTEX_SHADER = R"SHADER(
#version 450 core
layout(location = 0) in vec4 inPosition;
layout(location = 3) in vec2 inTexCoord0;
@ -157,7 +156,6 @@ void main(void) {
})SHADER";
const char* FRAGMENT_SHADER = R"SHADER(
#version 450 core
uniform sampler2D originalTexture;
@ -246,7 +244,7 @@ public:
makeCurrent();
setupDebugLogger(this);
gpu::Context::init<gpu::GLBackend>();
gpu::Context::init<gpu::gl::GLBackend>();
_context = std::make_shared<gpu::Context>();
makeCurrent();
auto shader = makeShader(unlit_vert, unlit_frag, gpu::Shader::BindingSet{});

View file

@ -6,6 +6,6 @@ setup_hifi_project(Quick Gui OpenGL)
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
# link in the shared libraries
link_hifi_libraries(render-utils gl gpu shared)
link_hifi_libraries(render-utils gl gpu gpu-gl shared)
package_libraries_for_deployment()

View file

@ -12,7 +12,7 @@
#include <string>
#include <vector>
#include <gpu/GLBackend.h>
#include <gpu/gl/GLBackend.h>
#include <gl/QOpenGLContextWrapper.h>
#include <gl/QOpenGLDebugLoggerWrapper.h>
@ -111,7 +111,7 @@ public:
show();
makeCurrent();
gpu::Context::init<gpu::GLBackend>();
gpu::Context::init<gpu::gl::GLBackend>();
setupDebugLogger(this);

View file

@ -8,7 +8,7 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
#include_oglplus()
# link in the shared libraries
link_hifi_libraries(shared octree gl gpu model render fbx networking entities
link_hifi_libraries(shared octree gl gpu gpu-gl model render fbx networking entities
script-engine physics
render-utils entities-renderer)

View file

@ -8,7 +8,7 @@
#include <iostream>
#include <mutex>
#include <gpu/GLBackend.h>
#include <gpu/gl/GLBackend.h>
#include <QLoggingCategory>
#include <QResizeEvent>
@ -114,7 +114,7 @@ public:
show();
makeCurrent();
gpu::Context::init<gpu::GLBackend>();
gpu::Context::init<gpu::gl::GLBackend>();
setupDebugLogger(this);
makeCurrent();
resize(QSize(800, 600));

View file

@ -66,42 +66,100 @@
var TRANSFORMER_URL_MATTHEW = 'atp:/dressingRoom/matthew.fbx';
var BEAM_TRIGGER_THRESHOLD = 0.075;
var BEAM_POSITION = {
x: 1103.3876,
y: 460.4591,
z: -74.2998
};
Reset.prototype = {
tidying: false,
eyesOn: false,
flickerInterval: null,
preload: function(entityID) {
_this.entityID = entityID;
_this.tidySound = SoundCache.getSound("atp:/sounds/tidy.wav");
Script.update.connect(_this.update);
},
showTidyingButton: function() {
var data = {
"Texture.001": "atp:/Tidyguy-7.fbx/Tidyguy-7.fbm/Head-Housing-Texture.png",
"button.tidy": "atp:/Tidyguy-7.fbx/Tidyguy-7.fbm/Tidy-Up-Button-Orange.png",
"button.tidy-active": "atp:/Tidyguy-7.fbx/Tidyguy-7.fbm/Tidy-Up-Button-Orange.png",
"button.tidy-active.emit": "atp:/Tidyguy-7.fbx/Tidyguy-7.fbm/Tidy-Up-Button-Orange-Emit.png",
"button.tidy.emit": "atp:/Tidyguy-7.fbx/Tidyguy-7.fbm/Tidy-Up-Button-Orange-Emit.png",
"tex.button.blanks": "atp:/Tidyguy-7.fbx/Tidyguy-7.fbm/Button-Blanks.png",
"tex.button.blanks.normal": "atp:/Tidyguy-7.fbx/Tidyguy-7.fbm/Button-Blanks-Normal.png",
"tex.face.sceen": "atp:/Tidyguy-7.fbx/Tidyguy-7.fbm/tidy-guy-face.png",
"tex.face.screen.emit": "atp:/Tidyguy-7.fbx/Tidyguy-7.fbm/tidy-guy-face-Emit.png"
}
"Texture": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/Tidy-Swipe-Sticker.jpg",
"Texture.001": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/Head-Housing-Texture.png",
"Texture.003": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/Tidy-Swipe-Sticker-Emit.jpg",
"tex.button.blanks": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/Button-Blanks.png",
"tex.button.blanks.normal": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/Button-Blanks-Normal.png",
"tex.face.sceen.default": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/face-default.jpg",
"tex.face.screen-active": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/face-active.jpg",
"tex.glow.active": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/glow-active.png",
"tex.glow.default": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/glow-active.png"
};
Entities.editEntity(_this.entityID, {
textures: JSON.stringify(data)
});
},
tidyGlowActive: function() {
var res = Entities.findEntities(MyAvatar.position, 30);
var glow = null;
res.forEach(function(item) {
var props = Entities.getEntityProperties(item);
if (props.name === "Tidyguy-Glow") {
glow = item;
}
});
if (glow !== null) {
Entities.editEntity(glow, {
color: {
red: 255,
green: 140,
blue: 20
}
});
}
},
tidyGlowDefault: function() {
var res = Entities.findEntities(MyAvatar.position, 30);
var glow = null;
res.forEach(function(item) {
var props = Entities.getEntityProperties(item);
if (props.name === "Tidyguy-Glow") {
glow = item;
}
});
if (glow !== null) {
Entities.editEntity(glow, {
color: {
red: 92,
green: 255,
blue: 209
}
});
}
},
showTidyButton: function() {
var data = {
"Texture.001": "atp:/Tidyguy-7.fbx/Tidyguy-7.fbm/Head-Housing-Texture.png",
"button.tidy": "atp:/Tidyguy-7.fbx/Tidyguy-7.fbm/Tidy-Up-Button-Green.png",
"button.tidy.emit": "atp:/Tidyguy-7.fbx/Tidyguy-7.fbm/Tidy-Up-Button-Green-Emit.png",
"tex.button.blanks": "atp:/Tidyguy-7.fbx/Tidyguy-7.fbm/Button-Blanks.png",
"tex.button.blanks.normal": "atp:/Tidyguy-7.fbx/Tidyguy-7.fbm/Button-Blanks-Normal.png",
"tex.face.sceen": "atp:/Tidyguy-7.fbx/Tidyguy-7.fbm/tidy-guy-face.png",
"tex.face.screen.emit": "atp:/Tidyguy-7.fbx/Tidyguy-7.fbm/tidy-guy-face-Emit.png"
}
"Texture": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/Tidy-Swipe-Sticker.jpg",
"Texture.001": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/Head-Housing-Texture.png",
"Texture.003": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/Tidy-Swipe-Sticker-Emit.jpg",
"tex.button.blanks": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/Button-Blanks.png",
"tex.button.blanks.normal": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/Button-Blanks-Normal.png",
"tex.face.sceen.default": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/face-default.jpg",
"tex.face.screen-active": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/face-active.jpg",
"tex.glow.active": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/glow-active.png",
"tex.glow.default": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/glow-default.png"
};
Entities.editEntity(_this.entityID, {
textures: JSON.stringify(data)
@ -109,7 +167,16 @@
},
playTidyingSound: function() {
var location = {
x: 1102.7660,
y: 460.9814,
z: -78.6451
};
var injector = Audio.playSound(_this.tidySound, {
volume: 1,
position: location
});
},
toggleButton: function() {
@ -118,11 +185,13 @@
} else {
_this.tidying = true;
_this.showTidyingButton();
_this.tidyGlowActive();
_this.playTidyingSound();
_this.flickerEyes();
_this.findAndDeleteHomeEntities();
Script.setTimeout(function() {
_this.showTidyButton();
_this.tidyGlowDefault();
_this.tidying = false;
}, 2500);
@ -130,22 +199,67 @@
_this.createKineticEntities();
_this.createScriptedEntities();
_this.setupDressingRoom();
}, 750)
}, 750);
}
},
flickerEyes: function() {
this.flickerInterval = Script.setInterval(function() {
if (_this.eyesOn === true) {
_this.turnEyesOff();
_this.eyesOn = false;
} else if (_this.eyesOn === false) {
_this.turnEyesOn();
_this.eyesOn = true
}
}, 100);
Script.setTimeout(function() {
Script.clearInterval(_this.flickerInterval);
}, 2500);
},
turnEyesOn: function() {
var data = {
"Texture": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/Tidy-Swipe-Sticker.jpg",
"Texture.001": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/Head-Housing-Texture.png",
"Texture.003": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/Tidy-Swipe-Sticker-Emit.jpg",
"tex.button.blanks": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/Button-Blanks.png",
"tex.button.blanks.normal": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/Button-Blanks-Normal.png",
"tex.face.sceen.default": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/face-active.jpg",
"tex.face.screen-active": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/face-active.jpg",
"tex.glow.active": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/glow-active.png",
"tex.glow.default": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/glow-active.png"
};
Entities.editEntity(_this.entityID, {
textures: JSON.stringify(data)
});
},
turnEyesOff: function() {
var data = {
"Texture": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/Tidy-Swipe-Sticker.jpg",
"Texture.001": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/Head-Housing-Texture.png",
"Texture.003": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/Tidy-Swipe-Sticker-Emit.jpg",
"tex.button.blanks": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/Button-Blanks.png",
"tex.button.blanks.normal": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/Button-Blanks-Normal.png",
"tex.face.sceen.default": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/face-default.jpg",
"tex.face.screen-active": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/face-active.jpg",
"tex.glow.active": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/glow-active.png",
"tex.glow.default": "atp:/Tidyguy-4d.fbx/Tidyguy-4d.fbm/glow-active.png"
};
Entities.editEntity(_this.entityID, {
textures: JSON.stringify(data)
});
},
clickReleaseOnEntity: function(entityID, mouseEvent) {
if (!mouseEvent.isLeftButton) {
return;
}
_this.toggleButton();
},
startNearTrigger: function() {
_this.toggleButton();
},
findAndDeleteHomeEntities: function() {
@ -155,12 +269,10 @@
var found = [];
results.forEach(function(result) {
var properties = Entities.getEntityProperties(result);
if (properties.userData === "" || properties.userData === undefined) {
print('no userdata -- its blank or undefined')
return;
}
var userData = null;
try {
userData = JSON.parse(properties.userData);
@ -174,10 +286,9 @@
Entities.deleteEntity(result);
}
}
})
print('HOME after deleting home entities')
print('HOME after deleting home entities');
},
createScriptedEntities: function() {
@ -311,11 +422,11 @@
y: 461,
z: -73.3
});
print('HOME after creating kinetic entities')
print('HOME after creating kinetic entities');
},
setupDressingRoom: function() {
print('HOME setup dressing room')
print('HOME setup dressing room');
this.createRotatorBlock();
this.createTransformingDais();
this.createTransformers();
@ -362,7 +473,7 @@
}
var rotatorBlock = Entities.addEntity(rotatorBlockProps);
print('HOME created rotator block')
print('HOME created rotator block');
},
createTransformingDais: function() {
@ -479,8 +590,25 @@
},
update: function() {
if (_this.tidying === true) {
return;
}
var leftHandPosition = MyAvatar.getLeftPalmPosition();
var rightHandPosition = MyAvatar.getRightPalmPosition();
var rightDistance = Vec3.distance(leftHandPosition, BEAM_POSITION)
var leftDistance = Vec3.distance(rightHandPosition, BEAM_POSITION)
if (rightDistance < BEAM_TRIGGER_THRESHOLD || leftDistance < BEAM_TRIGGER_THRESHOLD) {
_this.toggleButton();
}
},
unload: function() {
// this.findAndDeleteHomeEntities();
Script.update.disconnect(_this.update);
Script.clearInterval(_this.flickerInterval);
}
}

View file

@ -9,7 +9,7 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
Script.include("libraries/utils.js");
Script.include("../libraries/utils.js");
var basketballURL ="http://hifi-production.s3.amazonaws.com/DomainContent/Toybox/basketball/basketball2.fbx";
var collisionSoundURL = "http://hifi-production.s3.amazonaws.com/DomainContent/Toybox/basketball/basketball.wav";

View file

@ -11,7 +11,7 @@
(function() {
Script.include("libraries/utils.js");
Script.include("../libraries/utils.js");
var NOTCH_ARROW_SOUND_URL = 'http://hifi-production.s3.amazonaws.com/DomainContent/Toybox/bow/notch.wav';
var SHOOT_ARROW_SOUND_URL = 'http://hifi-production.s3.amazonaws.com/DomainContent/Toybox/bow/String_release2.L.wav';

View file

@ -10,7 +10,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var utilsPath = Script.resolvePath('libraries/utils.js');
var utilsPath = Script.resolvePath('../libraries/utils.js');
Script.include(utilsPath);
var SCRIPT_URL = Script.resolvePath('bow.js');

View file

@ -10,7 +10,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
/*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */
Script.include("libraries/utils.js");
Script.include("../libraries/utils.js");
var WAND_MODEL = 'http://hifi-production.s3.amazonaws.com/DomainContent/Toybox/bubblewand/wand.fbx';
var WAND_COLLISION_SHAPE = 'http://hifi-production.s3.amazonaws.com/DomainContent/Toybox/bubblewand/wand_collision_hull.obj';

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