mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:44:02 +02:00
Merge master into 22007-hifiQtBuildv2
This commit is contained in:
commit
c660ddd1af
36 changed files with 1493 additions and 247 deletions
|
@ -22,6 +22,7 @@
|
|||
#include <QtCore/QThread>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QUrlQuery>
|
||||
#include <QSaveFile>
|
||||
|
||||
#include <AccountManager.h>
|
||||
#include <Assignment.h>
|
||||
|
@ -1712,28 +1713,44 @@ void DomainServerSettingsManager::sortPermissions() {
|
|||
}
|
||||
|
||||
void DomainServerSettingsManager::persistToFile() {
|
||||
sortPermissions();
|
||||
|
||||
// make sure we have the dir the settings file is supposed to live in
|
||||
QFileInfo settingsFileInfo(_configMap.getUserConfigFilename());
|
||||
|
||||
if (!settingsFileInfo.dir().exists()) {
|
||||
settingsFileInfo.dir().mkpath(".");
|
||||
}
|
||||
|
||||
QFile settingsFile(_configMap.getUserConfigFilename());
|
||||
|
||||
if (settingsFile.open(QIODevice::WriteOnly)) {
|
||||
// take a read lock so we can grab the config and write it to file
|
||||
QReadLocker locker(&_settingsLock);
|
||||
settingsFile.write(QJsonDocument::fromVariant(_configMap.getConfig()).toJson());
|
||||
} else {
|
||||
qCritical("Could not write to JSON settings file. Unable to persist settings.");
|
||||
|
||||
// failed to write, reload whatever the current config state is
|
||||
// with a write lock since we're about to overwrite the config map
|
||||
QString settingsFilename = _configMap.getUserConfigFilename();
|
||||
QDir settingsDir = QFileInfo(settingsFilename).dir();
|
||||
if (!settingsDir.exists() && !settingsDir.mkpath(".")) {
|
||||
// If the path already exists when the `mkpath` method is
|
||||
// called, it will return true. It will only return false if the
|
||||
// path doesn't exist after the call returns.
|
||||
qCritical("Could not create the settings file parent directory. Unable to persist settings.");
|
||||
QWriteLocker locker(&_settingsLock);
|
||||
_configMap.loadConfig();
|
||||
return;
|
||||
}
|
||||
QSaveFile settingsFile(settingsFilename);
|
||||
if (!settingsFile.open(QIODevice::WriteOnly)) {
|
||||
qCritical("Could not open the JSON settings file. Unable to persist settings.");
|
||||
QWriteLocker locker(&_settingsLock);
|
||||
_configMap.loadConfig();
|
||||
return;
|
||||
}
|
||||
|
||||
sortPermissions();
|
||||
|
||||
QVariantMap conf;
|
||||
{
|
||||
QReadLocker locker(&_settingsLock);
|
||||
conf = _configMap.getConfig();
|
||||
}
|
||||
QByteArray json = QJsonDocument::fromVariant(conf).toJson();
|
||||
if (settingsFile.write(json) == -1) {
|
||||
qCritical("Could not write to JSON settings file. Unable to persist settings.");
|
||||
QWriteLocker locker(&_settingsLock);
|
||||
_configMap.loadConfig();
|
||||
return;
|
||||
}
|
||||
if (!settingsFile.commit()) {
|
||||
qCritical("Could not commit writes to JSON settings file. Unable to persist settings.");
|
||||
QWriteLocker locker(&_settingsLock);
|
||||
_configMap.loadConfig();
|
||||
return; // defend against future code
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -209,7 +209,7 @@ link_hifi_libraries(
|
|||
model-networking model-baker entities avatars trackers
|
||||
audio audio-client animation script-engine physics
|
||||
render-utils entities-renderer avatars-renderer ui qml auto-updater midi
|
||||
controllers plugins image trackers
|
||||
controllers plugins image trackers platform
|
||||
ui-plugins display-plugins input-plugins
|
||||
# Platform specific GL libraries
|
||||
${PLATFORM_GL_BACKEND}
|
||||
|
@ -228,6 +228,7 @@ target_bullet()
|
|||
target_opengl()
|
||||
add_crashpad()
|
||||
target_breakpad()
|
||||
target_json()
|
||||
|
||||
# perform standard include and linking for found externals
|
||||
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
||||
|
|
|
@ -192,7 +192,7 @@
|
|||
#include "scripting/WalletScriptingInterface.h"
|
||||
#include "scripting/TTSScriptingInterface.h"
|
||||
#include "scripting/KeyboardScriptingInterface.h"
|
||||
#include "scripting/RefreshRateScriptingInterface.h"
|
||||
#include "scripting/PerformanceScriptingInterface.h"
|
||||
|
||||
|
||||
|
||||
|
@ -3274,7 +3274,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) {
|
|||
|
||||
surfaceContext->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("RefreshRate", new RefreshRateScriptingInterface());
|
||||
surfaceContext->setContextProperty("Performance", new PerformanceScriptingInterface());
|
||||
_fileDownload = new FileScriptingInterface(engine);
|
||||
surfaceContext->setContextProperty("File", _fileDownload);
|
||||
connect(_fileDownload, &FileScriptingInterface::unzipResult, this, &Application::handleUnzip);
|
||||
|
@ -3424,7 +3424,7 @@ void Application::setupQmlSurface(QQmlContext* surfaceContext, bool setAdditiona
|
|||
|
||||
surfaceContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance());
|
||||
surfaceContext->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance());
|
||||
surfaceContext->setContextProperty("RefreshRate", new RefreshRateScriptingInterface());
|
||||
surfaceContext->setContextProperty("Performance", new PerformanceScriptingInterface());
|
||||
|
||||
surfaceContext->setContextProperty("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
|
||||
surfaceContext->setContextProperty("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
|
||||
|
@ -7392,7 +7392,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
|
|||
scriptEngine->registerGlobalObject("LODManager", DependencyManager::get<LODManager>().data());
|
||||
|
||||
scriptEngine->registerGlobalObject("Keyboard", DependencyManager::get<KeyboardScriptingInterface>().data());
|
||||
scriptEngine->registerGlobalObject("RefreshRate", new RefreshRateScriptingInterface);
|
||||
scriptEngine->registerGlobalObject("Performance", new PerformanceScriptingInterface());
|
||||
|
||||
scriptEngine->registerGlobalObject("Paths", DependencyManager::get<PathUtils>().data());
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//
|
||||
//
|
||||
// Application.h
|
||||
// interface/src
|
||||
//
|
||||
|
@ -48,7 +48,6 @@
|
|||
#include <ThreadSafeValueCache.h>
|
||||
#include <shared/ConicalViewFrustum.h>
|
||||
#include <shared/FileLogger.h>
|
||||
|
||||
#include <RunningMarker.h>
|
||||
|
||||
#include "avatar/MyAvatar.h"
|
||||
|
|
|
@ -351,10 +351,18 @@ float LODManager::getHMDLODTargetFPS() const {
|
|||
}
|
||||
|
||||
float LODManager::getLODTargetFPS() const {
|
||||
auto refreshRateFPS = qApp->getRefreshRateManager().getActiveRefreshRate();
|
||||
auto lodTargetFPS = getDesktopLODTargetFPS();
|
||||
if (qApp->isHMDMode()) {
|
||||
return getHMDLODTargetFPS();
|
||||
lodTargetFPS = getHMDLODTargetFPS();
|
||||
}
|
||||
|
||||
// if RefreshRate is slower than LOD target then it becomes the true LOD target
|
||||
if (lodTargetFPS > refreshRateFPS) {
|
||||
return refreshRateFPS;
|
||||
} else {
|
||||
return lodTargetFPS;
|
||||
}
|
||||
return getDesktopLODTargetFPS();
|
||||
}
|
||||
|
||||
void LODManager::setWorldDetailQuality(float quality) {
|
||||
|
|
|
@ -13,13 +13,8 @@
|
|||
#include "RefreshRateManager.h"
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
|
||||
|
||||
#include <Application.h>
|
||||
|
||||
#include <display-plugins/hmd/HmdDisplayPlugin.h>
|
||||
|
||||
static const int VR_TARGET_RATE = 90;
|
||||
|
||||
static const std::array<std::string, RefreshRateManager::RefreshRateProfile::PROFILE_NUM> REFRESH_RATE_PROFILE_TO_STRING =
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
|
|
40
interface/src/scripting/PerformanceScriptingInterface.cpp
Normal file
40
interface/src/scripting/PerformanceScriptingInterface.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2019/05/14
|
||||
// Copyright 2013-2019 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 "PerformanceScriptingInterface.h"
|
||||
|
||||
#include "../Application.h"
|
||||
|
||||
std::once_flag PerformanceScriptingInterface::registry_flag;
|
||||
|
||||
PerformanceScriptingInterface::PerformanceScriptingInterface() {
|
||||
std::call_once(registry_flag, [] {
|
||||
qmlRegisterType<PerformanceScriptingInterface>("PerformanceEnums", 1, 0, "RefreshRate");
|
||||
});
|
||||
}
|
||||
|
||||
void PerformanceScriptingInterface::setRefreshRateProfile(RefreshRateProfile refreshRateProfile) {
|
||||
qApp->getRefreshRateManager().setRefreshRateProfile((RefreshRateManager::RefreshRateProfile)refreshRateProfile);
|
||||
}
|
||||
|
||||
PerformanceScriptingInterface::RefreshRateProfile PerformanceScriptingInterface::getRefreshRateProfile() const {
|
||||
return (PerformanceScriptingInterface::RefreshRateProfile)qApp->getRefreshRateManager().getRefreshRateProfile();
|
||||
}
|
||||
|
||||
int PerformanceScriptingInterface::getActiveRefreshRate() const {
|
||||
return qApp->getRefreshRateManager().getActiveRefreshRate();
|
||||
}
|
||||
|
||||
RefreshRateManager::UXMode PerformanceScriptingInterface::getUXMode() const {
|
||||
return qApp->getRefreshRateManager().getUXMode();
|
||||
}
|
||||
|
||||
RefreshRateManager::RefreshRateRegime PerformanceScriptingInterface::getRefreshRateRegime() const {
|
||||
return qApp->getRefreshRateManager().getRefreshRateRegime();
|
||||
}
|
48
interface/src/scripting/PerformanceScriptingInterface.h
Normal file
48
interface/src/scripting/PerformanceScriptingInterface.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2019/05/14
|
||||
// Copyright 2013-2019 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
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef hifi_PerformanceScriptingInterface_h
|
||||
#define hifi_PerformanceScriptingInterface_h
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "../RefreshRateManager.h"
|
||||
|
||||
|
||||
class PerformanceScriptingInterface : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
// Must match RefreshRateManager enums
|
||||
enum RefreshRateProfile {
|
||||
ECO = RefreshRateManager::RefreshRateProfile::ECO,
|
||||
INTERACTIVE = RefreshRateManager::RefreshRateProfile::INTERACTIVE,
|
||||
REALTIME = RefreshRateManager::RefreshRateProfile::REALTIME,
|
||||
};
|
||||
Q_ENUM(RefreshRateProfile)
|
||||
|
||||
|
||||
PerformanceScriptingInterface();
|
||||
~PerformanceScriptingInterface() = default;
|
||||
|
||||
public slots:
|
||||
void setRefreshRateProfile(RefreshRateProfile refreshRateProfile);
|
||||
RefreshRateProfile getRefreshRateProfile() const;
|
||||
|
||||
int getActiveRefreshRate() const;
|
||||
RefreshRateManager::UXMode getUXMode() const;
|
||||
RefreshRateManager::RefreshRateRegime getRefreshRateRegime() const;
|
||||
|
||||
|
||||
private:
|
||||
static std::once_flag registry_flag;
|
||||
};
|
||||
|
||||
#endif // header guard
|
|
@ -1,46 +0,0 @@
|
|||
//
|
||||
// RefreshRateScriptingInterface.h
|
||||
// interface/src/scrfipting
|
||||
//
|
||||
// Created by Dante Ruiz on 2019-04-15.
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_RefreshRateScriptingInterface_h
|
||||
#define hifi_RefreshRateScriptingInterface_h
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <Application.h>
|
||||
|
||||
class RefreshRateScriptingInterface : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
RefreshRateScriptingInterface() = default;
|
||||
~RefreshRateScriptingInterface() = default;
|
||||
|
||||
public:
|
||||
Q_INVOKABLE QString getRefreshRateProfile() {
|
||||
RefreshRateManager& refreshRateManager = qApp->getRefreshRateManager();
|
||||
return QString::fromStdString(RefreshRateManager::refreshRateProfileToString(refreshRateManager.getRefreshRateProfile()));
|
||||
}
|
||||
|
||||
Q_INVOKABLE QString getRefreshRateRegime() {
|
||||
RefreshRateManager& refreshRateManager = qApp->getRefreshRateManager();
|
||||
return QString::fromStdString(RefreshRateManager::refreshRateRegimeToString(refreshRateManager.getRefreshRateRegime()));
|
||||
}
|
||||
|
||||
Q_INVOKABLE QString getUXMode() {
|
||||
RefreshRateManager& refreshRateManager = qApp->getRefreshRateManager();
|
||||
return QString::fromStdString(RefreshRateManager::uxModeToString(refreshRateManager.getUXMode()));
|
||||
}
|
||||
|
||||
Q_INVOKABLE int getActiveRefreshRate() {
|
||||
return qApp->getRefreshRateManager().getActiveRefreshRate();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -19,6 +19,7 @@
|
|||
#include <shared/QtHelpers.h>
|
||||
#include <SettingHandle.h>
|
||||
|
||||
#include <plugins/PluginManager.h>
|
||||
#include <display-plugins/CompositorHelper.h>
|
||||
#include <AddressManager.h>
|
||||
#include "AndroidHelper.h"
|
||||
|
@ -414,11 +415,11 @@ QString WindowScriptingInterface::protocolSignature() {
|
|||
}
|
||||
|
||||
int WindowScriptingInterface::getInnerWidth() {
|
||||
return qApp->getWindow()->geometry().width();
|
||||
return qApp->getPrimaryWidget()->geometry().width();
|
||||
}
|
||||
|
||||
int WindowScriptingInterface::getInnerHeight() {
|
||||
return qApp->getWindow()->geometry().height() - qApp->getPrimaryMenu()->geometry().height();
|
||||
return qApp->getPrimaryWidget()->geometry().height();
|
||||
}
|
||||
|
||||
glm::vec2 WindowScriptingInterface::getDeviceSize() const {
|
||||
|
@ -609,3 +610,31 @@ void WindowScriptingInterface::onMessageBoxSelected(int button) {
|
|||
float WindowScriptingInterface::domainLoadingProgress() {
|
||||
return qApp->getOctreePacketProcessor().domainLoadingProgress();
|
||||
}
|
||||
|
||||
int WindowScriptingInterface::getDisplayPluginCount() {
|
||||
return (int)PluginManager::getInstance()->getDisplayPlugins().size();
|
||||
}
|
||||
|
||||
QString WindowScriptingInterface::getDisplayPluginName(int index) {
|
||||
return PluginManager::getInstance()->getDisplayPlugins().at(index)->getName();
|
||||
}
|
||||
|
||||
bool WindowScriptingInterface::isDisplayPluginHmd(int index) {
|
||||
return PluginManager::getInstance()->getDisplayPlugins().at(index)->isHmd();
|
||||
}
|
||||
|
||||
int WindowScriptingInterface::getActiveDisplayPlugin() {
|
||||
auto active = qApp->getActiveDisplayPlugin();
|
||||
auto size = getDisplayPluginCount();
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (PluginManager::getInstance()->getDisplayPlugins().at(i) == active) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void WindowScriptingInterface::setActiveDisplayPlugin(int index) {
|
||||
auto name = PluginManager::getInstance()->getDisplayPlugins().at(index)->getName();
|
||||
qApp->setActiveDisplayPlugin(name);
|
||||
}
|
||||
|
|
|
@ -558,6 +558,44 @@ public slots:
|
|||
*/
|
||||
float domainLoadingProgress();
|
||||
|
||||
/**jsdoc
|
||||
* Return the number of display plugins currently available
|
||||
* @function Window.getDisplayPluginCount
|
||||
* @returns {int} The number of currently available display plugins
|
||||
*/
|
||||
int getDisplayPluginCount();
|
||||
|
||||
/**jsdoc
|
||||
* Return the human readable name of a display plugin
|
||||
* @function Window.getDisplayPluginName
|
||||
* @param {int} index - The index of the display plugin. Must be less than the value returned by {@link Window.getDisplayPluginCount|getDisplayPluginCount}.
|
||||
* @returns {string} The name of the specified display plugin
|
||||
*/
|
||||
QString getDisplayPluginName(int index);
|
||||
|
||||
/**jsdoc
|
||||
* Return whether a given display plugin is an HMD
|
||||
* @function Window.isDisplayPluginHmd
|
||||
* @param {int} index - The index of the display plugin. Must be less than the value returned by {@link Window.getDisplayPluginCount|getDisplayPluginCount}.
|
||||
* @returns {bool} True if the specified display plugin is a HMD
|
||||
*/
|
||||
bool isDisplayPluginHmd(int index);
|
||||
|
||||
/**jsdoc
|
||||
* Return the currently active display plugin
|
||||
* @function Window.getActiveDisplayPlugin
|
||||
* @returns {int} The index of the currently active display plugin
|
||||
*/
|
||||
int getActiveDisplayPlugin();
|
||||
|
||||
/**jsdoc
|
||||
* Return the currently active display plugin
|
||||
* @function Window.setActiveDisplayPlugin
|
||||
* @param {int} index - The index of the display plugin. Must be less than the value returned by {@link Window.getDisplayPluginCount|getDisplayPluginCount}.
|
||||
*/
|
||||
void setActiveDisplayPlugin(int index);
|
||||
|
||||
|
||||
private slots:
|
||||
void onWindowGeometryChanged(const QRect& geometry);
|
||||
void onMessageBoxSelected(int button);
|
||||
|
|
|
@ -86,7 +86,6 @@ void interactiveWindowPointerFromScriptValue(const QScriptValue& object, Interac
|
|||
* provided as {@link Desktop|Desktop.ALWAYS_ON_TOP} and {@link Desktop|Desktop.CLOSE_BUTTON_HIDES}.
|
||||
*/
|
||||
InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap& properties) {
|
||||
bool docked = false;
|
||||
InteractiveWindowPresentationMode presentationMode = InteractiveWindowPresentationMode::Native;
|
||||
|
||||
if (properties.contains(PRESENTATION_MODE_PROPERTY)) {
|
||||
|
@ -146,12 +145,12 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
|
|||
QObject::connect(quickView.get(), &QQuickView::statusChanged, [&, this] (QQuickView::Status status) {
|
||||
if (status == QQuickView::Ready) {
|
||||
QQuickItem* rootItem = _dockWidget->getRootItem();
|
||||
_dockWidget->getQuickView()->rootContext()->setContextProperty(EVENT_BRIDGE_PROPERTY, this);
|
||||
QObject::connect(rootItem, SIGNAL(sendToScript(QVariant)), this, SLOT(qmlToScript(const QVariant&)), Qt::QueuedConnection);
|
||||
}
|
||||
});
|
||||
_dockWidget->setSource(QUrl(sourceUrl));
|
||||
mainWindow->addDockWidget(dockArea, _dockWidget.get());
|
||||
_dockedWindow = docked;
|
||||
} else {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
// Build the event bridge and wrapper on the main thread
|
||||
|
@ -210,10 +209,10 @@ InteractiveWindow::~InteractiveWindow() {
|
|||
|
||||
void InteractiveWindow::sendToQml(const QVariant& message) {
|
||||
// Forward messages received from the script on to QML
|
||||
if (_dockedWindow) {
|
||||
if (_dockWidget) {
|
||||
QQuickItem* rootItem = _dockWidget->getRootItem();
|
||||
if (rootItem) {
|
||||
QMetaObject::invokeMethod(_qmlWindow, "fromScript", Qt::QueuedConnection, Q_ARG(QVariant, message));
|
||||
QMetaObject::invokeMethod(rootItem, "fromScript", Qt::QueuedConnection, Q_ARG(QVariant, message));
|
||||
}
|
||||
} else {
|
||||
QMetaObject::invokeMethod(_qmlWindow, "fromScript", Qt::QueuedConnection, Q_ARG(QVariant, message));
|
||||
|
|
|
@ -288,7 +288,6 @@ protected slots:
|
|||
void qmlToScript(const QVariant& message);
|
||||
|
||||
private:
|
||||
bool _dockedWindow { false };
|
||||
QPointer<QObject> _qmlWindow;
|
||||
std::shared_ptr<DockWidget> _dockWidget { nullptr };
|
||||
};
|
||||
|
|
|
@ -30,7 +30,7 @@ int RefreshRateController::getRefreshRateLimitPeriod() const {
|
|||
return durationNanosecondsToHz(_refreshRateLimitPeriod);
|
||||
}
|
||||
|
||||
void RefreshRateController::sleepThreadIfNeeded(QThread* thread, bool isHmd) {
|
||||
std::chrono::nanoseconds RefreshRateController::sleepThreadIfNeeded(QThread* thread, bool isHmd) {
|
||||
if (!isHmd) {
|
||||
static const std::chrono::nanoseconds EPSILON = std::chrono::milliseconds(1);
|
||||
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(_endTime - _startTime);
|
||||
|
@ -39,5 +39,7 @@ void RefreshRateController::sleepThreadIfNeeded(QThread* thread, bool isHmd) {
|
|||
if (sleepDuration.count() > 0) {
|
||||
thread->msleep(std::chrono::duration_cast<std::chrono::milliseconds>(sleepDuration).count());
|
||||
}
|
||||
return sleepDuration;
|
||||
}
|
||||
return std::chrono::nanoseconds(0);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public:
|
|||
|
||||
void clockStartTime() { _startTime = std::chrono::high_resolution_clock::now(); }
|
||||
void clockEndTime() { _endTime = std::chrono::high_resolution_clock::now(); }
|
||||
void sleepThreadIfNeeded(QThread* thread, bool isHmd);
|
||||
std::chrono::nanoseconds sleepThreadIfNeeded(QThread* thread, bool isHmd);
|
||||
private:
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> _startTime { std::chrono::high_resolution_clock::now() };
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> _endTime { std::chrono::high_resolution_clock::now() };
|
||||
|
|
|
@ -37,6 +37,28 @@
|
|||
|
||||
#include "FBXSerializer.h"
|
||||
|
||||
#define GLTF_GET_INDICIES(accCount) int index1 = (indices[n + 0] * accCount); int index2 = (indices[n + 1] * accCount); int index3 = (indices[n + 2] * accCount);
|
||||
|
||||
#define GLTF_APPEND_ARRAY_1(newArray, oldArray) GLTF_GET_INDICIES(1) \
|
||||
newArray.append(oldArray[index1]); \
|
||||
newArray.append(oldArray[index2]); \
|
||||
newArray.append(oldArray[index3]);
|
||||
|
||||
#define GLTF_APPEND_ARRAY_2(newArray, oldArray) GLTF_GET_INDICIES(2) \
|
||||
newArray.append(oldArray[index1]); newArray.append(oldArray[index1 + 1]); \
|
||||
newArray.append(oldArray[index2]); newArray.append(oldArray[index2 + 1]); \
|
||||
newArray.append(oldArray[index3]); newArray.append(oldArray[index3 + 1]);
|
||||
|
||||
#define GLTF_APPEND_ARRAY_3(newArray, oldArray) GLTF_GET_INDICIES(3) \
|
||||
newArray.append(oldArray[index1]); newArray.append(oldArray[index1 + 1]); newArray.append(oldArray[index1 + 2]); \
|
||||
newArray.append(oldArray[index2]); newArray.append(oldArray[index2 + 1]); newArray.append(oldArray[index2 + 2]); \
|
||||
newArray.append(oldArray[index3]); newArray.append(oldArray[index3 + 1]); newArray.append(oldArray[index3 + 2]);
|
||||
|
||||
#define GLTF_APPEND_ARRAY_4(newArray, oldArray) GLTF_GET_INDICIES(4) \
|
||||
newArray.append(oldArray[index1]); newArray.append(oldArray[index1 + 1]); newArray.append(oldArray[index1 + 2]); newArray.append(oldArray[index1 + 3]); \
|
||||
newArray.append(oldArray[index2]); newArray.append(oldArray[index2 + 1]); newArray.append(oldArray[index2 + 2]); newArray.append(oldArray[index2 + 3]); \
|
||||
newArray.append(oldArray[index3]); newArray.append(oldArray[index3 + 1]); newArray.append(oldArray[index3 + 2]); newArray.append(oldArray[index3 + 3]);
|
||||
|
||||
bool GLTFSerializer::getStringVal(const QJsonObject& object, const QString& fieldname,
|
||||
QString& value, QMap<QString, bool>& defined) {
|
||||
bool _defined = (object.contains(fieldname) && object[fieldname].isString());
|
||||
|
@ -261,6 +283,41 @@ bool GLTFSerializer::setAsset(const QJsonObject& object) {
|
|||
return isAssetDefined;
|
||||
}
|
||||
|
||||
GLTFAccessor::GLTFAccessorSparse::GLTFAccessorSparseIndices GLTFSerializer::createAccessorSparseIndices(const QJsonObject& object) {
|
||||
GLTFAccessor::GLTFAccessorSparse::GLTFAccessorSparseIndices accessorSparseIndices;
|
||||
|
||||
getIntVal(object, "bufferView", accessorSparseIndices.bufferView, accessorSparseIndices.defined);
|
||||
getIntVal(object, "byteOffset", accessorSparseIndices.byteOffset, accessorSparseIndices.defined);
|
||||
getIntVal(object, "componentType", accessorSparseIndices.componentType, accessorSparseIndices.defined);
|
||||
|
||||
return accessorSparseIndices;
|
||||
}
|
||||
|
||||
GLTFAccessor::GLTFAccessorSparse::GLTFAccessorSparseValues GLTFSerializer::createAccessorSparseValues(const QJsonObject& object) {
|
||||
GLTFAccessor::GLTFAccessorSparse::GLTFAccessorSparseValues accessorSparseValues;
|
||||
|
||||
getIntVal(object, "bufferView", accessorSparseValues.bufferView, accessorSparseValues.defined);
|
||||
getIntVal(object, "byteOffset", accessorSparseValues.byteOffset, accessorSparseValues.defined);
|
||||
|
||||
return accessorSparseValues;
|
||||
}
|
||||
|
||||
GLTFAccessor::GLTFAccessorSparse GLTFSerializer::createAccessorSparse(const QJsonObject& object) {
|
||||
GLTFAccessor::GLTFAccessorSparse accessorSparse;
|
||||
|
||||
getIntVal(object, "count", accessorSparse.count, accessorSparse.defined);
|
||||
QJsonObject sparseIndicesObject;
|
||||
if (getObjectVal(object, "indices", sparseIndicesObject, accessorSparse.defined)) {
|
||||
accessorSparse.indices = createAccessorSparseIndices(sparseIndicesObject);
|
||||
}
|
||||
QJsonObject sparseValuesObject;
|
||||
if (getObjectVal(object, "values", sparseValuesObject, accessorSparse.defined)) {
|
||||
accessorSparse.values = createAccessorSparseValues(sparseValuesObject);
|
||||
}
|
||||
|
||||
return accessorSparse;
|
||||
}
|
||||
|
||||
bool GLTFSerializer::addAccessor(const QJsonObject& object) {
|
||||
GLTFAccessor accessor;
|
||||
|
||||
|
@ -273,6 +330,12 @@ bool GLTFSerializer::addAccessor(const QJsonObject& object) {
|
|||
if (getStringVal(object, "type", type, accessor.defined)) {
|
||||
accessor.type = getAccessorType(type);
|
||||
}
|
||||
|
||||
QJsonObject sparseObject;
|
||||
if (getObjectVal(object, "sparse", sparseObject, accessor.defined)) {
|
||||
accessor.sparse = createAccessorSparse(sparseObject);
|
||||
}
|
||||
|
||||
getDoubleArrayVal(object, "max", accessor.max, accessor.defined);
|
||||
getDoubleArrayVal(object, "min", accessor.min, accessor.defined);
|
||||
|
||||
|
@ -749,32 +812,16 @@ glm::mat4 GLTFSerializer::getModelTransform(const GLTFNode& node) {
|
|||
void GLTFSerializer::getSkinInverseBindMatrices(std::vector<std::vector<float>>& inverseBindMatrixValues) {
|
||||
for (auto &skin : _file.skins) {
|
||||
GLTFAccessor& indicesAccessor = _file.accessors[skin.inverseBindMatrices];
|
||||
GLTFBufferView& indicesBufferview = _file.bufferviews[indicesAccessor.bufferView];
|
||||
GLTFBuffer& indicesBuffer = _file.buffers[indicesBufferview.buffer];
|
||||
int accBoffset = indicesAccessor.defined["byteOffset"] ? indicesAccessor.byteOffset : 0;
|
||||
QVector<float> matrices;
|
||||
addArrayOfType(indicesBuffer.blob,
|
||||
indicesBufferview.byteOffset + accBoffset,
|
||||
indicesAccessor.count,
|
||||
matrices,
|
||||
indicesAccessor.type,
|
||||
indicesAccessor.componentType);
|
||||
addArrayFromAccessor(indicesAccessor, matrices);
|
||||
inverseBindMatrixValues.push_back(matrices.toStdVector());
|
||||
}
|
||||
}
|
||||
|
||||
void GLTFSerializer::generateTargetData(int index, float weight, QVector<glm::vec3>& returnVector) {
|
||||
GLTFAccessor& accessor = _file.accessors[index];
|
||||
GLTFBufferView& bufferview = _file.bufferviews[accessor.bufferView];
|
||||
GLTFBuffer& buffer = _file.buffers[bufferview.buffer];
|
||||
int accBoffset = accessor.defined["byteOffset"] ? accessor.byteOffset : 0;
|
||||
QVector<float> storedValues;
|
||||
addArrayOfType(buffer.blob,
|
||||
bufferview.byteOffset + accBoffset,
|
||||
accessor.count,
|
||||
storedValues,
|
||||
accessor.type,
|
||||
accessor.componentType);
|
||||
addArrayFromAccessor(accessor, storedValues);
|
||||
for (int n = 0; n < storedValues.size(); n = n + 3) {
|
||||
returnVector.push_back(glm::vec3(weight * storedValues[n], weight * storedValues[n + 1], weight * storedValues[n + 2]));
|
||||
}
|
||||
|
@ -783,7 +830,7 @@ void GLTFSerializer::generateTargetData(int index, float weight, QVector<glm::ve
|
|||
bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& mapping, const hifi::URL& url) {
|
||||
int numNodes = _file.nodes.size();
|
||||
|
||||
// Build dependencies
|
||||
//Build dependencies
|
||||
QVector<int> parents;
|
||||
QVector<int> sortedNodes;
|
||||
parents.fill(-1, numNodes);
|
||||
|
@ -813,7 +860,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash&
|
|||
nodecount++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// since parent indices must exist in the sorted list before any of their children, sortedNodes might not be initialized in the correct order
|
||||
// therefore we need to re-initialize the order in which nodes will be parsed
|
||||
QVector<bool> hasBeenSorted;
|
||||
|
@ -868,7 +915,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash&
|
|||
joint.translation = extractTranslation(joint.transform);
|
||||
joint.rotation = glmExtractRotation(joint.transform);
|
||||
glm::vec3 scale = extractScale(joint.transform);
|
||||
joint.postTransform = glm::scale(glm::mat4(), scale);
|
||||
joint.postTransform = glm::scale(glm::mat4(), scale);
|
||||
|
||||
joint.name = node.name;
|
||||
joint.isSkeletonJoint = false;
|
||||
|
@ -915,12 +962,18 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash&
|
|||
}
|
||||
|
||||
|
||||
// Build materials
|
||||
//Build materials
|
||||
QVector<QString> materialIDs;
|
||||
QString unknown = "Default";
|
||||
int ukcount = 0;
|
||||
foreach(auto material, _file.materials) {
|
||||
QString mid = (material.defined["name"]) ? material.name : unknown + ukcount++;
|
||||
if (!material.defined["name"]) {
|
||||
QString name = unknown + QString::number(ukcount++);
|
||||
material.name = name;
|
||||
material.defined.insert("name", true);
|
||||
}
|
||||
|
||||
QString mid = material.name;
|
||||
materialIDs.push_back(mid);
|
||||
}
|
||||
|
||||
|
@ -929,6 +982,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash&
|
|||
hfmModel.materials[matid] = HFMMaterial();
|
||||
HFMMaterial& hfmMaterial = hfmModel.materials[matid];
|
||||
hfmMaterial._material = std::make_shared<graphics::Material>();
|
||||
hfmMaterial.name = hfmMaterial.materialID = matid;
|
||||
setHFMMaterial(hfmMaterial, _file.materials[i]);
|
||||
}
|
||||
|
||||
|
@ -939,56 +993,76 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash&
|
|||
auto& node = _file.nodes[nodeIndex];
|
||||
|
||||
if (node.defined["mesh"]) {
|
||||
foreach(auto &primitive, _file.meshes[node.mesh].primitives) {
|
||||
hfmModel.meshes.append(HFMMesh());
|
||||
HFMMesh& mesh = hfmModel.meshes[hfmModel.meshes.size() - 1];
|
||||
if (!hfmModel.hasSkeletonJoints) {
|
||||
|
||||
hfmModel.meshes.append(HFMMesh());
|
||||
HFMMesh& mesh = hfmModel.meshes[hfmModel.meshes.size() - 1];
|
||||
if (!hfmModel.hasSkeletonJoints) {
|
||||
HFMCluster cluster;
|
||||
cluster.jointIndex = nodecount;
|
||||
cluster.inverseBindMatrix = glm::mat4();
|
||||
cluster.inverseBindTransform = Transform(cluster.inverseBindMatrix);
|
||||
mesh.clusters.append(cluster);
|
||||
} else { // skinned model
|
||||
for (int j = 0; j < numNodes; j++) {
|
||||
HFMCluster cluster;
|
||||
cluster.jointIndex = nodecount;
|
||||
cluster.inverseBindMatrix = glm::mat4();
|
||||
cluster.jointIndex = j;
|
||||
cluster.inverseBindMatrix = jointInverseBindTransforms[j];
|
||||
cluster.inverseBindTransform = Transform(cluster.inverseBindMatrix);
|
||||
mesh.clusters.append(cluster);
|
||||
} else { // skinned model
|
||||
for (int j = 0; j < numNodes; j++) {
|
||||
HFMCluster cluster;
|
||||
cluster.jointIndex = j;
|
||||
cluster.inverseBindMatrix = jointInverseBindTransforms[j];
|
||||
cluster.inverseBindTransform = Transform(cluster.inverseBindMatrix);
|
||||
mesh.clusters.append(cluster);
|
||||
}
|
||||
}
|
||||
HFMCluster root;
|
||||
root.jointIndex = 0;
|
||||
root.inverseBindMatrix = jointInverseBindTransforms[root.jointIndex];
|
||||
root.inverseBindTransform = Transform(root.inverseBindMatrix);
|
||||
mesh.clusters.append(root);
|
||||
|
||||
QList<QString> meshAttributes;
|
||||
foreach(auto &primitive, _file.meshes[node.mesh].primitives) {
|
||||
QList<QString> keys = primitive.attributes.values.keys();
|
||||
foreach (auto &key, keys) {
|
||||
if (!meshAttributes.contains(key)) {
|
||||
meshAttributes.push_back(key);
|
||||
}
|
||||
}
|
||||
HFMCluster root;
|
||||
root.jointIndex = 0;
|
||||
root.inverseBindMatrix = jointInverseBindTransforms[root.jointIndex];
|
||||
root.inverseBindTransform = Transform(root.inverseBindMatrix);
|
||||
mesh.clusters.append(root);
|
||||
}
|
||||
|
||||
foreach(auto &primitive, _file.meshes[node.mesh].primitives) {
|
||||
HFMMeshPart part = HFMMeshPart();
|
||||
|
||||
int indicesAccessorIdx = primitive.indices;
|
||||
|
||||
GLTFAccessor& indicesAccessor = _file.accessors[indicesAccessorIdx];
|
||||
GLTFBufferView& indicesBufferview = _file.bufferviews[indicesAccessor.bufferView];
|
||||
GLTFBuffer& indicesBuffer = _file.buffers[indicesBufferview.buffer];
|
||||
|
||||
int indicesAccBoffset = indicesAccessor.defined["byteOffset"] ? indicesAccessor.byteOffset : 0;
|
||||
// Buffers
|
||||
QVector<int> indices;
|
||||
QVector<float> vertices;
|
||||
int verticesStride = 3;
|
||||
QVector<float> normals;
|
||||
int normalStride = 3;
|
||||
QVector<float> tangents;
|
||||
int tangentStride = 4;
|
||||
QVector<float> texcoords;
|
||||
int texCoordStride = 2;
|
||||
QVector<float> texcoords2;
|
||||
int texCoord2Stride = 2;
|
||||
QVector<float> colors;
|
||||
int colorStride = 3;
|
||||
QVector<uint16_t> joints;
|
||||
int jointStride = 4;
|
||||
QVector<float> weights;
|
||||
int weightStride = 4;
|
||||
|
||||
QVector<int> raw_indices;
|
||||
QVector<glm::vec3> raw_vertices;
|
||||
QVector<glm::vec3> raw_normals;
|
||||
|
||||
bool success = addArrayOfType(indicesBuffer.blob,
|
||||
indicesBufferview.byteOffset + indicesAccBoffset,
|
||||
indicesAccessor.count,
|
||||
part.triangleIndices,
|
||||
indicesAccessor.type,
|
||||
indicesAccessor.componentType);
|
||||
bool success = addArrayFromAccessor(indicesAccessor, indices);
|
||||
|
||||
if (!success) {
|
||||
qWarning(modelformat) << "There was a problem reading glTF INDICES data for model " << _url;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Increment the triangle indices by the current mesh vertex count so each mesh part can all reference the same buffers within the mesh
|
||||
int prevMeshVerticesCount = mesh.vertices.count();
|
||||
|
||||
QList<QString> keys = primitive.attributes.values.keys();
|
||||
QVector<uint16_t> clusterJoints;
|
||||
QVector<float> clusterWeights;
|
||||
|
@ -997,147 +1071,391 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash&
|
|||
int accessorIdx = primitive.attributes.values[key];
|
||||
|
||||
GLTFAccessor& accessor = _file.accessors[accessorIdx];
|
||||
GLTFBufferView& bufferview = _file.bufferviews[accessor.bufferView];
|
||||
GLTFBuffer& buffer = _file.buffers[bufferview.buffer];
|
||||
|
||||
int accBoffset = accessor.defined["byteOffset"] ? accessor.byteOffset : 0;
|
||||
if (key == "POSITION") {
|
||||
QVector<float> vertices;
|
||||
success = addArrayOfType(buffer.blob,
|
||||
bufferview.byteOffset + accBoffset,
|
||||
accessor.count, vertices,
|
||||
accessor.type,
|
||||
accessor.componentType);
|
||||
if (accessor.type != GLTFAccessorType::VEC3) {
|
||||
qWarning(modelformat) << "Invalid accessor type on glTF POSITION data for model " << _url;
|
||||
continue;
|
||||
}
|
||||
|
||||
success = addArrayFromAccessor(accessor, vertices);
|
||||
if (!success) {
|
||||
qWarning(modelformat) << "There was a problem reading glTF POSITION data for model " << _url;
|
||||
continue;
|
||||
}
|
||||
for (int n = 0; n < vertices.size(); n = n + 3) {
|
||||
mesh.vertices.push_back(glm::vec3(vertices[n], vertices[n + 1], vertices[n + 2]));
|
||||
}
|
||||
} else if (key == "NORMAL") {
|
||||
QVector<float> normals;
|
||||
success = addArrayOfType(buffer.blob,
|
||||
bufferview.byteOffset + accBoffset,
|
||||
accessor.count,
|
||||
normals,
|
||||
accessor.type,
|
||||
accessor.componentType);
|
||||
if (accessor.type != GLTFAccessorType::VEC3) {
|
||||
qWarning(modelformat) << "Invalid accessor type on glTF NORMAL data for model " << _url;
|
||||
continue;
|
||||
}
|
||||
|
||||
success = addArrayFromAccessor(accessor, normals);
|
||||
if (!success) {
|
||||
qWarning(modelformat) << "There was a problem reading glTF NORMAL data for model " << _url;
|
||||
continue;
|
||||
}
|
||||
for (int n = 0; n < normals.size(); n = n + 3) {
|
||||
mesh.normals.push_back(glm::vec3(normals[n], normals[n + 1], normals[n + 2]));
|
||||
}
|
||||
} else if (key == "COLOR_0") {
|
||||
QVector<float> colors;
|
||||
success = addArrayOfType(buffer.blob,
|
||||
bufferview.byteOffset + accBoffset,
|
||||
accessor.count,
|
||||
colors,
|
||||
accessor.type,
|
||||
accessor.componentType);
|
||||
if (!success) {
|
||||
qWarning(modelformat) << "There was a problem reading glTF COLOR_0 data for model " << _url;
|
||||
} else if (key == "TANGENT") {
|
||||
if (accessor.type == GLTFAccessorType::VEC4) {
|
||||
tangentStride = 4;
|
||||
} else if (accessor.type == GLTFAccessorType::VEC3) {
|
||||
tangentStride = 3;
|
||||
} else {
|
||||
qWarning(modelformat) << "Invalid accessor type on glTF TANGENT data for model " << _url;
|
||||
continue;
|
||||
}
|
||||
int stride = (accessor.type == GLTFAccessorType::VEC4) ? 4 : 3;
|
||||
for (int n = 0; n < colors.size() - 3; n += stride) {
|
||||
mesh.colors.push_back(glm::vec3(colors[n], colors[n + 1], colors[n + 2]));
|
||||
}
|
||||
} else if (key == "TANGENT") {
|
||||
QVector<float> tangents;
|
||||
success = addArrayOfType(buffer.blob,
|
||||
bufferview.byteOffset + accBoffset,
|
||||
accessor.count,
|
||||
tangents,
|
||||
accessor.type,
|
||||
accessor.componentType);
|
||||
|
||||
success = addArrayFromAccessor(accessor, tangents);
|
||||
if (!success) {
|
||||
qWarning(modelformat) << "There was a problem reading glTF TANGENT data for model " << _url;
|
||||
tangentStride = 0;
|
||||
continue;
|
||||
}
|
||||
// tangents can be a vec3 or a vec4 which includes a w component (of -1 or 1)
|
||||
int stride = (accessor.type == GLTFAccessorType::VEC4) ? 4 : 3;
|
||||
for (int n = 0; n < tangents.size() - 3; n += stride) {
|
||||
float tanW = stride == 4 ? tangents[n + 3] : 1;
|
||||
mesh.tangents.push_back(glm::vec3(tanW * tangents[n], tangents[n + 1], tanW * tangents[n + 2]));
|
||||
}
|
||||
} else if (key == "TEXCOORD_0") {
|
||||
QVector<float> texcoords;
|
||||
success = addArrayOfType(buffer.blob,
|
||||
bufferview.byteOffset + accBoffset,
|
||||
accessor.count,
|
||||
texcoords,
|
||||
accessor.type,
|
||||
accessor.componentType);
|
||||
success = addArrayFromAccessor(accessor, texcoords);
|
||||
if (!success) {
|
||||
qWarning(modelformat) << "There was a problem reading glTF TEXCOORD_0 data for model " << _url;
|
||||
continue;
|
||||
}
|
||||
for (int n = 0; n < texcoords.size(); n = n + 2) {
|
||||
mesh.texCoords.push_back(glm::vec2(texcoords[n], texcoords[n + 1]));
|
||||
|
||||
if (accessor.type != GLTFAccessorType::VEC2) {
|
||||
qWarning(modelformat) << "Invalid accessor type on glTF TEXCOORD_0 data for model " << _url;
|
||||
continue;
|
||||
}
|
||||
} else if (key == "TEXCOORD_1") {
|
||||
QVector<float> texcoords;
|
||||
success = addArrayOfType(buffer.blob,
|
||||
bufferview.byteOffset + accBoffset,
|
||||
accessor.count,
|
||||
texcoords,
|
||||
accessor.type,
|
||||
accessor.componentType);
|
||||
success = addArrayFromAccessor(accessor, texcoords2);
|
||||
if (!success) {
|
||||
qWarning(modelformat) << "There was a problem reading glTF TEXCOORD_1 data for model " << _url;
|
||||
continue;
|
||||
}
|
||||
for (int n = 0; n < texcoords.size(); n = n + 2) {
|
||||
mesh.texCoords1.push_back(glm::vec2(texcoords[n], texcoords[n + 1]));
|
||||
|
||||
if (accessor.type != GLTFAccessorType::VEC2) {
|
||||
qWarning(modelformat) << "Invalid accessor type on glTF TEXCOORD_1 data for model " << _url;
|
||||
continue;
|
||||
}
|
||||
} else if (key == "COLOR_0") {
|
||||
if (accessor.type == GLTFAccessorType::VEC4) {
|
||||
colorStride = 4;
|
||||
} else if (accessor.type == GLTFAccessorType::VEC3) {
|
||||
colorStride = 3;
|
||||
} else {
|
||||
qWarning(modelformat) << "Invalid accessor type on glTF COLOR_0 data for model " << _url;
|
||||
continue;
|
||||
}
|
||||
|
||||
success = addArrayFromAccessor(accessor, colors);
|
||||
if (!success) {
|
||||
qWarning(modelformat) << "There was a problem reading glTF COLOR_0 data for model " << _url;
|
||||
continue;
|
||||
}
|
||||
} else if (key == "JOINTS_0") {
|
||||
QVector<uint16_t> joints;
|
||||
success = addArrayOfType(buffer.blob,
|
||||
bufferview.byteOffset + accBoffset,
|
||||
accessor.count,
|
||||
joints,
|
||||
accessor.type,
|
||||
accessor.componentType);
|
||||
if (accessor.type == GLTFAccessorType::VEC4) {
|
||||
jointStride = 4;
|
||||
} else if (accessor.type == GLTFAccessorType::VEC3) {
|
||||
jointStride = 3;
|
||||
} else if (accessor.type == GLTFAccessorType::VEC2) {
|
||||
jointStride = 2;
|
||||
} else if (accessor.type == GLTFAccessorType::SCALAR) {
|
||||
jointStride = 1;
|
||||
} else {
|
||||
qWarning(modelformat) << "Invalid accessor type on glTF JOINTS_0 data for model " << _url;
|
||||
continue;
|
||||
}
|
||||
|
||||
success = addArrayFromAccessor(accessor, joints);
|
||||
if (!success) {
|
||||
qWarning(modelformat) << "There was a problem reading glTF JOINTS_0 data for model " << _url;
|
||||
continue;
|
||||
}
|
||||
for (int n = 0; n < joints.size(); n++) {
|
||||
clusterJoints.push_back(joints[n]);
|
||||
}
|
||||
} else if (key == "WEIGHTS_0") {
|
||||
QVector<float> weights;
|
||||
success = addArrayOfType(buffer.blob,
|
||||
bufferview.byteOffset + accBoffset,
|
||||
accessor.count,
|
||||
weights,
|
||||
accessor.type,
|
||||
accessor.componentType);
|
||||
if (accessor.type == GLTFAccessorType::VEC4) {
|
||||
weightStride = 4;
|
||||
} else if (accessor.type == GLTFAccessorType::VEC3) {
|
||||
weightStride = 3;
|
||||
} else if (accessor.type == GLTFAccessorType::VEC2) {
|
||||
weightStride = 2;
|
||||
} else if (accessor.type == GLTFAccessorType::SCALAR) {
|
||||
weightStride = 1;
|
||||
} else {
|
||||
qWarning(modelformat) << "Invalid accessor type on glTF WEIGHTS_0 data for model " << _url;
|
||||
continue;
|
||||
}
|
||||
|
||||
success = addArrayFromAccessor(accessor, weights);
|
||||
if (!success) {
|
||||
qWarning(modelformat) << "There was a problem reading glTF WEIGHTS_0 data for model " << _url;
|
||||
continue;
|
||||
}
|
||||
for (int n = 0; n < weights.size(); n++) {
|
||||
clusterWeights.push_back(weights[n]);
|
||||
}
|
||||
}
|
||||
|
||||
// Validation stage
|
||||
if (indices.count() == 0) {
|
||||
qWarning(modelformat) << "Missing indices for model " << _url;
|
||||
continue;
|
||||
}
|
||||
if (vertices.count() == 0) {
|
||||
qWarning(modelformat) << "Missing vertices for model " << _url;
|
||||
continue;
|
||||
}
|
||||
|
||||
int partVerticesCount = vertices.size() / 3;
|
||||
|
||||
// generate the normals if they don't exist
|
||||
if (normals.size() == 0) {
|
||||
QVector<int> newIndices;
|
||||
QVector<float> newVertices;
|
||||
QVector<float> newNormals;
|
||||
QVector<float> newTexcoords;
|
||||
QVector<float> newTexcoords2;
|
||||
QVector<float> newColors;
|
||||
QVector<uint16_t> newJoints;
|
||||
QVector<float> newWeights;
|
||||
|
||||
for (int n = 0; n < indices.size(); n = n + 3) {
|
||||
int v1_index = (indices[n + 0] * 3);
|
||||
int v2_index = (indices[n + 1] * 3);
|
||||
int v3_index = (indices[n + 2] * 3);
|
||||
|
||||
glm::vec3 v1 = glm::vec3(vertices[v1_index], vertices[v1_index + 1], vertices[v1_index + 2]);
|
||||
glm::vec3 v2 = glm::vec3(vertices[v2_index], vertices[v2_index + 1], vertices[v2_index + 2]);
|
||||
glm::vec3 v3 = glm::vec3(vertices[v3_index], vertices[v3_index + 1], vertices[v3_index + 2]);
|
||||
|
||||
newVertices.append(v1.x);
|
||||
newVertices.append(v1.y);
|
||||
newVertices.append(v1.z);
|
||||
newVertices.append(v2.x);
|
||||
newVertices.append(v2.y);
|
||||
newVertices.append(v2.z);
|
||||
newVertices.append(v3.x);
|
||||
newVertices.append(v3.y);
|
||||
newVertices.append(v3.z);
|
||||
|
||||
glm::vec3 norm = glm::normalize(glm::cross(v2 - v1, v3 - v1));
|
||||
|
||||
newNormals.append(norm.x);
|
||||
newNormals.append(norm.y);
|
||||
newNormals.append(norm.z);
|
||||
newNormals.append(norm.x);
|
||||
newNormals.append(norm.y);
|
||||
newNormals.append(norm.z);
|
||||
newNormals.append(norm.x);
|
||||
newNormals.append(norm.y);
|
||||
newNormals.append(norm.z);
|
||||
|
||||
if (texcoords.size() == partVerticesCount * texCoordStride) {
|
||||
GLTF_APPEND_ARRAY_2(newTexcoords, texcoords)
|
||||
}
|
||||
|
||||
if (texcoords2.size() == partVerticesCount * texCoord2Stride) {
|
||||
GLTF_APPEND_ARRAY_2(newTexcoords2, texcoords2)
|
||||
}
|
||||
|
||||
if (colors.size() == partVerticesCount * colorStride) {
|
||||
if (colorStride == 4) {
|
||||
GLTF_APPEND_ARRAY_4(newColors, colors)
|
||||
} else {
|
||||
GLTF_APPEND_ARRAY_3(newColors, colors)
|
||||
}
|
||||
}
|
||||
|
||||
if (joints.size() == partVerticesCount * jointStride) {
|
||||
if (jointStride == 4) {
|
||||
GLTF_APPEND_ARRAY_4(newJoints, joints)
|
||||
} else if (jointStride == 3) {
|
||||
GLTF_APPEND_ARRAY_3(newJoints, joints)
|
||||
} else if (jointStride == 2) {
|
||||
GLTF_APPEND_ARRAY_2(newJoints, joints)
|
||||
} else {
|
||||
GLTF_APPEND_ARRAY_1(newJoints, joints)
|
||||
}
|
||||
}
|
||||
|
||||
if (weights.size() == partVerticesCount * weightStride) {
|
||||
if (weightStride == 4) {
|
||||
GLTF_APPEND_ARRAY_4(newWeights, weights)
|
||||
} else if (weightStride == 3) {
|
||||
GLTF_APPEND_ARRAY_3(newWeights, weights)
|
||||
} else if (weightStride == 2) {
|
||||
GLTF_APPEND_ARRAY_2(newWeights, weights)
|
||||
} else {
|
||||
GLTF_APPEND_ARRAY_1(newWeights, weights)
|
||||
}
|
||||
}
|
||||
newIndices.append(n);
|
||||
newIndices.append(n + 1);
|
||||
newIndices.append(n + 2);
|
||||
}
|
||||
|
||||
vertices = newVertices;
|
||||
normals = newNormals;
|
||||
tangents = QVector<float>();
|
||||
texcoords = newTexcoords;
|
||||
texcoords2 = newTexcoords2;
|
||||
colors = newColors;
|
||||
joints = newJoints;
|
||||
weights = newWeights;
|
||||
indices = newIndices;
|
||||
|
||||
partVerticesCount = vertices.size() / 3;
|
||||
}
|
||||
|
||||
QVector<int> validatedIndices;
|
||||
for (int n = 0; n < indices.count(); n++) {
|
||||
if (indices[n] < partVerticesCount) {
|
||||
validatedIndices.push_back(indices[n] + prevMeshVerticesCount);
|
||||
} else {
|
||||
validatedIndices = QVector<int>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (validatedIndices.size() == 0) {
|
||||
qWarning(modelformat) << "Indices out of range for model " << _url;
|
||||
continue;
|
||||
}
|
||||
|
||||
part.triangleIndices.append(validatedIndices);
|
||||
|
||||
for (int n = 0; n < vertices.size(); n = n + verticesStride) {
|
||||
mesh.vertices.push_back(glm::vec3(vertices[n], vertices[n + 1], vertices[n + 2]));
|
||||
}
|
||||
|
||||
for (int n = 0; n < normals.size(); n = n + normalStride) {
|
||||
mesh.normals.push_back(glm::vec3(normals[n], normals[n + 1], normals[n + 2]));
|
||||
}
|
||||
|
||||
// TODO: add correct tangent generation
|
||||
if (tangents.size() == partVerticesCount * tangentStride) {
|
||||
for (int n = 0; n < tangents.size(); n += tangentStride) {
|
||||
float tanW = tangentStride == 4 ? tangents[n + 3] : 1;
|
||||
mesh.tangents.push_back(glm::vec3(tanW * tangents[n], tangents[n + 1], tanW * tangents[n + 2]));
|
||||
}
|
||||
} else {
|
||||
if (meshAttributes.contains("TANGENT")) {
|
||||
for (int i = 0; i < partVerticesCount; i++) {
|
||||
mesh.tangents.push_back(glm::vec3(0.0f, 0.0f, 0.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (texcoords.size() == partVerticesCount * texCoordStride) {
|
||||
for (int n = 0; n < texcoords.size(); n = n + 2) {
|
||||
mesh.texCoords.push_back(glm::vec2(texcoords[n], texcoords[n + 1]));
|
||||
}
|
||||
} else {
|
||||
if (meshAttributes.contains("TEXCOORD_0")) {
|
||||
for (int i = 0; i < partVerticesCount; i++) {
|
||||
mesh.texCoords.push_back(glm::vec2(0.0f, 0.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (texcoords2.size() == partVerticesCount * texCoord2Stride) {
|
||||
for (int n = 0; n < texcoords2.size(); n = n + 2) {
|
||||
mesh.texCoords1.push_back(glm::vec2(texcoords2[n], texcoords2[n + 1]));
|
||||
}
|
||||
} else {
|
||||
if (meshAttributes.contains("TEXCOORD_1")) {
|
||||
for (int i = 0; i < partVerticesCount; i++) {
|
||||
mesh.texCoords1.push_back(glm::vec2(0.0f, 0.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (colors.size() == partVerticesCount * colorStride) {
|
||||
for (int n = 0; n < colors.size(); n += colorStride) {
|
||||
mesh.colors.push_back(glm::vec3(colors[n], colors[n + 1], colors[n + 2]));
|
||||
}
|
||||
} else {
|
||||
if (meshAttributes.contains("COLOR_0")) {
|
||||
for (int i = 0; i < partVerticesCount; i++) {
|
||||
mesh.colors.push_back(glm::vec3(1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (joints.size() == partVerticesCount * jointStride) {
|
||||
for (int n = 0; n < joints.size(); n += jointStride) {
|
||||
clusterJoints.push_back(joints[n]);
|
||||
if (jointStride > 1) {
|
||||
clusterJoints.push_back(joints[n + 1]);
|
||||
if (jointStride > 2) {
|
||||
clusterJoints.push_back(joints[n + 2]);
|
||||
if (jointStride > 3) {
|
||||
clusterJoints.push_back(joints[n + 3]);
|
||||
} else {
|
||||
clusterJoints.push_back(0);
|
||||
}
|
||||
} else {
|
||||
clusterJoints.push_back(0);
|
||||
clusterJoints.push_back(0);
|
||||
}
|
||||
} else {
|
||||
clusterJoints.push_back(0);
|
||||
clusterJoints.push_back(0);
|
||||
clusterJoints.push_back(0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (meshAttributes.contains("JOINTS_0")) {
|
||||
for (int i = 0; i < partVerticesCount; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
clusterJoints.push_back(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (weights.size() == partVerticesCount * weightStride) {
|
||||
for (int n = 0; n < weights.size(); n += weightStride) {
|
||||
clusterWeights.push_back(weights[n]);
|
||||
if (weightStride > 1) {
|
||||
clusterWeights.push_back(weights[n + 1]);
|
||||
if (weightStride > 2) {
|
||||
clusterWeights.push_back(weights[n + 2]);
|
||||
if (weightStride > 3) {
|
||||
clusterWeights.push_back(weights[n + 3]);
|
||||
} else {
|
||||
clusterWeights.push_back(0.0f);
|
||||
}
|
||||
} else {
|
||||
clusterWeights.push_back(0.0f);
|
||||
clusterWeights.push_back(0.0f);
|
||||
}
|
||||
} else {
|
||||
clusterWeights.push_back(0.0f);
|
||||
clusterWeights.push_back(0.0f);
|
||||
clusterWeights.push_back(0.0f);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (meshAttributes.contains("WEIGHTS_0")) {
|
||||
for (int i = 0; i < partVerticesCount; i++) {
|
||||
clusterWeights.push_back(1.0f);
|
||||
for (int j = 1; j < 4; j++) {
|
||||
clusterWeights.push_back(0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build weights (adapted from FBXSerializer.cpp)
|
||||
if (hfmModel.hasSkeletonJoints) {
|
||||
int numClusterIndices = clusterJoints.size();
|
||||
int prevMeshClusterIndexCount = mesh.clusterIndices.count();
|
||||
int prevMeshClusterWeightCount = mesh.clusterWeights.count();
|
||||
const int WEIGHTS_PER_VERTEX = 4;
|
||||
const float ALMOST_HALF = 0.499f;
|
||||
int numVertices = mesh.vertices.size();
|
||||
mesh.clusterIndices.fill(mesh.clusters.size() - 1, numClusterIndices);
|
||||
mesh.clusterWeights.fill(0, numClusterIndices);
|
||||
int numVertices = mesh.vertices.size() - prevMeshVerticesCount;
|
||||
|
||||
// Append new cluster indices and weights for this mesh part
|
||||
for (int i = 0; i < numVertices * WEIGHTS_PER_VERTEX; i++) {
|
||||
mesh.clusterIndices.push_back(mesh.clusters.size() - 1);
|
||||
mesh.clusterWeights.push_back(0);
|
||||
}
|
||||
|
||||
for (int c = 0; c < clusterJoints.size(); c++) {
|
||||
mesh.clusterIndices[c] = originalToNewNodeIndexMap[_file.skins[node.skin].joints[clusterJoints[c]]];
|
||||
mesh.clusterIndices[prevMeshClusterIndexCount + c] =
|
||||
originalToNewNodeIndexMap[_file.skins[node.skin].joints[clusterJoints[c]]];
|
||||
}
|
||||
|
||||
// normalize and compress to 16-bits
|
||||
|
@ -1151,10 +1469,10 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash&
|
|||
if (totalWeight > 0.0f) {
|
||||
float weightScalingFactor = (float)(UINT16_MAX) / totalWeight;
|
||||
for (int k = j; k < j + WEIGHTS_PER_VERTEX; ++k) {
|
||||
mesh.clusterWeights[k] = (uint16_t)(weightScalingFactor * clusterWeights[k] + ALMOST_HALF);
|
||||
mesh.clusterWeights[prevMeshClusterWeightCount + k] = (uint16_t)(weightScalingFactor * clusterWeights[k] + ALMOST_HALF);
|
||||
}
|
||||
} else {
|
||||
mesh.clusterWeights[j] = (uint16_t)((float)(UINT16_MAX) + ALMOST_HALF);
|
||||
mesh.clusterWeights[prevMeshClusterWeightCount + j] = (uint16_t)((float)(UINT16_MAX) + ALMOST_HALF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1259,6 +1577,20 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash&
|
|||
|
||||
mesh.meshIndex = hfmModel.meshes.size();
|
||||
}
|
||||
|
||||
mesh.meshExtents.reset();
|
||||
foreach(const glm::vec3& vertex, mesh.vertices) {
|
||||
mesh.meshExtents.addPoint(vertex);
|
||||
hfmModel.meshExtents.addPoint(vertex);
|
||||
}
|
||||
|
||||
// Add epsilon to mesh extents to compensate for planar meshes
|
||||
mesh.meshExtents.minimum -= glm::vec3(EPSILON, EPSILON, EPSILON);
|
||||
mesh.meshExtents.maximum += glm::vec3(EPSILON, EPSILON, EPSILON);
|
||||
hfmModel.meshExtents.minimum -= glm::vec3(EPSILON, EPSILON, EPSILON);
|
||||
hfmModel.meshExtents.maximum += glm::vec3(EPSILON, EPSILON, EPSILON);
|
||||
|
||||
mesh.meshIndex = hfmModel.meshes.size();
|
||||
}
|
||||
nodecount++;
|
||||
}
|
||||
|
@ -1412,10 +1744,6 @@ HFMTexture GLTFSerializer::getHFMTexture(const GLTFTexture& texture) {
|
|||
void GLTFSerializer::setHFMMaterial(HFMMaterial& fbxmat, const GLTFMaterial& material) {
|
||||
|
||||
|
||||
if (material.defined["name"]) {
|
||||
fbxmat.name = fbxmat.materialID = material.name;
|
||||
}
|
||||
|
||||
if (material.defined["emissiveFactor"] && material.emissiveFactor.size() == 3) {
|
||||
glm::vec3 emissive = glm::vec3(material.emissiveFactor[0],
|
||||
material.emissiveFactor[1],
|
||||
|
@ -1552,7 +1880,74 @@ bool GLTFSerializer::addArrayOfType(const hifi::ByteArray& bin, int byteOffset,
|
|||
return false;
|
||||
}
|
||||
|
||||
void GLTFSerializer::retriangulate(const QVector<int>& inIndices, const QVector<glm::vec3>& in_vertices,
|
||||
template <typename T>
|
||||
bool GLTFSerializer::addArrayFromAccessor(GLTFAccessor& accessor, QVector<T>& outarray) {
|
||||
bool success = true;
|
||||
|
||||
if (accessor.defined["bufferView"]) {
|
||||
GLTFBufferView& bufferview = _file.bufferviews[accessor.bufferView];
|
||||
GLTFBuffer& buffer = _file.buffers[bufferview.buffer];
|
||||
|
||||
int accBoffset = accessor.defined["byteOffset"] ? accessor.byteOffset : 0;
|
||||
|
||||
success = addArrayOfType(buffer.blob, bufferview.byteOffset + accBoffset, accessor.count, outarray, accessor.type,
|
||||
accessor.componentType);
|
||||
} else {
|
||||
for (int i = 0; i < accessor.count; i++) {
|
||||
T value;
|
||||
memset(&value, 0, sizeof(T)); // Make sure the dummy array is initalised to zero.
|
||||
outarray.push_back(value);
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
if (accessor.defined["sparse"]) {
|
||||
QVector<int> out_sparse_indices_array;
|
||||
|
||||
GLTFBufferView& sparseIndicesBufferview = _file.bufferviews[accessor.sparse.indices.bufferView];
|
||||
GLTFBuffer& sparseIndicesBuffer = _file.buffers[sparseIndicesBufferview.buffer];
|
||||
|
||||
int accSIBoffset = accessor.sparse.indices.defined["byteOffset"] ? accessor.sparse.indices.byteOffset : 0;
|
||||
|
||||
success = addArrayOfType(sparseIndicesBuffer.blob, sparseIndicesBufferview.byteOffset + accSIBoffset,
|
||||
accessor.sparse.count, out_sparse_indices_array, GLTFAccessorType::SCALAR,
|
||||
accessor.sparse.indices.componentType);
|
||||
if (success) {
|
||||
QVector<T> out_sparse_values_array;
|
||||
|
||||
GLTFBufferView& sparseValuesBufferview = _file.bufferviews[accessor.sparse.values.bufferView];
|
||||
GLTFBuffer& sparseValuesBuffer = _file.buffers[sparseValuesBufferview.buffer];
|
||||
|
||||
int accSVBoffset = accessor.sparse.values.defined["byteOffset"] ? accessor.sparse.values.byteOffset : 0;
|
||||
|
||||
success = addArrayOfType(sparseValuesBuffer.blob, sparseValuesBufferview.byteOffset + accSVBoffset,
|
||||
accessor.sparse.count, out_sparse_values_array, accessor.type, accessor.componentType);
|
||||
|
||||
if (success) {
|
||||
for (int i = 0; i < accessor.sparse.count; i++) {
|
||||
if ((i * 3) + 2 < out_sparse_values_array.size()) {
|
||||
if ((out_sparse_indices_array[i] * 3) + 2 < outarray.length()) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
outarray[(out_sparse_indices_array[i] * 3) + j] = out_sparse_values_array[(i * 3) + j];
|
||||
}
|
||||
} else {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void GLTFSerializer::retriangulate(const QVector<int>& inIndices, const QVector<glm::vec3>& in_vertices,
|
||||
const QVector<glm::vec3>& in_normals, QVector<int>& outIndices,
|
||||
QVector<glm::vec3>& out_vertices, QVector<glm::vec3>& out_normals) {
|
||||
for (int i = 0; i < inIndices.size(); i = i + 3) {
|
||||
|
@ -1717,7 +2112,7 @@ void GLTFSerializer::hfmDebugDump(const HFMModel& hfmModel) {
|
|||
|
||||
qCDebug(modelformat) << "---------------- Joints ----------------";
|
||||
|
||||
foreach(HFMJoint joint, hfmModel.joints) {
|
||||
foreach (HFMJoint joint, hfmModel.joints) {
|
||||
qCDebug(modelformat) << "\n";
|
||||
qCDebug(modelformat) << " shapeInfo.avgPoint =" << joint.shapeInfo.avgPoint;
|
||||
qCDebug(modelformat) << " shapeInfo.debugLines =" << joint.shapeInfo.debugLines;
|
||||
|
|
|
@ -481,6 +481,49 @@ namespace GLTFAccessorComponentType {
|
|||
};
|
||||
}
|
||||
struct GLTFAccessor {
|
||||
struct GLTFAccessorSparse {
|
||||
struct GLTFAccessorSparseIndices {
|
||||
int bufferView;
|
||||
int byteOffset{ 0 };
|
||||
int componentType;
|
||||
|
||||
QMap<QString, bool> defined;
|
||||
void dump() {
|
||||
if (defined["bufferView"]) {
|
||||
qCDebug(modelformat) << "bufferView: " << bufferView;
|
||||
}
|
||||
if (defined["byteOffset"]) {
|
||||
qCDebug(modelformat) << "byteOffset: " << byteOffset;
|
||||
}
|
||||
if (defined["componentType"]) {
|
||||
qCDebug(modelformat) << "componentType: " << componentType;
|
||||
}
|
||||
}
|
||||
};
|
||||
struct GLTFAccessorSparseValues {
|
||||
int bufferView;
|
||||
int byteOffset{ 0 };
|
||||
|
||||
QMap<QString, bool> defined;
|
||||
void dump() {
|
||||
if (defined["bufferView"]) {
|
||||
qCDebug(modelformat) << "bufferView: " << bufferView;
|
||||
}
|
||||
if (defined["byteOffset"]) {
|
||||
qCDebug(modelformat) << "byteOffset: " << byteOffset;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int count;
|
||||
GLTFAccessorSparseIndices indices;
|
||||
GLTFAccessorSparseValues values;
|
||||
|
||||
QMap<QString, bool> defined;
|
||||
void dump() {
|
||||
|
||||
}
|
||||
};
|
||||
int bufferView;
|
||||
int byteOffset { 0 };
|
||||
int componentType; //required
|
||||
|
@ -489,6 +532,7 @@ struct GLTFAccessor {
|
|||
bool normalized{ false };
|
||||
QVector<double> max;
|
||||
QVector<double> min;
|
||||
GLTFAccessorSparse sparse;
|
||||
QMap<QString, bool> defined;
|
||||
void dump() {
|
||||
if (defined["bufferView"]) {
|
||||
|
@ -521,6 +565,10 @@ struct GLTFAccessor {
|
|||
qCDebug(modelformat) << m;
|
||||
}
|
||||
}
|
||||
if (defined["sparse"]) {
|
||||
qCDebug(modelformat) << "sparse: ";
|
||||
sparse.dump();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -763,6 +811,11 @@ private:
|
|||
int& outidx, QMap<QString, bool>& defined);
|
||||
|
||||
bool setAsset(const QJsonObject& object);
|
||||
|
||||
GLTFAccessor::GLTFAccessorSparse::GLTFAccessorSparseIndices createAccessorSparseIndices(const QJsonObject& object);
|
||||
GLTFAccessor::GLTFAccessorSparse::GLTFAccessorSparseValues createAccessorSparseValues(const QJsonObject& object);
|
||||
GLTFAccessor::GLTFAccessorSparse createAccessorSparse(const QJsonObject& object);
|
||||
|
||||
bool addAccessor(const QJsonObject& object);
|
||||
bool addAnimation(const QJsonObject& object);
|
||||
bool addBufferView(const QJsonObject& object);
|
||||
|
@ -782,11 +835,14 @@ private:
|
|||
template<typename T, typename L>
|
||||
bool readArray(const hifi::ByteArray& bin, int byteOffset, int count,
|
||||
QVector<L>& outarray, int accessorType);
|
||||
|
||||
|
||||
template<typename T>
|
||||
bool addArrayOfType(const hifi::ByteArray& bin, int byteOffset, int count,
|
||||
QVector<T>& outarray, int accessorType, int componentType);
|
||||
|
||||
template <typename T>
|
||||
bool addArrayFromAccessor(GLTFAccessor& accessor, QVector<T>& outarray);
|
||||
|
||||
void retriangulate(const QVector<int>& in_indices, const QVector<glm::vec3>& in_vertices,
|
||||
const QVector<glm::vec3>& in_normals, QVector<int>& out_indices,
|
||||
QVector<glm::vec3>& out_vertices, QVector<glm::vec3>& out_normals);
|
||||
|
|
5
libraries/platform/CMakeLists.txt
Normal file
5
libraries/platform/CMakeLists.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
set(TARGET_NAME platform)
|
||||
setup_hifi_library()
|
||||
|
||||
link_hifi_libraries(shared)
|
||||
target_json()
|
40
libraries/platform/src/AndroidPlatform.cpp
Normal file
40
libraries/platform/src/AndroidPlatform.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// Created by Amer Cerkic 05/02/2019
|
||||
// Copyright 2019 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 "AndroidPlatform.h"
|
||||
#include "platformJsonKeys.h"
|
||||
|
||||
#include <GPUIdent.h>
|
||||
#include <string>
|
||||
using namespace platform;
|
||||
|
||||
void AndroidInstance::enumerateCpu() {
|
||||
json cpu;
|
||||
cpu["cpuBrand"] = "";
|
||||
cpu["cpuModel"] = "";
|
||||
cpu["cpuClockSpeed"] = "";
|
||||
cpu["cpuNumCores"] = "";
|
||||
_cpu.push_back(cpu);
|
||||
}
|
||||
|
||||
void AndroidInstance::enumerateGpu() {
|
||||
GPUIdent* ident = GPUIdent::getInstance();
|
||||
json gpu = {};
|
||||
gpu["gpuName"] = ident->getName().toUtf8().constData();
|
||||
gpu["gpuMemory"] = ident->getMemory();
|
||||
gpu["gpuDriver"] = ident->getDriver().toUtf8().constData();
|
||||
|
||||
_gpu.push_back(gpu);
|
||||
_display = ident->getOutput();
|
||||
}
|
||||
|
||||
void AndroidInstance::enumerateMemory() {
|
||||
json ram = {};
|
||||
|
||||
_memory.push_back(ram);
|
||||
}
|
25
libraries/platform/src/AndroidPlatform.h
Normal file
25
libraries/platform/src/AndroidPlatform.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// Created by Amer Cerkic 05/02/2019
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_AndroidPlatform_h
|
||||
#define hifi_AndroidPlatform_h
|
||||
|
||||
#include "platformInstance.h"
|
||||
|
||||
namespace platform {
|
||||
class AndroidInstance : public Instance {
|
||||
|
||||
public:
|
||||
void enumerateCpu() override;
|
||||
void enumerateMemory() override;
|
||||
void enumerateGpu() override;
|
||||
};
|
||||
|
||||
} // namespace platform
|
||||
|
||||
#endif //hifi_androidplatform_h
|
42
libraries/platform/src/LinuxPlatform.cpp
Normal file
42
libraries/platform/src/LinuxPlatform.cpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// Created by Amer Cerkic 05/02/2019
|
||||
// Copyright 2019 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 "LinuxPlatform.h"
|
||||
#include "platformJsonKeys.h"
|
||||
#include <GPUIdent.h>
|
||||
#include <string>
|
||||
|
||||
using namespace platform;
|
||||
void LinuxInstance::enumerateCpu() {
|
||||
json cpu = {};
|
||||
|
||||
cpu["cpuBrand"] = "";
|
||||
cpu["cpuModel"] = "";
|
||||
cpu["cpuClockSpeed"] = "";
|
||||
cpu["cpuNumCores"] = "";
|
||||
|
||||
_cpu.push_back(cpu);
|
||||
}
|
||||
|
||||
void LinuxInstance::enumerateGpu() {
|
||||
GPUIdent* ident = GPUIdent::getInstance();
|
||||
json gpu = {};
|
||||
gpu["gpuName"] = ident->getName().toUtf8().constData();
|
||||
gpu["gpuMemory"] = ident->getMemory();
|
||||
gpu["gpuDriver"] = ident->getDriver().toUtf8().constData();
|
||||
|
||||
_gpu.push_back(gpu);
|
||||
_display = ident->getOutput();
|
||||
}
|
||||
|
||||
void LinuxInstance::enumerateMemory() {
|
||||
json ram = {};
|
||||
|
||||
|
||||
_memory.push_back(ram);
|
||||
}
|
25
libraries/platform/src/LinuxPlatform.h
Normal file
25
libraries/platform/src/LinuxPlatform.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// Created by Amer Cerkic 05/02/2019
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_LinuxPlatform_h
|
||||
#define hifi_LinuxPlatform_h
|
||||
|
||||
#include "platformInstance.h"
|
||||
|
||||
namespace platform {
|
||||
class LinuxInstance : public Instance {
|
||||
|
||||
public:
|
||||
void enumerateCpu() override;
|
||||
void enumerateMemory() override;
|
||||
void enumerateGpu() override;
|
||||
};
|
||||
|
||||
} // namespace platform
|
||||
|
||||
#endif //hifi_linuxPlaform_h
|
86
libraries/platform/src/MACOSPlatform.cpp
Normal file
86
libraries/platform/src/MACOSPlatform.cpp
Normal file
|
@ -0,0 +1,86 @@
|
|||
//
|
||||
// Created by Amer Cerkic 05/02/2019
|
||||
// Copyright 2019 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 "MACOSPlatform.h"
|
||||
#include "platformJsonKeys.h"
|
||||
#include <thread>
|
||||
#include <GPUIdent.h>
|
||||
#include <string>
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#include <unistd.h>
|
||||
#include <cpuid.h>
|
||||
#endif
|
||||
|
||||
using namespace platform;
|
||||
|
||||
static void getCpuId( uint32_t* p, uint32_t ax )
|
||||
{
|
||||
#ifdef Q_OS_MAC
|
||||
__asm __volatile
|
||||
( "movl %%ebx, %%esi\n\t"
|
||||
"cpuid\n\t"
|
||||
"xchgl %%ebx, %%esi"
|
||||
: "=a" (p[0]), "=S" (p[1]),
|
||||
"=c" (p[2]), "=d" (p[3])
|
||||
: "0" (ax)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MACOSInstance::enumerateCpu() {
|
||||
json cpu = {};
|
||||
uint32_t cpuInfo[4]={0,0,0,0};
|
||||
char CPUBrandString[16];
|
||||
char CPUModelString[16];
|
||||
char CPUClockString[16];
|
||||
uint32_t nExIds;
|
||||
getCpuId(cpuInfo, 0x80000000);
|
||||
nExIds = cpuInfo[0];
|
||||
|
||||
for (uint32_t i = 0x80000000; i <= nExIds; ++i) {
|
||||
getCpuId(cpuInfo, i);
|
||||
// Interpret CPU brand string
|
||||
if (i == 0x80000002) {
|
||||
memcpy(CPUBrandString, cpuInfo, sizeof(cpuInfo));
|
||||
} else if (i == 0x80000003) {
|
||||
memcpy(CPUModelString, cpuInfo, sizeof(cpuInfo));
|
||||
} else if (i == 0x80000004) {
|
||||
memcpy(CPUClockString, cpuInfo, sizeof(cpuInfo));
|
||||
}
|
||||
}
|
||||
|
||||
cpu["cpuBrand"] = CPUBrandString;
|
||||
cpu["cpuModel"] = CPUModelString;
|
||||
cpu["cpuClockSpeed"] = CPUClockString;
|
||||
cpu["cpuNumCores"] = std::thread::hardware_concurrency();
|
||||
|
||||
_cpu.push_back(cpu);
|
||||
}
|
||||
|
||||
void MACOSInstance::enumerateGpu() {
|
||||
GPUIdent* ident = GPUIdent::getInstance();
|
||||
json gpu = {};
|
||||
gpu["gpuName"] = ident->getName().toUtf8().constData();
|
||||
gpu["gpuMemory"] = ident->getMemory();
|
||||
gpu["gpuDriver"] = ident->getDriver().toUtf8().constData();
|
||||
|
||||
_gpu.push_back(gpu);
|
||||
_display = ident->getOutput();
|
||||
}
|
||||
|
||||
void MACOSInstance::enumerateMemory() {
|
||||
json ram = {};
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
long pages = sysconf(_SC_PHYS_PAGES);
|
||||
long page_size = sysconf(_SC_PAGE_SIZE);
|
||||
ram["totalMemory"] = pages * page_size;;
|
||||
#endif
|
||||
_memory.push_back(ram);
|
||||
}
|
25
libraries/platform/src/MACOSPlatform.h
Normal file
25
libraries/platform/src/MACOSPlatform.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// Created by Amer Cerkic 05/02/2019
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_MACOSPlatform_h
|
||||
#define hifi_MACOSPlatform_h
|
||||
|
||||
#include "platformInstance.h"
|
||||
|
||||
namespace platform {
|
||||
class MACOSInstance : public Instance {
|
||||
|
||||
public:
|
||||
void enumerateCpu() override;
|
||||
void enumerateMemory() override;
|
||||
void enumerateGpu() override;
|
||||
};
|
||||
|
||||
} // namespace platform
|
||||
|
||||
#endif //hifi_winplatform_h
|
82
libraries/platform/src/WINPlatform.cpp
Normal file
82
libraries/platform/src/WINPlatform.cpp
Normal file
|
@ -0,0 +1,82 @@
|
|||
//
|
||||
// Created by Amer Cerkic 05/02/2019
|
||||
// Copyright 2019 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 "WINPlatform.h"
|
||||
#include "platformJsonKeys.h"
|
||||
#ifdef Q_OS_WINDOWS
|
||||
#include <intrin.h>
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include <thread>
|
||||
#include <GPUIdent.h>
|
||||
#include <string>
|
||||
|
||||
|
||||
using namespace platform;
|
||||
|
||||
void WINInstance::enumerateCpu() {
|
||||
json cpu = {};
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
int CPUInfo[4] = { -1 };
|
||||
unsigned nExIds;
|
||||
unsigned int i = 0;
|
||||
char CPUBrandString[16];
|
||||
char CPUModelString[16];
|
||||
char CPUClockString[16];
|
||||
// Get the information associated with each extended ID.
|
||||
__cpuid(CPUInfo, 0x80000000);
|
||||
nExIds = CPUInfo[0];
|
||||
|
||||
for (i = 0x80000000; i <= nExIds; ++i) {
|
||||
__cpuid(CPUInfo, i);
|
||||
// Interpret CPU brand string
|
||||
if (i == 0x80000002) {
|
||||
memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo));
|
||||
} else if (i == 0x80000003) {
|
||||
memcpy(CPUModelString, CPUInfo, sizeof(CPUInfo));
|
||||
} else if (i == 0x80000004) {
|
||||
memcpy(CPUClockString, CPUInfo, sizeof(CPUInfo));
|
||||
}
|
||||
}
|
||||
|
||||
cpu["cpuBrand"] = CPUBrandString;
|
||||
cpu["cpuModel"] = CPUModelString;
|
||||
cpu["cpuClockSpeed"] = CPUClockString;
|
||||
cpu["cpuNumCores"] = std::thread::hardware_concurrency();
|
||||
#endif
|
||||
|
||||
_cpu.push_back(cpu);
|
||||
}
|
||||
|
||||
void WINInstance::enumerateGpu() {
|
||||
|
||||
GPUIdent* ident = GPUIdent::getInstance();
|
||||
|
||||
json gpu = {};
|
||||
gpu["gpuName"] = ident->getName().toUtf8().constData();
|
||||
gpu["gpuMemory"] = ident->getMemory();
|
||||
gpu["gpuDriver"] = ident->getDriver().toUtf8().constData();
|
||||
|
||||
_gpu.push_back(gpu);
|
||||
_display = ident->getOutput();
|
||||
}
|
||||
|
||||
void WINInstance::enumerateMemory() {
|
||||
json ram = {};
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
MEMORYSTATUSEX statex;
|
||||
statex.dwLength = sizeof(statex);
|
||||
GlobalMemoryStatusEx(&statex);
|
||||
int totalRam = statex.ullTotalPhys / 1024 / 1024;
|
||||
ram[jsonKeys::totalMemory] = totalRam;
|
||||
#endif
|
||||
_memory.push_back(ram);
|
||||
}
|
25
libraries/platform/src/WINPlatform.h
Normal file
25
libraries/platform/src/WINPlatform.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// Created by Amer Cerkic 05/02/2019
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_WinPlatform_h
|
||||
#define hifi_WinPlatform_h
|
||||
|
||||
#include "platformInstance.h"
|
||||
|
||||
namespace platform {
|
||||
class WINInstance : public Instance {
|
||||
|
||||
public:
|
||||
void enumerateCpu() override;
|
||||
void enumerateMemory() override;
|
||||
void enumerateGpu() override;
|
||||
|
||||
};
|
||||
} // namespace platform
|
||||
|
||||
#endif //hifi_winplatform_h
|
79
libraries/platform/src/platform.cpp
Normal file
79
libraries/platform/src/platform.cpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
//
|
||||
// Created by Amer Cerkic 05/02/2019
|
||||
// Copyright 2019 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 "platform.h"
|
||||
|
||||
#include <qglobal.h>
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
#include "WINPlatform.h"
|
||||
#elif defined(Q_OS_MAC)
|
||||
#include "MACOSPlatform.h"
|
||||
#elif defined(Q_OS_ANDROID)
|
||||
#include "AndroidPlatform.h"
|
||||
#elif defined(Q_OS_LINUX)
|
||||
#include "LinuxPlatform.h"
|
||||
#endif
|
||||
|
||||
using namespace platform;
|
||||
|
||||
Instance *_instance;
|
||||
|
||||
void platform::create() {
|
||||
#if defined(Q_OS_WIN)
|
||||
_instance =new WINInstance();
|
||||
#elif defined(Q_OS_MAC)
|
||||
_instance = new MACOSInstance();
|
||||
#elif defined(Q_OS_ANDROID)
|
||||
_instance= new AndroidInstance();
|
||||
#elif defined(Q_OS_LINUX)
|
||||
_instance= new LinuxInstance();
|
||||
#endif
|
||||
}
|
||||
|
||||
void platform::destroy() {
|
||||
if(_instance)
|
||||
delete _instance;
|
||||
}
|
||||
|
||||
bool platform::enumeratePlatform() {
|
||||
return _instance->enumeratePlatform();
|
||||
}
|
||||
|
||||
int platform::getNumCPU() {
|
||||
return _instance->getNumCPU();
|
||||
}
|
||||
|
||||
json platform::getCPU(int index) {
|
||||
return _instance->getCPU(index);
|
||||
}
|
||||
|
||||
int platform::getNumGPU() {
|
||||
return _instance->getNumGPU();
|
||||
}
|
||||
|
||||
json platform::getGPU(int index) {
|
||||
return _instance->getGPU(index);
|
||||
}
|
||||
|
||||
int platform::getNumDisplay() {
|
||||
return _instance->getNumDisplay();
|
||||
}
|
||||
|
||||
json platform::getDisplay(int index) {
|
||||
return _instance->getDisplay(index);
|
||||
}
|
||||
|
||||
int platform::getNumMemory() {
|
||||
return _instance->getNumMemory();
|
||||
}
|
||||
|
||||
json platform::getMemory(int index) {
|
||||
return _instance->getMemory(index);
|
||||
}
|
37
libraries/platform/src/platform.h
Normal file
37
libraries/platform/src/platform.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// Created by Amer Cerkic 05/02/2019
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_Platform_h
|
||||
#define hifi_Platform_h
|
||||
|
||||
#include "platformInstance.h"
|
||||
#include <vector>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace platform {
|
||||
using json = nlohmann::json;
|
||||
|
||||
void create();
|
||||
void destroy();
|
||||
bool enumeratePlatform();
|
||||
|
||||
int getNumCPU();
|
||||
json getCPU(int index);
|
||||
|
||||
int getNumGPU();
|
||||
json getGPU(int index);
|
||||
|
||||
int getNumDisplay();
|
||||
json getDisplay(int index);
|
||||
|
||||
int getNumMemory();
|
||||
json getMemory(int index);
|
||||
|
||||
} // namespace platform
|
||||
|
||||
#endif // hifi_platform_h
|
86
libraries/platform/src/platformInstance.cpp
Normal file
86
libraries/platform/src/platformInstance.cpp
Normal file
|
@ -0,0 +1,86 @@
|
|||
//
|
||||
// Created by Amer Cerkic 05/02/2019
|
||||
// Copyright 2019 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 "platform.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include "WINPlatform.h"
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
#include "MACOSPlatform.h"
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
#endif
|
||||
|
||||
using namespace platform;
|
||||
|
||||
bool Instance::enumeratePlatform() {
|
||||
enumerateCpu();
|
||||
enumerateGpu();
|
||||
enumerateMemory();
|
||||
return true;
|
||||
}
|
||||
|
||||
json Instance::getCPU(int index) {
|
||||
assert(index <(int) _cpu.size());
|
||||
if (index >= (int)_cpu.size())
|
||||
return json();
|
||||
|
||||
return _cpu.at(index);
|
||||
}
|
||||
|
||||
//These are ripe for template.. will work on that next
|
||||
json Instance::getMemory(int index) {
|
||||
assert(index <(int) _memory.size());
|
||||
if(index >= (int)_memory.size())
|
||||
return json();
|
||||
|
||||
return _memory.at(index);
|
||||
}
|
||||
|
||||
json Instance::getGPU(int index) {
|
||||
assert(index <(int) _gpu.size());
|
||||
|
||||
if (index >=(int) _gpu.size())
|
||||
return json();
|
||||
|
||||
return _gpu.at(index);
|
||||
}
|
||||
|
||||
json Instance::getDisplay(int index) {
|
||||
assert(index <(int) _display.size());
|
||||
|
||||
if (index >=(int) _display.size())
|
||||
return json();
|
||||
|
||||
return _display.at(index);
|
||||
}
|
||||
|
||||
Instance::~Instance() {
|
||||
if (_cpu.size() > 0) {
|
||||
_cpu.clear();
|
||||
}
|
||||
|
||||
if (_memory.size() > 0) {
|
||||
_memory.clear();
|
||||
}
|
||||
|
||||
|
||||
if (_gpu.size() > 0) {
|
||||
_gpu.clear();
|
||||
}
|
||||
|
||||
if (_display.size() > 0) {
|
||||
_display.clear();
|
||||
}
|
||||
}
|
49
libraries/platform/src/platformInstance.h
Normal file
49
libraries/platform/src/platformInstance.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// Created by Amer Cerkic 05/02/2019
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_PlatformInstance_h
|
||||
#define hifi_PlatformInstance_h
|
||||
|
||||
#include <vector>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace platform {
|
||||
using json = nlohmann::json;
|
||||
|
||||
class Instance {
|
||||
public:
|
||||
bool virtual enumeratePlatform();
|
||||
|
||||
int getNumCPU() { return (int)_cpu.size(); }
|
||||
json getCPU(int index);
|
||||
|
||||
int getNumGPU() { return (int)_gpu.size(); }
|
||||
json getGPU(int index);
|
||||
|
||||
int getNumMemory() { return (int)_memory.size(); }
|
||||
json getMemory(int index);
|
||||
|
||||
int getNumDisplay() { return (int)_display.size(); }
|
||||
json getDisplay(int index);
|
||||
|
||||
void virtual enumerateCpu()=0;
|
||||
void virtual enumerateMemory()=0;
|
||||
void virtual enumerateGpu()=0;
|
||||
|
||||
virtual ~Instance();
|
||||
|
||||
protected:
|
||||
std::vector<json> _cpu;
|
||||
std::vector<json> _memory;
|
||||
std::vector<json> _gpu;
|
||||
std::vector<json> _display;
|
||||
};
|
||||
|
||||
} // namespace platform
|
||||
|
||||
#endif // hifi_platformInstance_h
|
34
libraries/platform/src/platformJsonKeys.h
Normal file
34
libraries/platform/src/platformJsonKeys.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// Created by Amer Cerkic 05/02/2019
|
||||
// Copyright 2019 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
|
||||
//
|
||||
#pragma once
|
||||
#ifndef hifi_PlatformJsonKeys_h
|
||||
#define hifi_PlatformJsonKeys_h
|
||||
|
||||
namespace platform {
|
||||
namespace jsonKeys{
|
||||
#if 0
|
||||
static const char* cpuBrand { "cpuBrand"};
|
||||
static const char* cpuModel {"cpuModel"};
|
||||
static const char* cpuClockSpeed {"clockSpeed"};
|
||||
static const char* cpuNumCores { "numCores"};
|
||||
static const char* gpuName {"GpuName"};
|
||||
static const char* gpuMemory {"gpuMemory"};
|
||||
static const char* gpuDriver {"gpuDriver"};
|
||||
static const char* totalMemory {"totalMem"};
|
||||
static const char* displayDescription { "description"};
|
||||
static const char* displayName {"deviceName"};
|
||||
static const char* displayCoordsLeft {"coordinatesleft"};
|
||||
static const char* displayCoordsRight { "coordinatesright"};
|
||||
static const char* displayCoordsTop { "coordinatestop"};
|
||||
static const char* displayCoordsBottom { "coordinatesbottom"};
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace platform
|
||||
|
||||
#endif
|
|
@ -211,7 +211,7 @@ public:
|
|||
virtual void cycleDebugOutput() {}
|
||||
|
||||
void waitForPresent();
|
||||
float getAveragePresentTime() { return _movingAveragePresent.average / (float)USECS_PER_MSEC; } // in msec
|
||||
float getAveragePresentTime() { return _movingAveragePresent.average / (float)USECS_PER_MSEC; } // in msec
|
||||
|
||||
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> getHUDOperator();
|
||||
|
||||
|
|
|
@ -15,3 +15,5 @@ endif()
|
|||
|
||||
target_zlib()
|
||||
target_nsight()
|
||||
target_json()
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <string>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
//#include <atlbase.h>
|
||||
//#include <Wbemidl.h>
|
||||
|
@ -250,6 +251,22 @@ GPUIdent* GPUIdent::ensureQuery(const QString& vendor, const QString& renderer)
|
|||
*/
|
||||
|
||||
if (!validAdapterList.empty()) {
|
||||
for (auto outy = adapterToOutputs.begin(); outy != adapterToOutputs.end(); ++outy) {
|
||||
|
||||
AdapterEntry entry = *outy;
|
||||
for (auto test = entry.second.begin(); test != entry.second.end(); ++test) {
|
||||
|
||||
nlohmann::json output = {};
|
||||
output["description"] = entry.first.first.Description;
|
||||
output["deviceName"]= test->DeviceName;
|
||||
output["coordinatesleft"] = test->DesktopCoordinates.left;
|
||||
output["coordinatesright"] = test->DesktopCoordinates.right;
|
||||
output["coordinatestop"] = test->DesktopCoordinates.top;
|
||||
output["coordinatesbottom"] = test->DesktopCoordinates.bottom;
|
||||
_output.push_back(output);
|
||||
}
|
||||
}
|
||||
|
||||
auto& adapterEntry = adapterToOutputs[validAdapterList.front()];
|
||||
|
||||
std::wstring wDescription(adapterEntry.first.first.Description);
|
||||
|
|
|
@ -15,19 +15,25 @@
|
|||
#define hifi_GPUIdent_h
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <QString>
|
||||
#include <memory>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <vector>
|
||||
|
||||
class GPUIdent
|
||||
{
|
||||
|
||||
public:
|
||||
uint64_t getMemory() { return _dedicatedMemoryMB; }
|
||||
QString getName() { return _name; }
|
||||
QString getDriver() { return _driver; }
|
||||
bool isValid() { return _isValid; }
|
||||
const std::vector<nlohmann::json>& getOutput() { return _output; }
|
||||
|
||||
// E.g., GPUIdent::getInstance()->getMemory();
|
||||
static GPUIdent* getInstance(const QString& vendor = "", const QString& renderer = "") { return _instance.ensureQuery(vendor, renderer); }
|
||||
private:
|
||||
std::vector<nlohmann::json> _output;
|
||||
uint64_t _dedicatedMemoryMB { 0 };
|
||||
QString _name { "" };
|
||||
QString _driver { "" };
|
||||
|
|
Loading…
Reference in a new issue