mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-04-07 12:34:31 +02:00
Merge remote-tracking branch 'upstream/master' into docs/deb-rpm-package-instructions
This commit is contained in:
commit
44da6dca36
66 changed files with 579 additions and 188 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -111,3 +111,4 @@ tools/unity-avatar-exporter
|
|||
server-console/package-lock.json
|
||||
vcpkg/
|
||||
/tools/nitpick/compiledResources
|
||||
qt/
|
|
@ -1,8 +1,8 @@
|
|||
# Build Android
|
||||
|
||||
*Last Updated on December 21, 2019*
|
||||
*Last Updated on December 15, 2020*
|
||||
|
||||
Please read the [general build guide](BUILD.md) for information on building other platforms. Only Android specific instructions are found in this file. **Note that these instructions apply to building for Oculus Quest.**
|
||||
Please read the [general build guide](BUILD.md) for information on building other platforms. Only Android specific instructions are found in this file. **Note that these instructions apply to building for the Oculus Quest 1.**
|
||||
|
||||
## Dependencies
|
||||
|
||||
|
@ -14,7 +14,7 @@ Please install the dependencies for your OS using the [Windows](BUILD_WIN.md), [
|
|||
|
||||
### Android Studio
|
||||
|
||||
Download the [Android Studio](https://developer.android.com/studio/index.html) installer and run it. Once installed, at the welcome screen, click _Configure_ in the lower right corner and select _SDK Manager_.
|
||||
Download the [Android Studio](https://developer.android.com/studio/index.html) installer and run it. Once installed, click _File_ then _Settings_, expand _Appearance & Behavior_ then expand _System Settings_ and select _Android SDK_.
|
||||
|
||||
From the _SDK Platforms_ tab, select API levels 26 and 28.
|
||||
|
||||
|
@ -27,14 +27,16 @@ From the _SDK Tools_ tab, select the following
|
|||
* Android SDK Tools
|
||||
* NDK (even if you have the NDK installed separately)
|
||||
|
||||
Still in the _SDK Tools_ tab, click _Show Package Details_. Select CMake 3.6.4. Do this even if you have a separate CMake installation.
|
||||
Still in the _SDK Tools_ tab, check off _Show Package Details_ at the bottom. Select CMake 3.6.4. Do this even if you have a separate CMake installation. Also, make sure the NDK installed version is 18 (or higher).
|
||||
|
||||
Also, make sure the NDK installed version is 18 (or higher).
|
||||
Now go back to _File_ then _Project Structure_ then under _Project_ set the Android Gradle Plugin Version to `3.2.1` and Gradle Version to `4.10.1`.
|
||||
|
||||
If Android Studio pops open the "Plugin Update Recommeded" dialog, do not click update, just click X on the top right to close. Later versions of the Gradle plugin have known issues with cz.malohlava.
|
||||
|
||||
## Environment
|
||||
|
||||
### Create a keystore in Android Studio
|
||||
Follow the directions [here](https://developer.android.com/studio/publish/app-signing#generate-key) to create a keystore file. You can save it anywhere (preferably not in the `hifi` folder).
|
||||
Follow the directions [here](https://developer.android.com/studio/publish/app-signing#generate-key) to create a keystore file. You can save it anywhere (preferably not in the `vircadia` folder).
|
||||
|
||||
### Set up machine specific Gradle properties
|
||||
|
||||
|
@ -62,7 +64,11 @@ Add these lines to `gradle.properties`
|
|||
SUPPRESS_INTERFACE
|
||||
SUPPRESS_FRAME_PLAYER
|
||||
|
||||
The above code to suppress modules is not necessary, but will speed up the build process.
|
||||
|
||||
#### The Frame Player for both Android Phone and Oculus Quest is optional, so if you encounter problems with these during your build, you can skip them by adding these lines to `gradle.properties`
|
||||
|
||||
SUPPRESS_FRAME_PLAYER
|
||||
SUPPRESS_QUEST_FRAME_PLAYER
|
||||
|
||||
### Clone the repository
|
||||
|
||||
|
@ -74,12 +80,17 @@ The above code to suppress modules is not necessary, but will speed up the build
|
|||
|
||||
* Open Android Studio
|
||||
* Choose _Open an existing Android Studio project_
|
||||
* Navigate to the `hifi` repository and choose the `android` folder and select _OK_
|
||||
* Navigate to the `vircadia` repository that had you cloned and choose the `android` folder and select _OK_
|
||||
* Wait for Gradle to sync (this should take around 20 minutes the first time)
|
||||
* From the _Build_ menu select _Make Project_
|
||||
* If a dialog pops open saying "Plugin Update Recommeded" dialog, do not click update, just click X on the top right to close.
|
||||
* In the _Project_ window click on the project you wish to build (i.e. "questInterface") then click _Build_ in the top menu and choose _Make Module 'questInterface'_
|
||||
* By default this will build the "debug" apk, you can change this by opening the _Build Variants_ window along the left side and select other build types such as "release".
|
||||
* Your newly build APK should reside in `vircadia\android\apps\questInterface\release` (if you chose release).
|
||||
|
||||
### Running a Module
|
||||
|
||||
You are free to use the "adb" command line or other development tools to install (sideload on Quest) your newly built APK, or you can follow the instructions below to load the APK via Android Studio.
|
||||
|
||||
* In the toolbar at the top of Android Studio, next to the green hammer icon, you should see a dropdown menu.
|
||||
* You may already see a configuration for the module you are trying to build. If so, select it.
|
||||
* Otherwise, select _Edit Configurations_.
|
||||
|
@ -112,9 +123,17 @@ To view a more complete debug log,
|
|||
* Click the icon with the two overlapping squares in the upper left corner of the tab where the sync is running (hover text says _Toggle view_)
|
||||
* To change verbosity, click _File > Settings_. Under _Build, Execution, Deployment > Compiler_ you can add command-line flags, as per Gradle documentation
|
||||
|
||||
If you encounter CMake issues, try adding the following system environment variable:
|
||||
|
||||
With your start menu, search for 'Edit the System Environment Variables' and open it.
|
||||
* Click on 'Advanced' tab, then 'Environment Variables'
|
||||
* Select 'New' under System variables
|
||||
* Set "Variable name" to QT_CMAKE_PREFIX_PATH
|
||||
* Set "Variable value" to the directory that your android build placed the CMake 3.6.4 library CMake directory (i.e. android\qt\lib\cmake).
|
||||
|
||||
Some things you can try if you want to do a clean build
|
||||
|
||||
* Delete the `build` and `.externalNativeBuild` folders from the folder for each module you're building (for example, `hifi/android/apps/interface`)
|
||||
* Delete the `build` and `.externalNativeBuild` folders from the folder for each module you're building (for example, `vircadia/android/apps/interface`)
|
||||
* If you have set your `HIFI_VCPKG_ROOT` environment variable, delete the contents of that directory; otherwise, delete `AppData/Local/Temp/hifi`
|
||||
* In Android Studio, click _File > Invalidate Caches / Restart_ and select _Invalidate and Restart_
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include <Trace.h>
|
||||
#include <StatTracker.h>
|
||||
#include <ThreadHelpers.h>
|
||||
|
||||
#include "AssignmentClientLogging.h"
|
||||
#include "AssignmentFactory.h"
|
||||
|
@ -235,10 +236,13 @@ void AssignmentClient::handleCreateAssignmentPacket(QSharedPointer<ReceivedMessa
|
|||
qCDebug(assignment_client) << "Destination IP for assignment is" << nodeList->getDomainHandler().getIP().toString();
|
||||
|
||||
// start the deployed assignment
|
||||
QThread* workerThread = new QThread;
|
||||
QThread* workerThread = new QThread();
|
||||
workerThread->setObjectName("ThreadedAssignment Worker");
|
||||
|
||||
connect(workerThread, &QThread::started, _currentAssignment.data(), &ThreadedAssignment::run);
|
||||
connect(workerThread, &QThread::started, _currentAssignment.data(), [this] {
|
||||
setThreadName("ThreadedAssignment Worker");
|
||||
_currentAssignment->run();
|
||||
});
|
||||
|
||||
// Once the ThreadedAssignment says it is finished - we ask it to deleteLater
|
||||
// This is a queued connection so that it is put into the event loop to be processed by the worker
|
||||
|
|
|
@ -11,9 +11,13 @@
|
|||
|
||||
#include "AudioMixerSlavePool.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include <ThreadHelpers.h>
|
||||
|
||||
void AudioMixerSlaveThread::run() {
|
||||
while (true) {
|
||||
wait();
|
||||
|
@ -157,6 +161,7 @@ void AudioMixerSlavePool::resize(int numThreads) {
|
|||
// start new slaves
|
||||
for (int i = 0; i < numThreads - _numThreads; ++i) {
|
||||
auto slave = new AudioMixerSlaveThread(*this, _workerSharedData);
|
||||
QObject::connect(slave, &QThread::started, [] { setThreadName("AudioMixerSlaveThread"); });
|
||||
slave->start();
|
||||
_slaves.emplace_back(slave);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <QtCore/QDir>
|
||||
|
||||
#include <OctreeDataUtils.h>
|
||||
#include <ThreadHelpers.h>
|
||||
|
||||
Q_LOGGING_CATEGORY(octree_server, "hifi.octree-server")
|
||||
|
||||
|
@ -1192,7 +1193,10 @@ void OctreeServer::domainSettingsRequestComplete() {
|
|||
_persistAsFileType);
|
||||
_persistManager->moveToThread(&_persistThread);
|
||||
connect(&_persistThread, &QThread::finished, _persistManager, &QObject::deleteLater);
|
||||
connect(&_persistThread, &QThread::started, _persistManager, &OctreePersistThread::start);
|
||||
connect(&_persistThread, &QThread::started, _persistManager, [this] {
|
||||
setThreadName("OctreePersistThread");
|
||||
_persistManager->start();
|
||||
});
|
||||
connect(_persistManager, &OctreePersistThread::loadCompleted, this, [this]() {
|
||||
beginRunning();
|
||||
});
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
#include <Gzip.h>
|
||||
|
||||
#include <OctreeDataUtils.h>
|
||||
#include <ThreadHelpers.h>
|
||||
|
||||
using namespace std::chrono;
|
||||
|
||||
|
@ -830,9 +831,11 @@ void DomainServer::setupNodeListAndAssignments() {
|
|||
// set a custom packetVersionMatch as the verify packet operator for the udt::Socket
|
||||
nodeList->setPacketFilterOperator(&DomainServer::isPacketVerified);
|
||||
|
||||
_assetClientThread.setObjectName("AssetClient Thread");
|
||||
QString name = "AssetClient Thread";
|
||||
_assetClientThread.setObjectName(name);
|
||||
auto assetClient = DependencyManager::set<AssetClient>();
|
||||
assetClient->moveToThread(&_assetClientThread);
|
||||
connect(&_assetClientThread, &QThread::started, [name] { setThreadName(name.toStdString()); });
|
||||
_assetClientThread.start();
|
||||
// add whatever static assignments that have been parsed to the queue
|
||||
addStaticAssignmentsToQueue();
|
||||
|
|
|
@ -13,6 +13,9 @@ Item {
|
|||
property alias url: webViewCore.url
|
||||
property alias canGoBack: webViewCore.canGoBack
|
||||
property alias webViewCore: webViewCore
|
||||
// FIXME - This was commented out to allow for manual setting of the userAgent.
|
||||
//
|
||||
// property alias webViewCoreProfile: webViewCore.profile
|
||||
property string webViewCoreUserAgent
|
||||
|
||||
property bool useBackground: webViewCore.useBackground
|
||||
|
|
|
@ -11,6 +11,9 @@ Item {
|
|||
property alias url: webViewCore.url
|
||||
property alias canGoBack: webViewCore.canGoBack
|
||||
property alias webViewCore: webViewCore
|
||||
// FIXME - This was commented out to allow for manual setting of the userAgent.
|
||||
//
|
||||
// property alias webViewCoreProfile: webViewCore.profile
|
||||
|
||||
property alias useBackground: webViewCore.useBackground
|
||||
property alias userAgent: webViewCore.userAgent
|
||||
|
|
|
@ -27,7 +27,11 @@ Item {
|
|||
}
|
||||
*/
|
||||
|
||||
property alias viewProfile: webroot.webViewCoreProfile
|
||||
// FIXME - Reimplement profiles for... why? Was it so that new windows opened share the same profile?
|
||||
// Are profiles written to by the webengine during the session?
|
||||
// Removed in PR Feature/web entity user agent #988
|
||||
//
|
||||
// property alias viewProfile: webroot.webViewCoreProfile
|
||||
|
||||
FlickableWebViewCore {
|
||||
id: webroot
|
||||
|
|
|
@ -25,7 +25,11 @@ Item {
|
|||
property bool isDesktop: false
|
||||
property alias url: web.url
|
||||
property alias webView: web.webViewCore
|
||||
property alias profile: web.webViewCoreProfile
|
||||
// FIXME - Reimplement profiles for... why? Was it so that new windows opened share the same profile?
|
||||
// Are profiles written to by the webengine during the session?
|
||||
// Removed in PR Feature/web entity user agent #988
|
||||
//
|
||||
// property alias profile: web.webViewCoreProfile
|
||||
property bool remove: false
|
||||
property bool closeButtonVisible: true
|
||||
|
||||
|
|
|
@ -38,6 +38,12 @@ Item {
|
|||
}
|
||||
*/
|
||||
|
||||
// FIXME - Reimplement profiles for... why? Was it so that new windows opened share the same profile?
|
||||
// Are profiles written to by the webengine during the session?
|
||||
// Removed in PR Feature/web entity user agent #988
|
||||
//
|
||||
// property alias viewProfile: webroot.webViewCoreProfile
|
||||
|
||||
FlickableWebViewCore {
|
||||
id: webroot
|
||||
width: parent.width
|
||||
|
|
|
@ -254,6 +254,7 @@
|
|||
|
||||
#include "AboutUtil.h"
|
||||
#include "ExternalResource.h"
|
||||
#include <ThreadHelpers.h>
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
#include <VersionHelpers.h>
|
||||
|
@ -1168,6 +1169,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
if (!DISABLE_WATCHDOG) {
|
||||
auto deadlockWatchdogThread = new DeadlockWatchdogThread();
|
||||
deadlockWatchdogThread->setMainThreadID(QThread::currentThreadId());
|
||||
connect(deadlockWatchdogThread, &QThread::started, [] { setThreadName("DeadlockWatchdogThread"); });
|
||||
deadlockWatchdogThread->start();
|
||||
|
||||
// Pause the deadlock watchdog when we sleep, or it might
|
||||
|
@ -5206,6 +5208,7 @@ void getCpuUsage(vec3& systemAndUser) {
|
|||
void setupCpuMonitorThread() {
|
||||
initCpuUsage();
|
||||
auto cpuMonitorThread = QThread::currentThread();
|
||||
setThreadName("CPU Monitor Thread");
|
||||
|
||||
QTimer* timer = new QTimer();
|
||||
timer->setInterval(50);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include <SharedUtil.h>
|
||||
#include <shared/QtHelpers.h>
|
||||
#include <ThreadHelpers.h>
|
||||
|
||||
#include "AudioConstants.h"
|
||||
#include "AudioInjector.h"
|
||||
|
@ -54,11 +55,14 @@ AudioInjectorManager::~AudioInjectorManager() {
|
|||
}
|
||||
|
||||
void AudioInjectorManager::createThread() {
|
||||
_thread = new QThread;
|
||||
_thread = new QThread();
|
||||
_thread->setObjectName("Audio Injector Thread");
|
||||
|
||||
// when the thread is started, have it call our run to handle injection of audio
|
||||
connect(_thread, &QThread::started, this, &AudioInjectorManager::run, Qt::DirectConnection);
|
||||
connect(_thread, &QThread::started, this, [this] {
|
||||
setThreadName("AudioInjectorManager");
|
||||
run();
|
||||
}, Qt::DirectConnection);
|
||||
|
||||
moveToThread(_thread);
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) :
|
|||
{
|
||||
// SkeletonModels, and by extention Avatars, use Dual Quaternion skinning.
|
||||
_useDualQuaternionSkinning = true;
|
||||
_forceOffset = true;
|
||||
|
||||
// Avatars all cast shadow
|
||||
setCanCastShadow(true);
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "CompositorHelper.h"
|
||||
#include "Logging.h"
|
||||
#include "RefreshRateController.h"
|
||||
#include <ThreadHelpers.h>
|
||||
|
||||
using namespace shader::gpu::program;
|
||||
|
||||
|
@ -285,6 +286,7 @@ bool OpenGLDisplayPlugin::activate() {
|
|||
widget->context()->doneCurrent();
|
||||
|
||||
presentThread->setContext(widget->context());
|
||||
connect(presentThread.data(), &QThread::started, [] { setThreadName("OpenGL Present Thread"); });
|
||||
// Start execution
|
||||
presentThread->start();
|
||||
}
|
||||
|
|
|
@ -368,6 +368,11 @@ bool EntityRenderer::needsRenderUpdate() const {
|
|||
return needsRenderUpdateFromEntity(_entity);
|
||||
}
|
||||
|
||||
Transform EntityRenderer::getTransformToCenterWithMaybeOnlyLocalRotation(const EntityItemPointer& entity, bool& success) const {
|
||||
return entity->getBillboardMode() == BillboardMode::NONE ? entity->getTransformToCenter(success) :
|
||||
entity->getTransformToCenterWithOnlyLocalRotation(success);
|
||||
}
|
||||
|
||||
// Returns true if the item in question needs to have updateInScene called because of changes in the entity
|
||||
bool EntityRenderer::needsRenderUpdateFromEntity(const EntityItemPointer& entity) const {
|
||||
if (entity->needsRenderUpdate()) {
|
||||
|
@ -379,12 +384,12 @@ bool EntityRenderer::needsRenderUpdateFromEntity(const EntityItemPointer& entity
|
|||
}
|
||||
|
||||
bool success = false;
|
||||
auto bound = _entity->getAABox(success);
|
||||
auto bound = entity->getAABox(success);
|
||||
if (success && _bound != bound) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto newModelTransform = _entity->getTransformToCenter(success);
|
||||
auto newModelTransform = getTransformToCenterWithMaybeOnlyLocalRotation(entity, success);
|
||||
// FIXME can we use a stale model transform here?
|
||||
if (success && newModelTransform != _modelTransform) {
|
||||
return true;
|
||||
|
@ -401,15 +406,15 @@ bool EntityRenderer::needsRenderUpdateFromEntity(const EntityItemPointer& entity
|
|||
return false;
|
||||
}
|
||||
|
||||
void EntityRenderer::updateModelTransformAndBound() {
|
||||
void EntityRenderer::updateModelTransformAndBound(const EntityItemPointer& entity) {
|
||||
bool success = false;
|
||||
auto newModelTransform = _entity->getTransformToCenter(success);
|
||||
auto newModelTransform = getTransformToCenterWithMaybeOnlyLocalRotation(entity, success);
|
||||
if (success) {
|
||||
_modelTransform = newModelTransform;
|
||||
}
|
||||
|
||||
success = false;
|
||||
auto bound = _entity->getAABox(success);
|
||||
auto bound = entity->getAABox(success);
|
||||
if (success) {
|
||||
_bound = bound;
|
||||
}
|
||||
|
@ -429,7 +434,7 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa
|
|||
|
||||
_prevIsTransparent = transparent;
|
||||
|
||||
updateModelTransformAndBound();
|
||||
updateModelTransformAndBound(entity);
|
||||
|
||||
_moving = entity->isMovingRelativeToParent();
|
||||
_visible = entity->getVisible();
|
||||
|
|
|
@ -101,7 +101,7 @@ protected:
|
|||
virtual void doRender(RenderArgs* args) = 0;
|
||||
|
||||
virtual bool isFading() const { return _isFading; }
|
||||
virtual void updateModelTransformAndBound();
|
||||
virtual void updateModelTransformAndBound(const EntityItemPointer& entity);
|
||||
virtual bool isTransparent() const { return _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) < 1.0f : false; }
|
||||
inline bool isValidRenderItem() const { return _renderItemID != Item::INVALID_ITEM_ID; }
|
||||
|
||||
|
@ -109,16 +109,14 @@ protected:
|
|||
virtual void setRenderLayer(RenderLayer value) { _renderLayer = value; }
|
||||
virtual void setCullWithParent(bool value) { _cullWithParent = value; }
|
||||
|
||||
signals:
|
||||
void requestRenderUpdate();
|
||||
|
||||
protected:
|
||||
template<typename T>
|
||||
std::shared_ptr<T> asTypedEntity() { return std::static_pointer_cast<T>(_entity); }
|
||||
|
||||
static void makeStatusGetters(const EntityItemPointer& entity, Item::Status::Getters& statusGetters);
|
||||
const Transform& getModelTransform() const;
|
||||
|
||||
Transform getTransformToCenterWithMaybeOnlyLocalRotation(const EntityItemPointer& entity, bool& success) const;
|
||||
|
||||
Item::Bound _bound;
|
||||
SharedSoundPointer _collisionSound;
|
||||
QUuid _changeHandlerId;
|
||||
|
@ -154,6 +152,9 @@ protected:
|
|||
const EntityItemPointer _entity;
|
||||
|
||||
QUuid _entityID;
|
||||
|
||||
signals:
|
||||
void requestRenderUpdate();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -115,11 +115,12 @@ bool RenderableModelEntityItem::needsUpdateModelBounds() const {
|
|||
}
|
||||
|
||||
bool success;
|
||||
auto transform = getTransform(success);
|
||||
auto transform = getBillboardMode() == BillboardMode::NONE ? getTransform(success) : getTransformWithOnlyLocalRotation(success);
|
||||
if (success) {
|
||||
if (model->getTranslation() != transform.getTranslation()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (model->getRotation() != transform.getRotation()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -171,7 +172,7 @@ void RenderableModelEntityItem::updateModelBounds() {
|
|||
}
|
||||
|
||||
bool success;
|
||||
auto transform = getTransform(success);
|
||||
auto transform = getBillboardMode() == BillboardMode::NONE ? getTransform(success) : getTransformWithOnlyLocalRotation(success);
|
||||
if (success && (model->getTranslation() != transform.getTranslation() ||
|
||||
model->getRotation() != transform.getRotation())) {
|
||||
model->setTransformNoUpdateRenderItems(transform);
|
||||
|
|
|
@ -41,13 +41,13 @@ PolyLineEntityRenderer::PolyLineEntityRenderer(const EntityItemPointer& entity)
|
|||
}
|
||||
}
|
||||
|
||||
void PolyLineEntityRenderer::updateModelTransformAndBound() {
|
||||
void PolyLineEntityRenderer::updateModelTransformAndBound(const EntityItemPointer& entity) {
|
||||
bool success = false;
|
||||
auto newModelTransform = _entity->getTransformToCenter(success);
|
||||
auto newModelTransform = getTransformToCenterWithMaybeOnlyLocalRotation(entity, success);
|
||||
if (success) {
|
||||
_modelTransform = newModelTransform;
|
||||
|
||||
auto lineEntity = std::static_pointer_cast<PolyLineEntityItem>(_entity);
|
||||
auto lineEntity = std::static_pointer_cast<PolyLineEntityItem>(entity);
|
||||
AABox bound;
|
||||
lineEntity->computeTightLocalBoundingBox(bound);
|
||||
bound.transform(newModelTransform);
|
||||
|
|
|
@ -25,7 +25,7 @@ class PolyLineEntityRenderer : public TypedEntityRenderer<PolyLineEntityItem> {
|
|||
public:
|
||||
PolyLineEntityRenderer(const EntityItemPointer& entity);
|
||||
|
||||
void updateModelTransformAndBound() override;
|
||||
void updateModelTransformAndBound(const EntityItemPointer& entity) override;
|
||||
|
||||
virtual bool isTransparent() const override;
|
||||
|
||||
|
|
|
@ -1785,8 +1785,9 @@ void PolyVoxEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& s
|
|||
|
||||
void PolyVoxEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
|
||||
_lastVoxelToLocalMatrix = entity->voxelToLocalMatrix();
|
||||
_position = entity->getWorldPosition();
|
||||
_orientation = entity->getWorldOrientation();
|
||||
bool success;
|
||||
_position = entity->getCenterPosition(success);
|
||||
_orientation = entity->getBillboardMode() == BillboardMode::NONE ? entity->getWorldOrientation() : entity->getLocalOrientation();
|
||||
_lastVoxelVolumeSize = entity->getVoxelVolumeSize();
|
||||
_params->setSubData(0, vec4(_lastVoxelVolumeSize, 0.0));
|
||||
graphics::MeshPointer newMesh;
|
||||
|
|
|
@ -56,15 +56,12 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
|
||||
withWriteLock([&] {
|
||||
_shape = entity->getShape();
|
||||
_position = entity->getWorldPosition();
|
||||
_dimensions = entity->getUnscaledDimensions(); // get unscaled to avoid scaling twice
|
||||
_orientation = entity->getWorldOrientation();
|
||||
_renderTransform = getModelTransform(); // contains parent scale, if this entity scales with its parent
|
||||
if (_shape == entity::Sphere) {
|
||||
_renderTransform.postScale(SPHERE_ENTITY_SCALE);
|
||||
}
|
||||
|
||||
_renderTransform.postScale(_dimensions);
|
||||
_renderTransform.postScale(entity->getUnscaledDimensions());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -248,7 +245,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
outColor = procedural->getColor(outColor);
|
||||
outColor.a *= procedural->isFading() ? Interpolate::calculateFadeRatio(procedural->getFadeStartTime()) : 1.0f;
|
||||
withReadLock([&] {
|
||||
procedural->prepare(batch, _position, _dimensions, _orientation, _created, ProceduralProgramKey(outColor.a < 1.0f));
|
||||
procedural->prepare(batch, transform.getTranslation(), transform.getScale(), transform.getRotation(), _created, ProceduralProgramKey(outColor.a < 1.0f));
|
||||
});
|
||||
|
||||
if (render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES) {
|
||||
|
|
|
@ -45,10 +45,6 @@ private:
|
|||
std::shared_ptr<graphics::ProceduralMaterial> _material { std::make_shared<graphics::ProceduralMaterial>() };
|
||||
glm::vec3 _color { NAN };
|
||||
float _alpha { NAN };
|
||||
|
||||
glm::vec3 _position;
|
||||
glm::vec3 _dimensions;
|
||||
glm::quat _orientation;
|
||||
};
|
||||
|
||||
} }
|
||||
|
|
|
@ -109,6 +109,7 @@ void TextEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointe
|
|||
_effect = entity->getTextEffect();
|
||||
_effectColor = toGlm(entity->getTextEffectColor());
|
||||
_effectThickness = entity->getTextEffectThickness();
|
||||
_alignment = entity->getAlignment();
|
||||
updateTextRenderItem();
|
||||
}
|
||||
|
||||
|
@ -292,12 +293,12 @@ void entities::TextPayload::render(RenderArgs* args) {
|
|||
}
|
||||
auto textRenderable = std::static_pointer_cast<TextEntityRenderer>(renderable);
|
||||
|
||||
Transform modelTransform;
|
||||
Transform transform;
|
||||
glm::vec3 dimensions;
|
||||
|
||||
glm::vec4 textColor;
|
||||
textRenderable->withReadLock([&] {
|
||||
modelTransform = textRenderable->_renderTransform;
|
||||
transform = textRenderable->_renderTransform;
|
||||
dimensions = textRenderable->_dimensions;
|
||||
|
||||
float fadeRatio = textRenderable->_isFading ? Interpolate::calculateFadeRatio(textRenderable->_fadeStartTime) : 1.0f;
|
||||
|
@ -313,18 +314,18 @@ void entities::TextPayload::render(RenderArgs* args) {
|
|||
return;
|
||||
}
|
||||
|
||||
modelTransform.setRotation(BillboardModeHelpers::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), textRenderable->_billboardMode,
|
||||
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), textRenderable->_billboardMode,
|
||||
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
|
||||
|
||||
float scale = textRenderable->_lineHeight / textRenderer->getFontSize();
|
||||
modelTransform.postTranslate(glm::vec3(-0.5, 0.5, 1.0f + EPSILON / dimensions.z));
|
||||
modelTransform.setScale(scale);
|
||||
batch.setModelTransform(modelTransform);
|
||||
transform.postTranslate(glm::vec3(-0.5, 0.5, 1.0f + EPSILON / dimensions.z));
|
||||
transform.setScale(scale);
|
||||
batch.setModelTransform(transform);
|
||||
|
||||
glm::vec2 bounds = glm::vec2(dimensions.x - (textRenderable->_leftMargin + textRenderable->_rightMargin), dimensions.y - (textRenderable->_topMargin + textRenderable->_bottomMargin));
|
||||
textRenderer->draw(batch, textRenderable->_leftMargin / scale, -textRenderable->_topMargin / scale, bounds / scale, scale,
|
||||
textRenderable->_text, textRenderable->_font, textColor, effectColor, textRenderable->_effectThickness, textRenderable->_effect,
|
||||
textRenderable->_unlit, forward);
|
||||
textRenderable->_alignment, textRenderable->_unlit, forward);
|
||||
}
|
||||
|
||||
namespace render {
|
||||
|
|
|
@ -65,6 +65,7 @@ private:
|
|||
glm::vec3 _dimensions;
|
||||
|
||||
QString _font { "" };
|
||||
TextAlignment _alignment { TextAlignment::LEFT };
|
||||
TextEffect _effect { TextEffect::NO_EFFECT };
|
||||
glm::vec3 _effectColor { 0 };
|
||||
float _effectThickness { 0.0f };
|
||||
|
|
|
@ -1620,6 +1620,19 @@ const Transform EntityItem::getTransformToCenter(bool& success) const {
|
|||
return result;
|
||||
}
|
||||
|
||||
const Transform EntityItem::getTransformToCenterWithOnlyLocalRotation(bool& success) const {
|
||||
Transform result = getTransformWithOnlyLocalRotation(success);
|
||||
glm::vec3 pivot = getPivot();
|
||||
if (pivot != ENTITY_ITEM_ZERO_VEC3) {
|
||||
result.postTranslate(pivot);
|
||||
}
|
||||
glm::vec3 registrationPoint = getRegistrationPoint();
|
||||
if (registrationPoint != ENTITY_ITEM_HALF_VEC3) { // If it is not already centered, translate to center
|
||||
result.postTranslate((ENTITY_ITEM_HALF_VEC3 - registrationPoint) * getScaledDimensions()); // Position to center
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// The maximum bounding cube for the entity, independent of it's rotation.
|
||||
/// This accounts for the registration point (upon which rotation occurs around).
|
||||
///
|
||||
|
|
|
@ -190,6 +190,7 @@ public:
|
|||
void setCenterPosition(const glm::vec3& position);
|
||||
|
||||
const Transform getTransformToCenter(bool& success) const;
|
||||
const Transform getTransformToCenterWithOnlyLocalRotation(bool& success) const;
|
||||
|
||||
void requiresRecalcBoxes();
|
||||
|
||||
|
|
|
@ -309,7 +309,6 @@ void EntityItemProperties::setScreenshareFromString(const QString& mode) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
inline void addTextEffect(QHash<QString, TextEffect>& lookup, TextEffect effect) { lookup[TextEffectHelpers::getNameForTextEffect(effect)] = effect; }
|
||||
const QHash<QString, TextEffect> stringToTextEffectLookup = [] {
|
||||
QHash<QString, TextEffect> toReturn;
|
||||
|
@ -328,6 +327,23 @@ void EntityItemProperties::setTextEffectFromString(const QString& effect) {
|
|||
}
|
||||
}
|
||||
|
||||
inline void addTextAlignment(QHash<QString, TextAlignment>& lookup, TextAlignment alignment) { lookup[TextAlignmentHelpers::getNameForTextAlignment(alignment)] = alignment; }
|
||||
const QHash<QString, TextAlignment> stringToTextAlignmentLookup = [] {
|
||||
QHash<QString, TextAlignment> toReturn;
|
||||
addTextAlignment(toReturn, TextAlignment::LEFT);
|
||||
addTextAlignment(toReturn, TextAlignment::CENTER);
|
||||
addTextAlignment(toReturn, TextAlignment::RIGHT);
|
||||
return toReturn;
|
||||
}();
|
||||
QString EntityItemProperties::getAlignmentAsString() const { return TextAlignmentHelpers::getNameForTextAlignment(_alignment); }
|
||||
void EntityItemProperties::setAlignmentFromString(const QString& alignment) {
|
||||
auto textAlignmentItr = stringToTextAlignmentLookup.find(alignment.toLower());
|
||||
if (textAlignmentItr != stringToTextAlignmentLookup.end()) {
|
||||
_alignment = textAlignmentItr.value();
|
||||
_alignmentChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
QString getCollisionGroupAsString(uint16_t group) {
|
||||
switch (group) {
|
||||
case USER_COLLISION_GROUP_DYNAMIC:
|
||||
|
@ -564,6 +580,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_TEXT_EFFECT, textEffect);
|
||||
CHECK_PROPERTY_CHANGE(PROP_TEXT_EFFECT_COLOR, textEffectColor);
|
||||
CHECK_PROPERTY_CHANGE(PROP_TEXT_EFFECT_THICKNESS, textEffectThickness);
|
||||
CHECK_PROPERTY_CHANGE(PROP_TEXT_ALIGNMENT, alignment);
|
||||
|
||||
// Zone
|
||||
changedProperties += _keyLight.getChangedProperties();
|
||||
|
@ -1339,6 +1356,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* @property {Entities.TextEffect} textEffect="none" - The effect that is applied to the text.
|
||||
* @property {Color} textEffectColor=255,255,255 - The color of the effect.
|
||||
* @property {number} textEffectThickness=0.2 - The magnitude of the text effect, range <code>0.0</code> – <code>0.5</code>.
|
||||
* @property {Entities.TextAlignment} alignment="left" - How the text is aligned against its background.
|
||||
* @property {boolean} faceCamera - <code>true</code> if <code>billboardMode</code> is <code>"yaw"</code>, <code>false</code>
|
||||
* if it isn't. Setting this property to <code>false</code> sets the <code>billboardMode</code> to <code>"none"</code>.
|
||||
* <p class="important">Deprecated: This property is deprecated and will be removed.</p>
|
||||
|
@ -1791,6 +1809,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_TEXT_EFFECT, textEffect, getTextEffectAsString());
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_TEXT_EFFECT_COLOR, textEffectColor, u8vec3Color);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXT_EFFECT_THICKNESS, textEffectThickness);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_TEXT_ALIGNMENT, alignment, getAlignmentAsString());
|
||||
}
|
||||
|
||||
// Zones only
|
||||
|
@ -2175,6 +2194,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(textEffect, TextEffect);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(textEffectColor, u8vec3Color, setTextEffectColor);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(textEffectThickness, float, setTextEffectThickness);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(alignment, Alignment);
|
||||
|
||||
// Zone
|
||||
_keyLight.copyFromScriptValue(object, _defaultSettings);
|
||||
|
@ -2469,6 +2489,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
|
|||
COPY_PROPERTY_IF_CHANGED(textEffect);
|
||||
COPY_PROPERTY_IF_CHANGED(textEffectColor);
|
||||
COPY_PROPERTY_IF_CHANGED(textEffectThickness);
|
||||
COPY_PROPERTY_IF_CHANGED(alignment);
|
||||
|
||||
// Zone
|
||||
_keyLight.merge(other._keyLight);
|
||||
|
@ -2838,6 +2859,7 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr
|
|||
ADD_PROPERTY_TO_MAP(PROP_TEXT_EFFECT, TextEffect, textEffect, TextEffect);
|
||||
ADD_PROPERTY_TO_MAP(PROP_TEXT_EFFECT_COLOR, TextEffectColor, textEffectColor, u8vec3Color);
|
||||
ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_TEXT_EFFECT_THICKNESS, TextEffectThickness, textEffectThickness, float, 0.0, 0.5);
|
||||
ADD_PROPERTY_TO_MAP(PROP_TEXT_ALIGNMENT, Alignment, alignment, TextAlignment);
|
||||
|
||||
// Zone
|
||||
{ // Keylight
|
||||
|
@ -3280,6 +3302,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
|
|||
APPEND_ENTITY_PROPERTY(PROP_TEXT_EFFECT, (uint32_t)properties.getTextEffect());
|
||||
APPEND_ENTITY_PROPERTY(PROP_TEXT_EFFECT_COLOR, properties.getTextEffectColor());
|
||||
APPEND_ENTITY_PROPERTY(PROP_TEXT_EFFECT_THICKNESS, properties.getTextEffectThickness());
|
||||
APPEND_ENTITY_PROPERTY(PROP_TEXT_ALIGNMENT, (uint32_t)properties.getAlignment());
|
||||
}
|
||||
|
||||
if (properties.getType() == EntityTypes::Zone) {
|
||||
|
@ -3767,6 +3790,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT_EFFECT, TextEffect, setTextEffect);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT_EFFECT_COLOR, u8vec3Color, setTextEffectColor);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT_EFFECT_THICKNESS, float, setTextEffectThickness);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT_ALIGNMENT, TextAlignment, setAlignment);
|
||||
}
|
||||
|
||||
if (properties.getType() == EntityTypes::Zone) {
|
||||
|
@ -4168,6 +4192,7 @@ void EntityItemProperties::markAllChanged() {
|
|||
_textEffectChanged = true;
|
||||
_textEffectColorChanged = true;
|
||||
_textEffectThicknessChanged = true;
|
||||
_alignmentChanged = true;
|
||||
|
||||
// Zone
|
||||
_keyLight.markAllChanged();
|
||||
|
@ -4784,6 +4809,9 @@ QList<QString> EntityItemProperties::listChangedProperties() {
|
|||
if (textEffectThicknessChanged()) {
|
||||
out += "textEffectThickness";
|
||||
}
|
||||
if (alignmentChanged()) {
|
||||
out += "alignment";
|
||||
}
|
||||
|
||||
// Zone
|
||||
getKeyLight().listChangedProperties(out);
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
#include "WebInputMode.h"
|
||||
#include "GizmoType.h"
|
||||
#include "TextEffect.h"
|
||||
#include "TextAlignment.h"
|
||||
|
||||
const quint64 UNKNOWN_CREATED_TIME = 0;
|
||||
|
||||
|
@ -328,6 +329,7 @@ public:
|
|||
DEFINE_PROPERTY_REF_ENUM(PROP_TEXT_EFFECT, TextEffect, textEffect, TextEffect, TextEffect::NO_EFFECT);
|
||||
DEFINE_PROPERTY_REF(PROP_TEXT_EFFECT_COLOR, TextEffectColor, textEffectColor, u8vec3Color, TextEntityItem::DEFAULT_TEXT_COLOR);
|
||||
DEFINE_PROPERTY(PROP_TEXT_EFFECT_THICKNESS, TextEffectThickness, textEffectThickness, float, TextEntityItem::DEFAULT_TEXT_EFFECT_THICKNESS);
|
||||
DEFINE_PROPERTY_REF_ENUM(PROP_TEXT_ALIGNMENT, Alignment, alignment, TextAlignment, TextAlignment::LEFT);
|
||||
|
||||
// Zone
|
||||
DEFINE_PROPERTY_GROUP(KeyLight, keyLight, KeyLightPropertyGroup);
|
||||
|
|
|
@ -253,6 +253,7 @@ enum EntityPropertyList {
|
|||
PROP_TEXT_EFFECT = PROP_DERIVED_12,
|
||||
PROP_TEXT_EFFECT_COLOR = PROP_DERIVED_13,
|
||||
PROP_TEXT_EFFECT_THICKNESS = PROP_DERIVED_14,
|
||||
PROP_TEXT_ALIGNMENT = PROP_DERIVED_15,
|
||||
|
||||
// Zone
|
||||
// Keylight
|
||||
|
|
|
@ -218,8 +218,9 @@ EntityItemID EntityTreeElement::evalDetailedRayIntersection(const glm::vec3& ori
|
|||
// extents is the entity relative, scaled, centered extents of the entity
|
||||
glm::vec3 position = entity->getWorldPosition();
|
||||
glm::mat4 translation = glm::translate(position);
|
||||
glm::quat orientation = entity->getWorldOrientation();
|
||||
glm::mat4 rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(position, orientation, entity->getBillboardMode(),
|
||||
BillboardMode billboardMode = entity->getBillboardMode();
|
||||
glm::quat orientation = billboardMode == BillboardMode::NONE ? entity->getWorldOrientation() : entity->getLocalOrientation();
|
||||
glm::mat4 rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(position, orientation, billboardMode,
|
||||
viewFrustumPos, entity->getRotateForPicking()));
|
||||
glm::mat4 entityToWorldMatrix = translation * rotation;
|
||||
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
|
||||
|
@ -368,8 +369,9 @@ EntityItemID EntityTreeElement::evalDetailedParabolaIntersection(const glm::vec3
|
|||
// extents is the entity relative, scaled, centered extents of the entity
|
||||
glm::vec3 position = entity->getWorldPosition();
|
||||
glm::mat4 translation = glm::translate(position);
|
||||
glm::quat orientation = entity->getWorldOrientation();
|
||||
glm::mat4 rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(position, orientation, entity->getBillboardMode(),
|
||||
BillboardMode billboardMode = entity->getBillboardMode();
|
||||
glm::quat orientation = billboardMode == BillboardMode::NONE ? entity->getWorldOrientation() : entity->getLocalOrientation();
|
||||
glm::mat4 rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(position, orientation, billboardMode,
|
||||
viewFrustumPos, entity->getRotateForPicking()));
|
||||
glm::mat4 entityToWorldMatrix = translation * rotation;
|
||||
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
|
||||
|
|
|
@ -108,10 +108,11 @@ bool GizmoEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
|
|||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
glm::vec2 xyDimensions(dimensions.x, dimensions.z);
|
||||
glm::quat rotation = getWorldOrientation();
|
||||
BillboardMode billboardMode = getBillboardMode();
|
||||
glm::quat rotation = billboardMode == BillboardMode::NONE ? getWorldOrientation() : getLocalOrientation();
|
||||
rotation *= glm::angleAxis(-(float)M_PI_2, Vectors::RIGHT);
|
||||
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
|
||||
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), viewFrustumPos);
|
||||
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, billboardMode, viewFrustumPos);
|
||||
|
||||
if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
|
||||
glm::vec3 hitPosition = origin + (distance * direction);
|
||||
|
@ -143,10 +144,11 @@ bool GizmoEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin,
|
|||
//// Scale the dimensions by the diameter
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
glm::vec2 xyDimensions(dimensions.x, dimensions.z);
|
||||
glm::quat rotation = getWorldOrientation();
|
||||
BillboardMode billboardMode = getBillboardMode();
|
||||
glm::quat rotation = billboardMode == BillboardMode::NONE ? getWorldOrientation() : getLocalOrientation();
|
||||
rotation *= glm::angleAxis(-(float)M_PI_2, Vectors::RIGHT);
|
||||
glm::vec3 position = getWorldPosition();
|
||||
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), viewFrustumPos);
|
||||
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, billboardMode, viewFrustumPos);
|
||||
|
||||
glm::quat inverseRot = glm::inverse(rotation);
|
||||
glm::vec3 localOrigin = inverseRot * (origin - position);
|
||||
|
|
|
@ -330,6 +330,19 @@ const Transform ModelEntityItem::getTransform(bool& success, int depth) const {
|
|||
|
||||
return worldTransform;
|
||||
}
|
||||
|
||||
const Transform ModelEntityItem::getTransformWithOnlyLocalRotation(bool& success, int depth) const {
|
||||
const Transform parentTransform = getParentTransform(success, depth);
|
||||
Transform localTransform = getLocalTransform();
|
||||
localTransform.postScale(getModelScale());
|
||||
|
||||
Transform worldTransform;
|
||||
Transform::mult(worldTransform, parentTransform, localTransform);
|
||||
worldTransform.setRotation(localTransform.getRotation());
|
||||
|
||||
return worldTransform;
|
||||
}
|
||||
|
||||
void ModelEntityItem::setCompoundShapeURL(const QString& url) {
|
||||
withWriteLock([&] {
|
||||
if (_compoundShapeURL.get() != url) {
|
||||
|
|
|
@ -71,6 +71,7 @@ public:
|
|||
virtual void setScaledDimensions(const glm::vec3& value) override;
|
||||
|
||||
virtual const Transform getTransform(bool& success, int depth = 0) const override;
|
||||
virtual const Transform getTransformWithOnlyLocalRotation(bool& success, int depth = 0) const override;
|
||||
virtual const Transform getTransform() const override;
|
||||
|
||||
static const QString DEFAULT_COMPOUND_SHAPE_URL;
|
||||
|
|
|
@ -378,14 +378,15 @@ glm::mat4 PolyVoxEntityItem::localToVoxelMatrix() const {
|
|||
}
|
||||
|
||||
glm::mat4 PolyVoxEntityItem::voxelToWorldMatrix(bool includeBillboard) const {
|
||||
glm::quat orientation = getWorldOrientation();
|
||||
glm::vec3 position = getWorldPosition();
|
||||
glm::mat4 translation = glm::translate(position);
|
||||
glm::mat4 rotation;
|
||||
if (includeBillboard) {
|
||||
rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(position, orientation, getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition()));
|
||||
BillboardMode billboardMode = getBillboardMode();
|
||||
glm::quat orientation = billboardMode == BillboardMode::NONE ? getWorldOrientation() : getLocalOrientation();
|
||||
rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(position, orientation, billboardMode, BillboardModeHelpers::getPrimaryViewFrustumPosition()));
|
||||
} else {
|
||||
rotation = glm::mat4_cast(orientation);
|
||||
rotation = glm::mat4_cast(getWorldOrientation());
|
||||
}
|
||||
return translation * rotation * voxelToLocalMatrix();
|
||||
}
|
||||
|
|
|
@ -277,9 +277,10 @@ bool ShapeEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
|
|||
float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
glm::quat rotation = getWorldOrientation();
|
||||
BillboardMode billboardMode = getBillboardMode();
|
||||
glm::quat rotation = billboardMode == BillboardMode::NONE ? getWorldOrientation() : getLocalOrientation();
|
||||
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
|
||||
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), viewFrustumPos);
|
||||
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, billboardMode, viewFrustumPos);
|
||||
|
||||
// determine the ray in the frame of the entity transformed from a unit sphere
|
||||
glm::mat4 entityToWorldMatrix = glm::translate(position) * glm::mat4_cast(rotation) * glm::scale(dimensions);
|
||||
|
@ -309,9 +310,10 @@ bool ShapeEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin,
|
|||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
glm::quat rotation = getWorldOrientation();
|
||||
BillboardMode billboardMode = getBillboardMode();
|
||||
glm::quat rotation = billboardMode == BillboardMode::NONE ? getWorldOrientation() : getLocalOrientation();
|
||||
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
|
||||
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), viewFrustumPos);
|
||||
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, billboardMode, viewFrustumPos);
|
||||
|
||||
// determine the parabola in the frame of the entity transformed from a unit sphere
|
||||
glm::mat4 entityToWorldMatrix = glm::translate(position) * glm::mat4_cast(rotation) * glm::scale(dimensions);
|
||||
|
|
|
@ -69,6 +69,7 @@ EntityItemProperties TextEntityItem::getProperties(const EntityPropertyFlags& de
|
|||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(textEffect, getTextEffect);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(textEffectColor, getTextEffectColor);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(textEffectThickness, getTextEffectThickness);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alignment, getAlignment);
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
@ -96,7 +97,8 @@ bool TextEntityItem::setSubClassProperties(const EntityItemProperties& propertie
|
|||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(textEffect, setTextEffect);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(textEffectColor, setTextEffectColor);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(textEffectThickness, setTextEffectThickness);
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alignment, setAlignment);
|
||||
|
||||
return somethingChanged;
|
||||
}
|
||||
|
||||
|
@ -131,6 +133,7 @@ int TextEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
|
|||
READ_ENTITY_PROPERTY(PROP_TEXT_EFFECT, TextEffect, setTextEffect);
|
||||
READ_ENTITY_PROPERTY(PROP_TEXT_EFFECT_COLOR, glm::u8vec3, setTextEffectColor);
|
||||
READ_ENTITY_PROPERTY(PROP_TEXT_EFFECT_THICKNESS, float, setTextEffectThickness);
|
||||
READ_ENTITY_PROPERTY(PROP_TEXT_ALIGNMENT, TextAlignment, setAlignment);
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
@ -155,6 +158,7 @@ EntityPropertyFlags TextEntityItem::getEntityProperties(EncodeBitstreamParams& p
|
|||
requestedProperties += PROP_TEXT_EFFECT;
|
||||
requestedProperties += PROP_TEXT_EFFECT_COLOR;
|
||||
requestedProperties += PROP_TEXT_EFFECT_THICKNESS;
|
||||
requestedProperties += PROP_TEXT_ALIGNMENT;
|
||||
|
||||
return requestedProperties;
|
||||
}
|
||||
|
@ -189,6 +193,7 @@ void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
|
|||
APPEND_ENTITY_PROPERTY(PROP_TEXT_EFFECT, (uint32_t)getTextEffect());
|
||||
APPEND_ENTITY_PROPERTY(PROP_TEXT_EFFECT_COLOR, getTextEffectColor());
|
||||
APPEND_ENTITY_PROPERTY(PROP_TEXT_EFFECT_THICKNESS, getTextEffectThickness());
|
||||
APPEND_ENTITY_PROPERTY(PROP_TEXT_ALIGNMENT, (uint32_t)getAlignment());
|
||||
}
|
||||
|
||||
void TextEntityItem::setText(const QString& value) {
|
||||
|
@ -388,8 +393,21 @@ float TextEntityItem::getTextEffectThickness() const {
|
|||
});
|
||||
}
|
||||
|
||||
void TextEntityItem::setAlignment(TextAlignment value) {
|
||||
withWriteLock([&] {
|
||||
_needsRenderUpdate |= _alignment != value;
|
||||
_alignment = value;
|
||||
});
|
||||
}
|
||||
|
||||
TextAlignment TextEntityItem::getAlignment() const {
|
||||
return resultWithReadLock<TextAlignment>([&] {
|
||||
return _alignment;
|
||||
});
|
||||
}
|
||||
|
||||
PulsePropertyGroup TextEntityItem::getPulseProperties() const {
|
||||
return resultWithReadLock<PulsePropertyGroup>([&] {
|
||||
return _pulseProperties;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "EntityItem.h"
|
||||
|
||||
#include "PulsePropertyGroup.h"
|
||||
#include "TextEffect.h"
|
||||
|
||||
class TextEntityItem : public EntityItem {
|
||||
public:
|
||||
|
@ -100,6 +99,9 @@ public:
|
|||
float getTextEffectThickness() const;
|
||||
void setTextEffectThickness(float value);
|
||||
|
||||
TextAlignment getAlignment() const;
|
||||
void setAlignment(TextAlignment value);
|
||||
|
||||
PulsePropertyGroup getPulseProperties() const;
|
||||
|
||||
private:
|
||||
|
@ -117,6 +119,7 @@ private:
|
|||
bool _unlit;
|
||||
|
||||
QString _font;
|
||||
TextAlignment _alignment;
|
||||
TextEffect _effect;
|
||||
glm::u8vec3 _effectColor;
|
||||
float _effectThickness;
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
|
||||
#include "GLTexture.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QtCore/QThread>
|
||||
#include <NumericalConstants.h>
|
||||
#include <ThreadHelpers.h>
|
||||
|
||||
#include "GLBackend.h"
|
||||
|
||||
|
@ -64,7 +66,7 @@ public:
|
|||
protected:
|
||||
class TextureBufferThread : public QThread {
|
||||
public:
|
||||
TextureBufferThread(GLTextureTransferEngineDefault& parent) : _parent(parent) { start(); }
|
||||
TextureBufferThread(GLTextureTransferEngineDefault& parent) : _parent(parent) {}
|
||||
|
||||
protected:
|
||||
void run() override {
|
||||
|
@ -302,6 +304,10 @@ void GLTextureTransferEngineDefault::processTransferQueues() {
|
|||
#if THREADED_TEXTURE_BUFFERING
|
||||
if (!_transferThread) {
|
||||
_transferThread = new TextureBufferThread(*this);
|
||||
QString name = "TextureBufferThread";
|
||||
_transferThread->setObjectName(name);
|
||||
QObject::connect(_transferThread, &QThread::started, [name] { setThreadName(name.toStdString()); });
|
||||
_transferThread->start();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <QFileInfo>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
#include <ThreadHelpers.h>
|
||||
|
||||
#include "AssetResourceRequest.h"
|
||||
#include "FileResourceRequest.h"
|
||||
|
@ -28,12 +29,16 @@
|
|||
#include "NetworkingConstants.h"
|
||||
|
||||
ResourceManager::ResourceManager(bool atpSupportEnabled) : _atpSupportEnabled(atpSupportEnabled) {
|
||||
_thread.setObjectName("Resource Manager Thread");
|
||||
QString name = "Resource Manager Thread";
|
||||
_thread.setObjectName(name);
|
||||
|
||||
if (_atpSupportEnabled) {
|
||||
auto assetClient = DependencyManager::set<AssetClient>();
|
||||
assetClient->moveToThread(&_thread);
|
||||
QObject::connect(&_thread, &QThread::started, assetClient.data(), &AssetClient::initCaching);
|
||||
QObject::connect(&_thread, &QThread::started, assetClient.data(), [assetClient, name] {
|
||||
setThreadName(name.toStdString());
|
||||
assetClient->initCaching();
|
||||
});
|
||||
}
|
||||
|
||||
_thread.start();
|
||||
|
|
|
@ -286,6 +286,7 @@ enum class EntityVersion : PacketVersion {
|
|||
UseOriginalPivot,
|
||||
UserAgent,
|
||||
AllBillboardMode,
|
||||
TextAlignment,
|
||||
|
||||
// Add new versions above here
|
||||
NUM_PACKET_TYPE,
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "Socket.h"
|
||||
#include <Trace.h>
|
||||
#include <Profile.h>
|
||||
#include <ThreadHelpers.h>
|
||||
|
||||
#include "../NetworkLogging.h"
|
||||
|
||||
|
@ -67,24 +68,26 @@ const microseconds SendQueue::MINIMUM_ESTIMATED_TIMEOUT = milliseconds(10);
|
|||
std::unique_ptr<SendQueue> SendQueue::create(Socket* socket, HifiSockAddr destination, SequenceNumber currentSequenceNumber,
|
||||
MessageNumber currentMessageNumber, bool hasReceivedHandshakeACK) {
|
||||
Q_ASSERT_X(socket, "SendQueue::create", "Must be called with a valid Socket*");
|
||||
|
||||
|
||||
auto queue = std::unique_ptr<SendQueue>(new SendQueue(socket, destination, currentSequenceNumber,
|
||||
currentMessageNumber, hasReceivedHandshakeACK));
|
||||
|
||||
// Setup queue private thread
|
||||
QThread* thread = new QThread;
|
||||
thread->setObjectName("Networking: SendQueue " + destination.objectName()); // Name thread for easier debug
|
||||
|
||||
QThread* thread = new QThread();
|
||||
QString name = "Networking: SendQueue " + destination.objectName();
|
||||
thread->setObjectName(name); // Name thread for easier debug
|
||||
|
||||
connect(thread, &QThread::started, [name] { setThreadName(name.toStdString()); });
|
||||
connect(thread, &QThread::started, queue.get(), &SendQueue::run);
|
||||
|
||||
|
||||
connect(queue.get(), &QObject::destroyed, thread, &QThread::quit); // Thread auto cleanup
|
||||
connect(thread, &QThread::finished, thread, &QThread::deleteLater); // Thread auto cleanup
|
||||
|
||||
|
||||
// Move queue to private thread and start it
|
||||
queue->moveToThread(thread);
|
||||
|
||||
|
||||
thread->start();
|
||||
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "PulseMode.h"
|
||||
#include "GizmoType.h"
|
||||
#include "TextEffect.h"
|
||||
#include "TextAlignment.h"
|
||||
|
||||
#include "OctreeConstants.h"
|
||||
#include "OctreeElement.h"
|
||||
|
@ -278,6 +279,7 @@ public:
|
|||
static int unpackDataFromBytes(const unsigned char* dataBytes, PulseMode& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||
static int unpackDataFromBytes(const unsigned char* dataBytes, GizmoType& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||
static int unpackDataFromBytes(const unsigned char* dataBytes, TextEffect& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||
static int unpackDataFromBytes(const unsigned char* dataBytes, TextAlignment& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||
static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec2& result);
|
||||
static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec3& result);
|
||||
static int unpackDataFromBytes(const unsigned char* dataBytes, glm::u8vec3& result);
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "RenderControl.h"
|
||||
#include "RenderEventHandler.h"
|
||||
#include "TextureCache.h"
|
||||
#include <ThreadHelpers.h>
|
||||
|
||||
// Time between receiving a request to render the offscreen UI actually triggering
|
||||
// the render. Could possibly be increased depending on the framerate we expect to
|
||||
|
@ -162,7 +163,9 @@ void SharedObject::setRootItem(QQuickItem* rootItem) {
|
|||
|
||||
// Create the render thread
|
||||
_renderThread = new QThread();
|
||||
_renderThread->setObjectName(objectName());
|
||||
QString name = objectName();
|
||||
_renderThread->setObjectName(name);
|
||||
QObject::connect(_renderThread, &QThread::started, [name] { setThreadName("QML SharedObject " + name.toStdString()); });
|
||||
_renderThread->start();
|
||||
|
||||
// Create event handler for the render thread
|
||||
|
|
|
@ -114,7 +114,8 @@ Transform Model::getTransform() const {
|
|||
return transform;
|
||||
} else if (_spatiallyNestableOverride) {
|
||||
bool success;
|
||||
Transform transform = _spatiallyNestableOverride->getTransform(success);
|
||||
Transform transform = _billboardMode == BillboardMode::NONE ? _spatiallyNestableOverride->getTransform(success) :
|
||||
_spatiallyNestableOverride->getTransformWithOnlyLocalRotation(success);
|
||||
if (success) {
|
||||
transform.setScale(getScale());
|
||||
return transform;
|
||||
|
@ -151,6 +152,7 @@ void Model::setOffset(const glm::vec3& offset) {
|
|||
// if someone manually sets our offset, then we are no longer snapped to center
|
||||
_snapModelToRegistrationPoint = false;
|
||||
_snappedToRegistrationPoint = false;
|
||||
_forceOffset = true;
|
||||
}
|
||||
|
||||
void Model::calculateTextureInfo() {
|
||||
|
|
|
@ -43,18 +43,18 @@ float TextRenderer3D::getFontSize() const {
|
|||
void TextRenderer3D::draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds,
|
||||
const QString& str, const glm::vec4& color, bool unlit, bool forward) {
|
||||
if (_font) {
|
||||
_font->drawString(batch, _drawInfo, str, color, glm::vec3(0.0f), 0, TextEffect::NO_EFFECT, { x, y }, bounds, 1.0f, unlit, forward);
|
||||
_font->drawString(batch, _drawInfo, str, color, glm::vec3(0.0f), 0, TextEffect::NO_EFFECT, TextAlignment::LEFT, { x, y }, bounds, 1.0f, unlit, forward);
|
||||
}
|
||||
}
|
||||
|
||||
void TextRenderer3D::draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds, float scale,
|
||||
const QString& str, const QString& font, const glm::vec4& color, const glm::vec3& effectColor,
|
||||
float effectThickness, TextEffect effect, bool unlit, bool forward) {
|
||||
float effectThickness, TextEffect effect, TextAlignment alignment, bool unlit, bool forward) {
|
||||
if (font != _family) {
|
||||
_family = font;
|
||||
_font = Font::load(_family);
|
||||
}
|
||||
if (_font) {
|
||||
_font->drawString(batch, _drawInfo, str, color, effectColor, effectThickness, effect, { x, y }, bounds, scale, unlit, forward);
|
||||
_font->drawString(batch, _drawInfo, str, color, effectColor, effectThickness, effect, alignment, { x, y }, bounds, scale, unlit, forward);
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "text/Font.h"
|
||||
#include "TextEffect.h"
|
||||
#include "TextAlignment.h"
|
||||
#include "FontFamilies.h"
|
||||
|
||||
class TextRenderer3D {
|
||||
|
@ -30,7 +31,7 @@ public:
|
|||
const QString& str, const glm::vec4& color, bool unlit, bool forward);
|
||||
void draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds, float scale,
|
||||
const QString& str, const QString& font, const glm::vec4& color, const glm::vec3& effectColor,
|
||||
float effectThickness, TextEffect effect, bool unlit, bool forward);
|
||||
float effectThickness, TextEffect effect, TextAlignment alignment, bool unlit, bool forward);
|
||||
|
||||
private:
|
||||
TextRenderer3D(const char* family);
|
||||
|
|
|
@ -65,7 +65,6 @@ struct QuadBuilder {
|
|||
vertices[3] = TextureVertex(min + size,
|
||||
texMin + glm::vec2(texSize.x, 0.0f), bounds);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Font::Pointer Font::load(QIODevice& fontFile) {
|
||||
|
@ -303,7 +302,18 @@ void Font::setupGPU() {
|
|||
}
|
||||
}
|
||||
|
||||
void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm::vec2& origin, const glm::vec2& bounds, float scale, bool enlargeForShadows) {
|
||||
inline QuadBuilder adjustedQuadBuilderForAlignmentMode(const Glyph& glyph, glm::vec2 advance, float scale, float enlargeForShadows,
|
||||
TextAlignment alignment, float rightSpacing) {
|
||||
if (alignment == TextAlignment::RIGHT) {
|
||||
advance.x += rightSpacing;
|
||||
} else if (alignment == TextAlignment::CENTER) {
|
||||
advance.x += 0.5f * rightSpacing;
|
||||
}
|
||||
return QuadBuilder(glyph, advance, scale, enlargeForShadows);
|
||||
}
|
||||
|
||||
void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm::vec2& origin, const glm::vec2& bounds, float scale, bool enlargeForShadows,
|
||||
TextAlignment alignment) {
|
||||
drawInfo.verticesBuffer = std::make_shared<gpu::Buffer>();
|
||||
drawInfo.indicesBuffer = std::make_shared<gpu::Buffer>();
|
||||
drawInfo.indexCount = 0;
|
||||
|
@ -314,15 +324,17 @@ void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm
|
|||
drawInfo.origin = origin;
|
||||
|
||||
float enlargedBoundsX = bounds.x - 0.5f * DOUBLE_MAX_OFFSET_PIXELS * float(enlargeForShadows);
|
||||
float rightEdge = origin.x + enlargedBoundsX;
|
||||
|
||||
// Top left of text
|
||||
glm::vec2 advance = origin;
|
||||
std::vector<std::pair<Glyph, vec2>> glyphsAndCorners;
|
||||
foreach(const QString& token, tokenizeForWrapping(str)) {
|
||||
bool isNewLine = (token == QString('\n'));
|
||||
bool forceNewLine = false;
|
||||
|
||||
// Handle wrapping
|
||||
if (!isNewLine && (bounds.x != -1) && (advance.x + computeExtent(token).x > origin.x + enlargedBoundsX)) {
|
||||
if (!isNewLine && (bounds.x != -1) && (advance.x + computeExtent(token).x > rightEdge)) {
|
||||
// We are out of the x bound, force new line
|
||||
forceNewLine = true;
|
||||
}
|
||||
|
@ -347,38 +359,8 @@ void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm
|
|||
if (!isNewLine) {
|
||||
for (auto c : token) {
|
||||
auto glyph = _glyphs[c];
|
||||
quint16 verticesOffset = numVertices;
|
||||
|
||||
QuadBuilder qd(glyph, advance - glm::vec2(0.0f, _ascent), scale, enlargeForShadows);
|
||||
drawInfo.verticesBuffer->append(qd);
|
||||
numVertices += VERTICES_PER_QUAD;
|
||||
|
||||
// Sam's recommended triangle slices
|
||||
// Triangle tri1 = { v0, v1, v3 };
|
||||
// Triangle tri2 = { v1, v2, v3 };
|
||||
// NOTE: Random guy on the internet's recommended triangle slices
|
||||
// Triangle tri1 = { v0, v1, v2 };
|
||||
// Triangle tri2 = { v2, v3, v0 };
|
||||
|
||||
// The problem here being that the 4 vertices are { ll, lr, ul, ur }, a Z pattern
|
||||
// Additionally, you want to ensure that the shared side vertices are used sequentially
|
||||
// to improve cache locality
|
||||
//
|
||||
// 2 -- 3
|
||||
// | |
|
||||
// | |
|
||||
// 0 -- 1
|
||||
//
|
||||
// { 0, 1, 2 } -> { 2, 1, 3 }
|
||||
quint16 indices[NUMBER_OF_INDICES_PER_QUAD];
|
||||
indices[0] = verticesOffset + 0;
|
||||
indices[1] = verticesOffset + 1;
|
||||
indices[2] = verticesOffset + 2;
|
||||
indices[3] = verticesOffset + 2;
|
||||
indices[4] = verticesOffset + 1;
|
||||
indices[5] = verticesOffset + 3;
|
||||
drawInfo.indicesBuffer->append(sizeof(indices), (const gpu::Byte*)indices);
|
||||
drawInfo.indexCount += NUMBER_OF_INDICES_PER_QUAD;
|
||||
glyphsAndCorners.emplace_back(glyph, advance - glm::vec2(0.0f, _ascent));
|
||||
|
||||
// Advance by glyph size
|
||||
advance.x += glyph.d;
|
||||
|
@ -388,10 +370,71 @@ void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm
|
|||
advance.x += _spaceWidth;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<QuadBuilder> quadBuilders;
|
||||
quadBuilders.reserve(glyphsAndCorners.size());
|
||||
{
|
||||
int i = glyphsAndCorners.size() - 1;
|
||||
while (i >= 0) {
|
||||
auto nextGlyphAndCorner = glyphsAndCorners[i];
|
||||
float rightSpacing = rightEdge - (nextGlyphAndCorner.second.x + nextGlyphAndCorner.first.d);
|
||||
quadBuilders.push_back(adjustedQuadBuilderForAlignmentMode(nextGlyphAndCorner.first, nextGlyphAndCorner.second, scale, enlargeForShadows,
|
||||
alignment, rightSpacing));
|
||||
i--;
|
||||
while (i >= 0) {
|
||||
auto prevGlyphAndCorner = glyphsAndCorners[i];
|
||||
// We're to the right of the last character we checked, which means we're on a previous line, so we need to
|
||||
// recalculate the spacing, so we exit this loop
|
||||
if (prevGlyphAndCorner.second.x >= nextGlyphAndCorner.second.x) {
|
||||
break;
|
||||
}
|
||||
|
||||
quadBuilders.push_back(adjustedQuadBuilderForAlignmentMode(prevGlyphAndCorner.first, prevGlyphAndCorner.second, scale, enlargeForShadows,
|
||||
alignment, rightSpacing));
|
||||
|
||||
nextGlyphAndCorner = prevGlyphAndCorner;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The quadBuilders is backwards now because we looped over the glyphs backwards to adjust their alignment
|
||||
for (int i = quadBuilders.size() - 1; i >= 0; i--) {
|
||||
quint16 verticesOffset = numVertices;
|
||||
drawInfo.verticesBuffer->append(quadBuilders[i]);
|
||||
numVertices += VERTICES_PER_QUAD;
|
||||
|
||||
// Sam's recommended triangle slices
|
||||
// Triangle tri1 = { v0, v1, v3 };
|
||||
// Triangle tri2 = { v1, v2, v3 };
|
||||
// NOTE: Random guy on the internet's recommended triangle slices
|
||||
// Triangle tri1 = { v0, v1, v2 };
|
||||
// Triangle tri2 = { v2, v3, v0 };
|
||||
|
||||
// The problem here being that the 4 vertices are { ll, lr, ul, ur }, a Z pattern
|
||||
// Additionally, you want to ensure that the shared side vertices are used sequentially
|
||||
// to improve cache locality
|
||||
//
|
||||
// 2 -- 3
|
||||
// | |
|
||||
// | |
|
||||
// 0 -- 1
|
||||
//
|
||||
// { 0, 1, 2 } -> { 2, 1, 3 }
|
||||
quint16 indices[NUMBER_OF_INDICES_PER_QUAD];
|
||||
indices[0] = verticesOffset + 0;
|
||||
indices[1] = verticesOffset + 1;
|
||||
indices[2] = verticesOffset + 2;
|
||||
indices[3] = verticesOffset + 2;
|
||||
indices[4] = verticesOffset + 1;
|
||||
indices[5] = verticesOffset + 3;
|
||||
drawInfo.indicesBuffer->append(sizeof(indices), (const gpu::Byte*)indices);
|
||||
drawInfo.indexCount += NUMBER_OF_INDICES_PER_QUAD;
|
||||
}
|
||||
}
|
||||
|
||||
void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const QString& str, const glm::vec4& color,
|
||||
const glm::vec3& effectColor, float effectThickness, TextEffect effect,
|
||||
const glm::vec3& effectColor, float effectThickness, TextEffect effect, TextAlignment alignment,
|
||||
const glm::vec2& origin, const glm::vec2& bounds, float scale, bool unlit, bool forward) {
|
||||
if (!_loaded || str == "") {
|
||||
return;
|
||||
|
@ -401,11 +444,12 @@ void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const QString
|
|||
const int SHADOW_EFFECT = (int)TextEffect::SHADOW_EFFECT;
|
||||
|
||||
// If we're switching to or from shadow effect mode, we need to rebuild the vertices
|
||||
if (str != drawInfo.string || bounds != drawInfo.bounds || origin != drawInfo.origin ||
|
||||
if (str != drawInfo.string || bounds != drawInfo.bounds || origin != drawInfo.origin || alignment != _alignment ||
|
||||
(drawInfo.params.effect != textEffect && (textEffect == SHADOW_EFFECT || drawInfo.params.effect == SHADOW_EFFECT)) ||
|
||||
(textEffect == SHADOW_EFFECT && scale != _scale)) {
|
||||
_scale = scale;
|
||||
buildVertices(drawInfo, str, origin, bounds, scale, textEffect == SHADOW_EFFECT);
|
||||
_alignment = alignment;
|
||||
buildVertices(drawInfo, str, origin, bounds, scale, textEffect == SHADOW_EFFECT, alignment);
|
||||
}
|
||||
|
||||
setupGPU();
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "Glyph.h"
|
||||
#include "TextEffect.h"
|
||||
#include "TextAlignment.h"
|
||||
#include <gpu/Batch.h>
|
||||
#include <gpu/Pipeline.h>
|
||||
|
||||
|
@ -58,7 +59,7 @@ public:
|
|||
|
||||
// Render string to batch
|
||||
void drawString(gpu::Batch& batch, DrawInfo& drawInfo, const QString& str, const glm::vec4& color,
|
||||
const glm::vec3& effectColor, float effectThickness, TextEffect effect,
|
||||
const glm::vec3& effectColor, float effectThickness, TextEffect effect, TextAlignment alignment,
|
||||
const glm::vec2& origin, const glm::vec2& bound, float scale, bool unlit, bool forward);
|
||||
|
||||
static Pointer load(const QString& family);
|
||||
|
@ -76,7 +77,8 @@ private:
|
|||
glm::vec2 computeTokenExtent(const QString& str) const;
|
||||
|
||||
const Glyph& getGlyph(const QChar& c) const;
|
||||
void buildVertices(DrawInfo& drawInfo, const QString& str, const glm::vec2& origin, const glm::vec2& bounds, float scale, bool enlargeForShadows);
|
||||
void buildVertices(DrawInfo& drawInfo, const QString& str, const glm::vec2& origin, const glm::vec2& bounds, float scale, bool enlargeForShadows,
|
||||
TextAlignment alignment);
|
||||
|
||||
void setupGPU();
|
||||
|
||||
|
@ -96,6 +98,7 @@ private:
|
|||
float _spaceWidth { 0.0f };
|
||||
|
||||
float _scale { 0.0f };
|
||||
TextAlignment _alignment;
|
||||
|
||||
bool _loaded { true };
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
#include "SettingHandle.h"
|
||||
#include <AddressManager.h>
|
||||
#include <NetworkingConstants.h>
|
||||
|
||||
#include <ThreadHelpers.h>
|
||||
|
||||
const QString ScriptEngine::_SETTINGS_ENABLE_EXTENDED_EXCEPTIONS {
|
||||
"com.highfidelity.experimental.enableExtendedJSExceptions"
|
||||
|
@ -429,13 +429,17 @@ void ScriptEngine::runInThread() {
|
|||
// 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("js:") + getFilename().replace("about:",""));
|
||||
QString name = QString("js:") + getFilename().replace("about:","");
|
||||
workerThread->setObjectName(name);
|
||||
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
|
||||
connect(workerThread, &QThread::started, this, &ScriptEngine::run);
|
||||
connect(workerThread, &QThread::started, this, [this, name] {
|
||||
setThreadName(name.toStdString());
|
||||
run();
|
||||
});
|
||||
connect(this, &QObject::destroyed, workerThread, &QThread::quit);
|
||||
connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater);
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include <QDebug>
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
#include "ThreadHelpers.h"
|
||||
|
||||
GenericThread::GenericThread() :
|
||||
_stopThread(false),
|
||||
_isThreaded(false) // assume non-threaded, must call initialize()
|
||||
|
@ -36,8 +38,11 @@ void GenericThread::initialize(bool isThreaded, QThread::Priority priority) {
|
|||
// match the thread name to our object name
|
||||
_thread->setObjectName(objectName());
|
||||
|
||||
connect(_thread, &QThread::started, this, &GenericThread::started);
|
||||
connect(_thread, &QThread::started, this, &GenericThread::threadRoutine);
|
||||
connect(_thread, &QThread::started, this, [this] {
|
||||
setThreadName("Generic thread " + objectName().toStdString());
|
||||
started();
|
||||
threadRoutine();
|
||||
});
|
||||
connect(_thread, &QThread::finished, this, &GenericThread::finished);
|
||||
|
||||
moveToThread(_thread);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "SettingManager.h"
|
||||
#include "SharedLogging.h"
|
||||
#include "SharedUtil.h"
|
||||
#include "ThreadHelpers.h"
|
||||
|
||||
namespace Setting {
|
||||
// This should only run as a post-routine in the QCoreApplication destructor
|
||||
|
@ -53,7 +54,10 @@ namespace Setting {
|
|||
thread->setObjectName("Settings Thread");
|
||||
|
||||
// Setup setting periodical save timer
|
||||
QObject::connect(thread, &QThread::started, globalManager.data(), &Manager::startTimer);
|
||||
QObject::connect(thread, &QThread::started, globalManager.data(), [globalManager] {
|
||||
setThreadName("Settings Save Thread");
|
||||
globalManager->startTimer();
|
||||
});
|
||||
QObject::connect(thread, &QThread::finished, globalManager.data(), &Manager::stopTimer);
|
||||
|
||||
// Setup manager threading affinity
|
||||
|
|
|
@ -754,6 +754,17 @@ const Transform SpatiallyNestable::getTransform(bool& success, int depth) const
|
|||
return result;
|
||||
}
|
||||
|
||||
const Transform SpatiallyNestable::getTransformWithOnlyLocalRotation(bool& success, int depth) const {
|
||||
Transform result;
|
||||
// return a world-space transform for this object's location
|
||||
Transform parentTransform = getParentTransform(success, depth);
|
||||
_transformLock.withReadLock([&] {
|
||||
Transform::mult(result, parentTransform, _transform);
|
||||
result.setRotation(_transform.getRotation());
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
const Transform SpatiallyNestable::getTransform() const {
|
||||
bool success;
|
||||
Transform result = getTransform(success);
|
||||
|
|
|
@ -82,6 +82,7 @@ public:
|
|||
|
||||
// world frame
|
||||
virtual const Transform getTransform(bool& success, int depth = 0) const;
|
||||
virtual const Transform getTransformWithOnlyLocalRotation(bool& success, int depth = 0) const;
|
||||
virtual const Transform getTransform() const;
|
||||
virtual void setTransform(const Transform& transform, bool& success);
|
||||
virtual bool setTransform(const Transform& transform);
|
||||
|
|
25
libraries/shared/src/TextAlignment.cpp
Normal file
25
libraries/shared/src/TextAlignment.cpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// Created by HifiExperiments on 2/9/21
|
||||
// Copyright 2021 Vircadia contributors.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "TextAlignment.h"
|
||||
|
||||
const char* textAlignmentNames[] = {
|
||||
"left",
|
||||
"center",
|
||||
"right"
|
||||
};
|
||||
|
||||
static const size_t TEXT_ALIGNMENT_NAMES = (sizeof(textAlignmentNames) / sizeof(textAlignmentNames[0]));
|
||||
|
||||
QString TextAlignmentHelpers::getNameForTextAlignment(TextAlignment alignment) {
|
||||
if (((int)alignment <= 0) || ((int)alignment >= (int)TEXT_ALIGNMENT_NAMES)) {
|
||||
alignment = (TextAlignment)0;
|
||||
}
|
||||
|
||||
return textAlignmentNames[(int)alignment];
|
||||
}
|
40
libraries/shared/src/TextAlignment.h
Normal file
40
libraries/shared/src/TextAlignment.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// Created by HifiExperiments on 2/9/21
|
||||
// Copyright 2021 Vircadia contributors.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_TextAlignment_h
|
||||
#define hifi_TextAlignment_h
|
||||
|
||||
#include "QString"
|
||||
|
||||
/**jsdoc
|
||||
* <p>A {@link Entities.EntityProperties-Text|Text} entity may use one of the following alignments:</p>
|
||||
* <table>
|
||||
* <thead>
|
||||
* <tr><th>Value</th><th>Description</th></tr>
|
||||
* </thead>
|
||||
* <tbody>
|
||||
* <tr><td><code>"left"</code></td><td>Text is aligned to the left side.</td></tr>
|
||||
* <tr><td><code>"center"</code></td><td>Text is centered.</td></tr>
|
||||
* <tr><td><code>"right"</code></td><td>Text is aligned to the right side.</td></tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
* @typedef {string} Entities.TextAlignment
|
||||
*/
|
||||
|
||||
enum class TextAlignment {
|
||||
LEFT = 0,
|
||||
CENTER,
|
||||
RIGHT
|
||||
};
|
||||
|
||||
class TextAlignmentHelpers {
|
||||
public:
|
||||
static QString getNameForTextAlignment(TextAlignment alignment);
|
||||
};
|
||||
|
||||
#endif // hifi_TextAlignment_h
|
|
@ -20,7 +20,7 @@
|
|||
* <tbody>
|
||||
* <tr><td><code>"none"</code></td><td>No effect.</td></tr>
|
||||
* <tr><td><code>"outline"</code></td><td>An outline effect.</td></tr>
|
||||
* <tr><td><code>"outlineFill"</code></td><td>An outline effect, with fill.</td></tr>
|
||||
* <tr><td><code>"outline fill"</code></td><td>An outline effect, with fill.</td></tr>
|
||||
* <tr><td><code>"shadow"</code></td><td>A shadow effect.</td></tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
|
|
|
@ -32,6 +32,8 @@ void withLock(QMutex& lock, F function) {
|
|||
function();
|
||||
}
|
||||
|
||||
void setThreadName(const std::string& name);
|
||||
|
||||
void moveToNewNamedThread(QObject* object, const QString& name,
|
||||
std::function<void(QThread*)> preStartCallback,
|
||||
std::function<void()> startCallback,
|
||||
|
|
|
@ -595,7 +595,7 @@ void TabletProxy::gotoMenuScreen(const QString& submenu) {
|
|||
}
|
||||
|
||||
void TabletProxy::loadQMLOnTopImpl(const QVariant& path, bool localSafeContext) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
qCWarning(uiLogging) << __FUNCTION__ << "may not be called directly by scripts";
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <display-plugins/CompositorHelper.h>
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
#include <gl/OffscreenGLCanvas.h>
|
||||
#include <ThreadHelpers.h>
|
||||
|
||||
#include "OpenVrHelpers.h"
|
||||
|
||||
|
@ -494,6 +495,7 @@ bool OpenVrDisplayPlugin::internalActivate() {
|
|||
_submitCanvas->doneCurrent();
|
||||
});
|
||||
}
|
||||
connect(_submitThread.get(), &QThread::started, [] { setThreadName("OpenVR Submit Thread"); });
|
||||
_submitCanvas->moveToThread(_submitThread.get());
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
#include <plugins/DisplayPlugin.h>
|
||||
#include <ThreadHelpers.h>
|
||||
|
||||
#include <controllers/UserInputMapper.h>
|
||||
#include <plugins/InputConfiguration.h>
|
||||
|
@ -403,6 +404,7 @@ bool ViveControllerManager::activate() {
|
|||
|
||||
if (_viveProEye) {
|
||||
_viveProEyeReadThread = std::make_shared<ViveProEyeReadThread>();
|
||||
connect(_viveProEyeReadThread.get(), &QThread::started, [] { setThreadName("ViveProEyeReadThread"); });
|
||||
_viveProEyeReadThread->start(QThread::HighPriority);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,9 @@
|
|||
"textEffectThickness": {
|
||||
"tooltip": "The magnitude of the text effect."
|
||||
},
|
||||
"textAlignment": {
|
||||
"tooltip": "How the text is aligned within its left and right bounds."
|
||||
},
|
||||
"topMargin": {
|
||||
"tooltip": "The top margin, in meters."
|
||||
},
|
||||
|
|
|
@ -25,9 +25,10 @@
|
|||
</head>
|
||||
<body onload='loaded();' id="entity-list-body">
|
||||
<div id="entity-list-menubar">
|
||||
<input type="button" class="normal" id="selection" value="Select▾" />
|
||||
<input type="button" class="normal" id="actions" value="Edit▾" />
|
||||
<input type="button" class="normal" id="tools" value="Tools▾" />
|
||||
<input type="button" class="entity-list-menutitle" id="actions" value="Edit▾" />
|
||||
<input type="button" class="entity-list-menutitle" id="selection" value="Select▾" />
|
||||
<input type="button" class="entity-list-menutitle" id="transform" value="Transform▾" />
|
||||
<input type="button" class="entity-list-menutitle" id="tools" value="Tools▾" />
|
||||
</div>
|
||||
<div id="entity-list-header">
|
||||
<input type="button" class="glyph" id="refresh" value="F" />
|
||||
|
@ -146,35 +147,22 @@
|
|||
</div>
|
||||
</button>
|
||||
<div class="menu-separator"></div>
|
||||
<button class="menu-button" id="moveEntitySelectionToAvatar" >
|
||||
<button class="menu-button" id="exportSelectedEntities" >
|
||||
<div class = "menu-item">
|
||||
<div class = "menu-item-caption">Move Selected Entities to Avatar</div>
|
||||
<div class = "menu-item-caption">Export Selected Entities</div>
|
||||
<div class = "menu-item-shortcut"></div>
|
||||
</div>
|
||||
</button>
|
||||
<div class="menu-separator"></div>
|
||||
<button class="menu-button" id="rotateAsTheNextClickedSurface" >
|
||||
<button class="menu-button" id="importEntitiesFromFile" >
|
||||
<div class = "menu-item">
|
||||
<div class = "menu-item-caption">Snap To Next Clicked Surface</div>
|
||||
<div class = "menu-item-shortcut">0</div>
|
||||
<div class = "menu-item-caption">Import Entities (.json) From a File</div>
|
||||
<div class = "menu-item-shortcut"></div>
|
||||
</div>
|
||||
</button>
|
||||
<button class="menu-button" id="quickRotate90x" >
|
||||
<button class="menu-button" id="importEntitiesFromUrl" >
|
||||
<div class = "menu-item">
|
||||
<div class = "menu-item-caption">Rotate 90° on X axis</div>
|
||||
<div class = "menu-item-shortcut">7</div>
|
||||
</div>
|
||||
</button>
|
||||
<button class="menu-button" id="quickRotate90y" >
|
||||
<div class = "menu-item">
|
||||
<div class = "menu-item-caption">Rotate 90° on Y axis</div>
|
||||
<div class = "menu-item-shortcut">8</div>
|
||||
</div>
|
||||
</button>
|
||||
<button class="menu-button" id="quickRotate90z" >
|
||||
<div class = "menu-item">
|
||||
<div class = "menu-item-caption">Rotate 90° on Z axis</div>
|
||||
<div class = "menu-item-shortcut">9</div>
|
||||
<div class = "menu-item-caption">Import Entities (.json) From a URL</div>
|
||||
<div class = "menu-item-shortcut"></div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -242,6 +230,40 @@
|
|||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="entity-list-menu" id="transform-menu" >
|
||||
<button class="menu-button" id="moveEntitySelectionToAvatar" >
|
||||
<div class = "menu-item">
|
||||
<div class = "menu-item-caption">Move Selected Entities to Avatar</div>
|
||||
<div class = "menu-item-shortcut"></div>
|
||||
</div>
|
||||
</button>
|
||||
<div class="menu-separator"></div>
|
||||
<button class="menu-button" id="rotateAsTheNextClickedSurface" >
|
||||
<div class = "menu-item">
|
||||
<div class = "menu-item-caption">Snap To Next Clicked Surface</div>
|
||||
<div class = "menu-item-shortcut">0</div>
|
||||
</div>
|
||||
</button>
|
||||
<div class="menu-separator"></div>
|
||||
<button class="menu-button" id="quickRotate90x" >
|
||||
<div class = "menu-item">
|
||||
<div class = "menu-item-caption">Rotate 90° on X axis</div>
|
||||
<div class = "menu-item-shortcut">7</div>
|
||||
</div>
|
||||
</button>
|
||||
<button class="menu-button" id="quickRotate90y" >
|
||||
<div class = "menu-item">
|
||||
<div class = "menu-item-caption">Rotate 90° on Y axis</div>
|
||||
<div class = "menu-item-shortcut">8</div>
|
||||
</div>
|
||||
</button>
|
||||
<button class="menu-button" id="quickRotate90z" >
|
||||
<div class = "menu-item">
|
||||
<div class = "menu-item-caption">Rotate 90° on Z axis</div>
|
||||
<div class = "menu-item-shortcut">9</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="entity-list-menu" id="tools-menu" >
|
||||
<button class="menu-button" id="setCameraFocusToSelection" >
|
||||
<div class = "menu-item">
|
||||
|
@ -261,25 +283,6 @@
|
|||
<div class = "menu-item-caption">Toggle Local/World Mode</div>
|
||||
<div class = "menu-item-shortcut">T</div>
|
||||
</div>
|
||||
</button>
|
||||
<div class="menu-separator"></div>
|
||||
<button class="menu-button" id="exportSelectedEntities" >
|
||||
<div class = "menu-item">
|
||||
<div class = "menu-item-caption">Export Selected Entities</div>
|
||||
<div class = "menu-item-shortcut"></div>
|
||||
</div>
|
||||
</button>
|
||||
<button class="menu-button" id="importEntitiesFromFile" >
|
||||
<div class = "menu-item">
|
||||
<div class = "menu-item-caption">Import Entities (.json) From a File</div>
|
||||
<div class = "menu-item-shortcut"></div>
|
||||
</div>
|
||||
</button>
|
||||
<button class="menu-button" id="importEntitiesFromUrl" >
|
||||
<div class = "menu-item">
|
||||
<div class = "menu-item-caption">Import Entities (.json) From a URL</div>
|
||||
<div class = "menu-item-shortcut"></div>
|
||||
</div>
|
||||
</button>
|
||||
<div class="menu-separator"></div>
|
||||
<button class="menu-button" id="gridActivator" >
|
||||
|
|
|
@ -155,7 +155,15 @@ const COLUMNS = {
|
|||
propertyID: "lastEdited",
|
||||
initialWidth: 0.38,
|
||||
defaultSortOrder: DESCENDING_SORT,
|
||||
},
|
||||
},
|
||||
urlWithPath: {
|
||||
columnHeader: "URL",
|
||||
dropdownLabel: "URL",
|
||||
propertyID: "urlWithPath",
|
||||
initialWidth: 0.54,
|
||||
initiallyShown: false,
|
||||
defaultSortOrder: ASCENDING_SORT,
|
||||
},
|
||||
};
|
||||
|
||||
const FILTER_TYPES = [
|
||||
|
@ -226,9 +234,10 @@ let elEntityTable,
|
|||
elToggleVisible,
|
||||
elActionsMenu,
|
||||
elSelectionMenu,
|
||||
elToolsMenu,
|
||||
elTransformMenu,
|
||||
elToolsMenu,
|
||||
elMenuBackgroundOverlay,
|
||||
elHmdMultiSelect,
|
||||
elHmdMultiSelect,
|
||||
elHmdCopy,
|
||||
elHmdCut,
|
||||
elHmdPaste,
|
||||
|
@ -313,6 +322,7 @@ function loaded() {
|
|||
elHmdMultiSelect = document.getElementById("hmdmultiselect");
|
||||
elActionsMenu = document.getElementById("actions");
|
||||
elSelectionMenu = document.getElementById("selection");
|
||||
elTransformMenu = document.getElementById("transform");
|
||||
elToolsMenu = document.getElementById("tools");
|
||||
elMenuBackgroundOverlay = document.getElementById("menuBackgroundOverlay");
|
||||
elHmdCopy = document.getElementById("hmdcopy");
|
||||
|
@ -395,6 +405,10 @@ function loaded() {
|
|||
document.getElementById("menuBackgroundOverlay").style.display = "block";
|
||||
document.getElementById("selection-menu").style.display = "block";
|
||||
};
|
||||
elTransformMenu.onclick = function() {
|
||||
document.getElementById("menuBackgroundOverlay").style.display = "block";
|
||||
document.getElementById("transform-menu").style.display = "block";
|
||||
};
|
||||
elToolsMenu.onclick = function() {
|
||||
document.getElementById("menuBackgroundOverlay").style.display = "block";
|
||||
document.getElementById("tools-menu").style.display = "block";
|
||||
|
@ -919,7 +933,7 @@ function loaded() {
|
|||
entityIds: selection,
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
function updateEntityData(entityData) {
|
||||
entities = [];
|
||||
entitiesByID = {};
|
||||
|
@ -929,13 +943,14 @@ function loaded() {
|
|||
entityData.forEach(function(entity) {
|
||||
let type = entity.type;
|
||||
let filename = getFilename(entity.url);
|
||||
|
||||
|
||||
let entityData = {
|
||||
id: entity.id,
|
||||
name: entity.name,
|
||||
type: type,
|
||||
url: entity.certificateID === "" ? filename : "<i>" + CERTIFIED_PLACEHOLDER + "</i>",
|
||||
fullUrl: entity.certificateID === "" ? filename : CERTIFIED_PLACEHOLDER,
|
||||
urlWithPath: entity.certificateID === "" ? entity.url : "<i>" + CERTIFIED_PLACEHOLDER + "</i>",
|
||||
locked: entity.locked,
|
||||
visible: entity.visible,
|
||||
certificateID: entity.certificateID,
|
||||
|
@ -975,11 +990,13 @@ function loaded() {
|
|||
let searchFilter = searchTerm === '' || (e.name.toLowerCase().indexOf(searchTerm) > -1 ||
|
||||
e.type.toLowerCase().indexOf(searchTerm) > -1 ||
|
||||
e.fullUrl.toLowerCase().indexOf(searchTerm) > -1 ||
|
||||
(e.urlWithPath.toLowerCase().indexOf(searchTerm) > -1 &&
|
||||
columnsByID["urlWithPath"].elTh.style.visibility === "visible") ||
|
||||
e.id.toLowerCase().indexOf(searchTerm) > -1);
|
||||
return typeFilter && searchFilter;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
PROFILE("sort", function() {
|
||||
let isAscendingSort = currentSortOrder === ASCENDING_SORT;
|
||||
let isDefaultSort = currentSortOrder === COLUMNS[currentSortColumnID].defaultSortOrder;
|
||||
|
@ -1850,6 +1867,7 @@ function loaded() {
|
|||
document.getElementById("menuBackgroundOverlay").style.display = "none";
|
||||
document.getElementById("selection-menu").style.display = "none";
|
||||
document.getElementById("actions-menu").style.display = "none";
|
||||
document.getElementById("transform-menu").style.display = "none";
|
||||
document.getElementById("tools-menu").style.display = "none";
|
||||
}
|
||||
|
||||
|
|
|
@ -239,6 +239,17 @@ const GROUPS = [
|
|||
decimals: 2,
|
||||
propertyID: "textEffectThickness",
|
||||
},
|
||||
{
|
||||
label: "Alignment",
|
||||
type: "dropdown",
|
||||
options: {
|
||||
left: "Left",
|
||||
center: "Center",
|
||||
right: "Right"
|
||||
},
|
||||
propertyID: "textAlignment",
|
||||
propertyName: "alignment", // actual entity property name
|
||||
},
|
||||
{
|
||||
label: "Top Margin",
|
||||
type: "number-draggable",
|
||||
|
|
|
@ -1364,10 +1364,46 @@ div#grid-section, body#entity-list-body {
|
|||
}
|
||||
#entity-list-menubar {
|
||||
margin: 0px -8px 6px -8px;
|
||||
padding: 0px 8px 0px 8px;
|
||||
padding: 0px 9px 0px 9px;
|
||||
border: none;
|
||||
background-color: #000;
|
||||
background: linear-gradient(#343434 20%, #000 100%);
|
||||
background: linear-gradient(#343434 30%, #000 100%);
|
||||
}
|
||||
input[type=button].entity-list-menutitle {
|
||||
font-family: FiraSans-SemiBold;
|
||||
font-size: 15px;
|
||||
text-transform: none;
|
||||
vertical-align: top;
|
||||
height: 28px;
|
||||
min-width: 30px;
|
||||
padding: 0px 8px;
|
||||
margin-right: 6px;
|
||||
border-radius: 5px;
|
||||
border: none;
|
||||
color: #fff;
|
||||
background-color: #000;
|
||||
background: linear-gradient(#343434 30%, #000 100%);
|
||||
cursor: pointer;
|
||||
}
|
||||
input[type=button].entity-list-menutitle:enabled:hover {
|
||||
background: linear-gradient(#000, #000);
|
||||
border: none;
|
||||
}
|
||||
input[type=button].entity-list-menutitle:active {
|
||||
background: linear-gradient(#343434, #343434);
|
||||
}
|
||||
input[type=button].entity-list-menutitle:disabled {
|
||||
color: #252525;
|
||||
background: linear-gradient(#575757 30%, #252525 100%);
|
||||
}
|
||||
input[type=button].entity-list-menutitle[pressed=pressed] {
|
||||
color: #00b4ef;
|
||||
}
|
||||
input[type=button].entity-list-menutitle:focus {
|
||||
outline: none;
|
||||
color: #000000;
|
||||
background: linear-gradient(#c0c0c0, #c0c0c0);
|
||||
border-radius: 5px 5px 0px 0px;
|
||||
}
|
||||
.icon-input-radius input {
|
||||
position: relative;
|
||||
|
|
Loading…
Reference in a new issue