mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-17 10:06:42 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into no-fly-zones
This commit is contained in:
commit
74520f5c92
110 changed files with 1200 additions and 1070 deletions
2
LICENSE
2
LICENSE
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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 };
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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...";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -33,7 +33,6 @@ signals:
|
|||
protected:
|
||||
void displayAddressOfflineMessage();
|
||||
void displayAddressNotFoundMessage();
|
||||
void hide();
|
||||
|
||||
Q_INVOKABLE void loadAddress(const QString& address);
|
||||
Q_INVOKABLE void loadHome();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QDesktopWidget>
|
||||
|
||||
#include <gpu/GLBackend.h>
|
||||
#include <ViewFrustum.h>
|
||||
#include <MatrixStack.h>
|
||||
#include <plugins/PluginContainer.h>
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -128,7 +128,7 @@ protected:
|
|||
}
|
||||
|
||||
private:
|
||||
void setupEntitiesScriptEngine();
|
||||
void resetEntitiesScriptEngine();
|
||||
|
||||
void addEntityToScene(EntityItemPointer entity);
|
||||
bool findBestZoneAndMaybeContainingEntities(const glm::vec3& avatarPosition, QVector<EntityItemID>* entitiesContainingAvatar);
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -36,9 +36,6 @@ EntityItemProperties BoxEntityItem::getProperties(EntityPropertyFlags desiredPro
|
|||
properties._color = getXColor();
|
||||
properties._colorChanged = false;
|
||||
|
||||
properties._glowLevel = getGlowLevel();
|
||||
properties._glowLevelChanged = false;
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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("");
|
||||
|
|
|
@ -53,10 +53,6 @@ EntityItemProperties LineEntityItem::getProperties(EntityPropertyFlags desiredPr
|
|||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(linePoints, getLinePoints);
|
||||
|
||||
|
||||
properties._glowLevel = getGlowLevel();
|
||||
properties._glowLevelChanged = false;
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -37,7 +37,6 @@ private:
|
|||
bool _foundOld;
|
||||
bool _foundNew;
|
||||
bool _removeOld;
|
||||
bool _dontMove;
|
||||
quint64 _changeTime;
|
||||
|
||||
AACube _oldEntityCube;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
8
libraries/gpu-gl/CMakeLists.txt
Normal file
8
libraries/gpu-gl/CMakeLists.txt
Normal 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()
|
|
@ -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();
|
|
@ -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
|
2
libraries/gpu/src/gpu/GLBackendBuffer.cpp → libraries/gpu-gl/src/gpu/gl/GLBackendBuffer.cpp
Executable file → Normal file
2
libraries/gpu/src/gpu/GLBackendBuffer.cpp → libraries/gpu-gl/src/gpu/gl/GLBackendBuffer.cpp
Executable file → Normal 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;
|
2
libraries/gpu/src/gpu/GLBackendInput.cpp → libraries/gpu-gl/src/gpu/gl/GLBackendInput.cpp
Executable file → Normal file
2
libraries/gpu/src/gpu/GLBackendInput.cpp → libraries/gpu-gl/src/gpu/gl/GLBackendInput.cpp
Executable file → Normal 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);
|
40
libraries/gpu/src/gpu/GLBackendOutput.cpp → libraries/gpu-gl/src/gpu/gl/GLBackendOutput.cpp
Executable file → Normal file
40
libraries/gpu/src/gpu/GLBackendOutput.cpp → libraries/gpu-gl/src/gpu/gl/GLBackendOutput.cpp
Executable file → Normal 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);
|
||||
|
22
libraries/gpu/src/gpu/GLBackendPipeline.cpp → libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp
Executable file → Normal file
22
libraries/gpu/src/gpu/GLBackendPipeline.cpp → libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp
Executable file → Normal 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) {
|
|
@ -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();
|
||||
}
|
||||
}
|
60
libraries/gpu/src/gpu/GLBackendShader.cpp → libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp
Executable file → Normal file
60
libraries/gpu/src/gpu/GLBackendShader.cpp → libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp
Executable file → Normal 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, ¤tProgram);
|
||||
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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
} }
|
|
@ -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
|
|
@ -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()
|
||||
{}
|
9
libraries/gpu/src/gpu/GLBackendTexture.cpp → libraries/gpu-gl/src/gpu/gl/GLBackendTexture.cpp
Executable file → Normal file
9
libraries/gpu/src/gpu/GLBackendTexture.cpp → libraries/gpu-gl/src/gpu/gl/GLBackendTexture.cpp
Executable file → Normal 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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
} }
|
4
libraries/gpu/src/gpu/GLBackendTransform.cpp → libraries/gpu-gl/src/gpu/gl/GLBackendTransform.cpp
Executable file → Normal file
4
libraries/gpu/src/gpu/GLBackendTransform.cpp → libraries/gpu-gl/src/gpu/gl/GLBackendTransform.cpp
Executable file → Normal 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) {
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -449,6 +449,8 @@ public:
|
|||
|
||||
const GPUObjectPointer gpuObject {};
|
||||
|
||||
uint32 getHardwareId() const;
|
||||
|
||||
protected:
|
||||
std::unique_ptr< Storage > _storage;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -205,7 +205,7 @@
|
|||
};
|
||||
|
||||
return generateOverlayClass(that, ABSTRACT, [
|
||||
"alpha", "glowLevel", "pulseMax", "pulseMin", "pulsePeriod", "glowLevelPulse",
|
||||
"alpha", "pulseMax", "pulseMin", "pulsePeriod",
|
||||
"alphaPulse", "colorPulse", "visible", "anchor"
|
||||
]);
|
||||
})();
|
||||
|
|
|
@ -319,8 +319,6 @@ function addIndicators(modelID) {
|
|||
}
|
||||
|
||||
models[modelID] = modelID;
|
||||
} else {
|
||||
Entities.editEntity(modelID, { glowLevel: 0.0 });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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) {
|
|||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
|
||||
}());
|
||||
}());
|
||||
|
|
|
@ -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()
|
|
@ -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{});
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue