diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000000..e866713b11 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,72 @@ +module.exports = { + "root": true, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 5 + }, + "globals": { + "Account": false, + "AnimationCache": false, + "Assets": false, + "Audio": false, + "AudioDevice": false, + "AudioEffectOptions": false, + "AvatarList": false, + "AvatarManager": false, + "Camera": false, + "Clipboard": false, + "Controller": false, + "DialogsManager": false, + "Entities": false, + "FaceTracker": false, + "GlobalServices": false, + "HMD": false, + "LODManager": false, + "Mat4": false, + "Menu": false, + "Messages": false, + "ModelCache": false, + "MyAvatar": false, + "Overlays": false, + "Paths": false, + "Quat": false, + "Rates": false, + "Recording": false, + "Reticle": false, + "Scene": false, + "Script": false, + "ScriptDiscoveryService": false, + "Settings": false, + "SoundCache": false, + "Stats": false, + "TextureCache": false, + "Uuid": false, + "UndoStack": false, + "Vec3": false, + "WebSocket": false, + "WebWindow": false, + "Window": false, + "XMLHttpRequest": false, + "location": false, + "print": false + }, + "rules": { + "brace-style": ["error", "1tbs", { "allowSingleLine": false }], + "comma-dangle": ["error", "only-multiline"], + "camelcase": ["error"], + "curly": ["error", "all"], + "indent": ["error", 4, { "SwitchCase": 1 }], + "keyword-spacing": ["error", { "before": true, "after": true }], + "max-len": ["error", 128, 4], + "new-cap": ["error"], + //"no-magic-numbers": ["error", { "ignore": [0, 1], "ignoreArrayIndexes": true }], + "no-multiple-empty-lines": ["error"], + "no-multi-spaces": ["error"], + "no-unused-vars": ["error", { "args": "none", "vars": "local" }], + "semi": ["error", "always"], + "spaced-comment": ["error", "always", { + "line": { "markers": ["/"] } + }], + "space-before-function-paren": ["error", "never"] + } +}; diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 25cf860f54..ed40b4c520 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -1,6 +1,7 @@ var Settings = { showAdvanced: false, - METAVERSE_URL: 'https://metaverse.highfidelity.com', + // METAVERSE_URL: 'https://metaverse.highfidelity.com', + METAVERSE_URL: 'http://localhost:3000', ADVANCED_CLASS: 'advanced-setting', TRIGGER_CHANGE_CLASS: 'trigger-change', DATA_ROW_CLASS: 'value-row', diff --git a/domain-server/src/DomainMetadata.cpp b/domain-server/src/DomainMetadata.cpp index 927a14cab1..d614b1bbd3 100644 --- a/domain-server/src/DomainMetadata.cpp +++ b/domain-server/src/DomainMetadata.cpp @@ -50,8 +50,8 @@ const QString DomainMetadata::Descriptors::Hours::CLOSE = "close"; // "tags": [ String ], // capped list of tags // "hours": { // "utc_offset": Number, -// "weekday": [ { "open": Time, "close": Time } ], -// "weekend": [ { "open": Time, "close": Time } ], +// "weekday": [ [ Time, Time ] ], +// "weekend": [ [ Time, Time ] ], // } // } @@ -60,17 +60,50 @@ const QString DomainMetadata::Descriptors::Hours::CLOSE = "close"; // // it is meant to be sent to and consumed by an external API +// merge delta into target +// target should be of the form [ OpenTime, CloseTime ], +// delta should be of the form [ { open: Time, close: Time } ] +void parseHours(QVariant delta, QVariant& target) { + using Hours = DomainMetadata::Descriptors::Hours; + static const QVariantList DEFAULT_HOURS{ + { QVariantList{ "00:00", "23:59" } } + }; + target.setValue(DEFAULT_HOURS); + + if (!delta.canConvert()) { + return; + } + + auto& deltaList = *static_cast(delta.data()); + if (deltaList.isEmpty()) { + return; + } + + auto& deltaHours = *static_cast(deltaList.first().data()); + auto open = deltaHours.find(Hours::OPEN); + auto close = deltaHours.find(Hours::CLOSE); + if (open == deltaHours.end() || close == deltaHours.end()) { + return; + } + + // merge delta into new hours + static const int OPEN_INDEX = 0; + static const int CLOSE_INDEX = 1; + auto& hours = *static_cast(static_cast(target.data())->first().data()); + hours[OPEN_INDEX] = open.value(); + hours[CLOSE_INDEX] = close.value(); + + assert(hours[OPEN_INDEX].canConvert()); + assert(hours[CLOSE_INDEX].canConvert()); +} + DomainMetadata::DomainMetadata(QObject* domainServer) : QObject(domainServer) { // set up the structure necessary for casting during parsing (see parseHours, esp.) _metadata[USERS] = QVariantMap {}; _metadata[DESCRIPTORS] = QVariantMap { { Descriptors::HOURS, QVariantMap { - { Descriptors::Hours::WEEKDAY, QVariantList { - QVariantList{ QVariant{}, QVariant{} } } - }, - { Descriptors::Hours::WEEKEND, QVariantList { - QVariantList{ QVariant{}, QVariant{} } } - } + { Descriptors::Hours::WEEKDAY, QVariant{} }, + { Descriptors::Hours::WEEKEND, QVariant{} } } } }; @@ -100,45 +133,12 @@ QJsonObject DomainMetadata::get(const QString& group) { return QJsonObject::fromVariantMap(_metadata[group].toMap()); } -// merge delta into target -// target should be of the form [ OpenTime, CloseTime ], -// delta should be of the form [ { open: Time, close: Time } ] -void parseHours(QVariant delta, QVariant& target) { - using Hours = DomainMetadata::Descriptors::Hours; - - assert(target.canConvert()); - auto& targetList = *static_cast(target.data()); - - // if/when multiple ranges are allowed, this list will need to be iterated - assert(targetList[0].canConvert()); - auto& hours = *static_cast(targetList[0].data()); - - auto deltaHours = delta.toList()[0].toMap(); - if (deltaHours.isEmpty()) { - return; - } - - // merge delta into base - static const int OPEN_INDEX = 0; - static const int CLOSE_INDEX = 1; - auto open = deltaHours.find(Hours::OPEN); - if (open != deltaHours.end()) { - hours[OPEN_INDEX] = open.value(); - } - assert(hours[OPEN_INDEX].canConvert()); - auto close = deltaHours.find(Hours::CLOSE); - if (close != deltaHours.end()) { - hours[CLOSE_INDEX] = close.value(); - } - assert(hours[CLOSE_INDEX].canConvert()); -} - void DomainMetadata::descriptorsChanged() { // get descriptors assert(_metadata[DESCRIPTORS].canConvert()); auto& state = *static_cast(_metadata[DESCRIPTORS].data()); - auto settings = static_cast(parent())->_settingsManager.getSettingsMap(); - auto descriptors = settings[DESCRIPTORS].toMap(); + auto& settings = static_cast(parent())->_settingsManager.getSettingsMap(); + auto& descriptors = static_cast(parent())->_settingsManager.getDescriptorsMap(); // copy simple descriptors (description/maturity) state[Descriptors::DESCRIPTION] = descriptors[Descriptors::DESCRIPTION]; @@ -149,20 +149,20 @@ void DomainMetadata::descriptorsChanged() { state[Descriptors::TAGS] = descriptors[Descriptors::TAGS].toList(); // parse capacity - const QString CAPACITY = "security.maximum_user_capacity"; + static const QString CAPACITY = "security.maximum_user_capacity"; const QVariant* capacityVariant = valueForKeyPath(settings, CAPACITY); unsigned int capacity = capacityVariant ? capacityVariant->toUInt() : 0; state[Descriptors::CAPACITY] = capacity; // parse operating hours - const QString WEEKDAY_HOURS = "weekday_hours"; - const QString WEEKEND_HOURS = "weekend_hours"; - const QString UTC_OFFSET = "utc_offset"; + static const QString WEEKDAY_HOURS = "weekday_hours"; + static const QString WEEKEND_HOURS = "weekend_hours"; + static const QString UTC_OFFSET = "utc_offset"; assert(state[Descriptors::HOURS].canConvert()); auto& hours = *static_cast(state[Descriptors::HOURS].data()); - parseHours(descriptors.take(WEEKDAY_HOURS), hours[Descriptors::Hours::WEEKDAY]); - parseHours(descriptors.take(WEEKEND_HOURS), hours[Descriptors::Hours::WEEKEND]); hours[Descriptors::Hours::UTC_OFFSET] = descriptors.take(UTC_OFFSET); + parseHours(descriptors[WEEKDAY_HOURS], hours[Descriptors::Hours::WEEKDAY]); + parseHours(descriptors[WEEKEND_HOURS], hours[Descriptors::Hours::WEEKEND]); #if DEV_BUILD || PR_BUILD qDebug() << "Domain metadata descriptors set:" << QJsonObject::fromVariantMap(_metadata[DESCRIPTORS].toMap()); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 923a82d184..d78199ba8e 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -44,7 +44,8 @@ int const DomainServer::EXIT_CODE_REBOOT = 234923; -const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.com"; +// const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.com"; +const QString ICE_SERVER_DEFAULT_HOSTNAME = "localhost"; DomainServer::DomainServer(int argc, char* argv[]) : QCoreApplication(argc, argv), diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 943f0517dc..56656f9d7c 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include "DomainServerSettingsManager.h" @@ -272,23 +273,7 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList if (oldVersion < 1.5) { // This was prior to operating hours, so add default hours - static const QString WEEKDAY_HOURS{ "descriptors.weekday_hours" }; - static const QString WEEKEND_HOURS{ "descriptors.weekend_hours" }; - static const QString UTC_OFFSET{ "descriptors.utc_offset" }; - - QVariant* weekdayHours = valueForKeyPath(_configMap.getUserConfig(), WEEKDAY_HOURS, true); - QVariant* weekendHours = valueForKeyPath(_configMap.getUserConfig(), WEEKEND_HOURS, true); - QVariant* utcOffset = valueForKeyPath(_configMap.getUserConfig(), UTC_OFFSET, true); - - *weekdayHours = QVariantList { QVariantMap{ { "open", QVariant("00:00") }, { "close", QVariant("23:59") } } }; - *weekendHours = QVariantList { QVariantMap{ { "open", QVariant("00:00") }, { "close", QVariant("23:59") } } }; - *utcOffset = QVariant(QTimeZone::systemTimeZone().offsetFromUtc(QDateTime::currentDateTime()) / (float)3600); - - // write the new settings to file - persistToFile(); - - // reload the master and user config so the merged config is correct - _configMap.loadMasterAndUserConfig(_argumentList); + validateDescriptorsMap(); } } @@ -298,6 +283,49 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList appSettings.setValue(JSON_SETTINGS_VERSION_KEY, _descriptionVersion); } +QVariantMap& DomainServerSettingsManager::getDescriptorsMap() { + validateDescriptorsMap(); + + static const QString DESCRIPTORS{ "descriptors" }; + return *static_cast(getSettingsMap()[DESCRIPTORS].data()); +} + +void DomainServerSettingsManager::validateDescriptorsMap() { + static const QString WEEKDAY_HOURS{ "descriptors.weekday_hours" }; + static const QString WEEKEND_HOURS{ "descriptors.weekend_hours" }; + static const QString UTC_OFFSET{ "descriptors.utc_offset" }; + + QVariant* weekdayHours = valueForKeyPath(_configMap.getUserConfig(), WEEKDAY_HOURS, true); + QVariant* weekendHours = valueForKeyPath(_configMap.getUserConfig(), WEEKEND_HOURS, true); + QVariant* utcOffset = valueForKeyPath(_configMap.getUserConfig(), UTC_OFFSET, true); + + static const QString OPEN{ "open" }; + static const QString CLOSE{ "close" }; + static const QString DEFAULT_OPEN{ "00:00" }; + static const QString DEFAULT_CLOSE{ "23:59" }; + bool wasMalformed = false; + if (weekdayHours->isNull()) { + *weekdayHours = QVariantList{ QVariantMap{ { OPEN, QVariant(DEFAULT_OPEN) }, { CLOSE, QVariant(DEFAULT_CLOSE) } } }; + wasMalformed = true; + } + if (weekendHours->isNull()) { + *weekendHours = QVariantList{ QVariantMap{ { OPEN, QVariant(DEFAULT_OPEN) }, { CLOSE, QVariant(DEFAULT_CLOSE) } } }; + wasMalformed = true; + } + if (utcOffset->isNull()) { + *utcOffset = QVariant(QTimeZone::systemTimeZone().offsetFromUtc(QDateTime::currentDateTime()) / (float)SECS_PER_HOUR); + wasMalformed = true; + } + + if (wasMalformed) { + // write the new settings to file + persistToFile(); + + // reload the master and user config so the merged config is correct + _configMap.loadMasterAndUserConfig(_argumentList); + } +} + void DomainServerSettingsManager::packPermissionsForMap(QString mapName, NodePermissionsMap& agentPermissions, QString keyPath) { diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h index 7354955684..a4978c8e91 100644 --- a/domain-server/src/DomainServerSettingsManager.h +++ b/domain-server/src/DomainServerSettingsManager.h @@ -43,6 +43,8 @@ public: QVariantMap& getUserSettingsMap() { return _configMap.getUserConfig(); } QVariantMap& getSettingsMap() { return _configMap.getMergedConfig(); } + QVariantMap& getDescriptorsMap(); + // these give access to anonymous/localhost/logged-in settings from the domain-server settings page bool haveStandardPermissionsForName(const QString& name) const { return _standardAgentPermissions.contains(name); } NodePermissions getStandardPermissionsForName(const QString& name) const; @@ -97,6 +99,8 @@ private: friend class DomainServer; + void validateDescriptorsMap(); + // these cause calls to metaverse's group api void requestMissingGroupIDs(); void getGroupID(const QString& groupname); diff --git a/interface/resources/qml/desktop/Desktop.qml b/interface/resources/qml/desktop/Desktop.qml index 9f10cfc64a..27fa9692b9 100644 --- a/interface/resources/qml/desktop/Desktop.qml +++ b/interface/resources/qml/desktop/Desktop.qml @@ -24,6 +24,13 @@ FocusScope { readonly property int invalid_position: -9999; property rect recommendedRect: Qt.rect(0,0,0,0); property var expectedChildren; + property bool repositionLocked: true + + onRepositionLockedChanged: { + if (!repositionLocked) { + d.handleSizeChanged(); + } + } onHeightChanged: d.handleSizeChanged(); @@ -52,11 +59,14 @@ FocusScope { readonly property real menu: 8000 } - QtObject { id: d function handleSizeChanged() { + if (desktop.repositionLocked) { + return; + } + var oldRecommendedRect = recommendedRect; var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedOverlayRect(); var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y, @@ -235,6 +245,10 @@ FocusScope { } function repositionAll() { + if (desktop.repositionLocked) { + return; + } + var oldRecommendedRect = recommendedRect; var oldRecommendedDimmensions = { x: oldRecommendedRect.width, y: oldRecommendedRect.height }; var newRecommendedRect = Controller.getRecommendedOverlayRect(); diff --git a/interface/resources/qml/menus/MenuMouseHandler.qml b/interface/resources/qml/menus/MenuMouseHandler.qml index 9ba158cb28..48574d41e5 100644 --- a/interface/resources/qml/menus/MenuMouseHandler.qml +++ b/interface/resources/qml/menus/MenuMouseHandler.qml @@ -39,6 +39,19 @@ Item { onSelected: d.handleSelection(subMenu, currentItem, item) } } + property var delay: Timer { // No setTimeout in QML. + property var menuItem: null; + interval: 0 + repeat: false + running: false + function trigger(item) { // Capture item and schedule asynchronous Timer. + menuItem = item; + start(); + } + onTriggered: { + menuItem.trigger(); // Now trigger the item. + } + } function toModel(items) { var result = modelMaker.createObject(desktop); @@ -128,7 +141,8 @@ Item { case MenuItemType.Item: console.log("Triggering " + item.text) - item.trigger(); + // Don't block waiting for modal dialogs and such that the menu might open. + delay.trigger(item); clearMenus(); break; } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ad40016f9f..5978461dcf 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -773,6 +773,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : auto gpuIdent = GPUIdent::getInstance(); auto glContextData = getGLContextData(); QJsonObject properties = { + { "version", applicationVersion() }, { "previousSessionCrashed", _previousSessionCrashed }, { "previousSessionRuntime", sessionRunTime.get() }, { "cpu_architecture", QSysInfo::currentCpuArchitecture() }, @@ -963,6 +964,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : updateHeartbeat(); loadSettings(); + + // Now that we've loaded the menu and thus switched to the previous display plugin + // we can unlock the desktop repositioning code, since all the positions will be + // relative to the desktop size for this plugin + auto offscreenUi = DependencyManager::get(); + offscreenUi->getDesktop()->setProperty("repositionLocked", false); + // Make sure we don't time out during slow operations at startup updateHeartbeat(); @@ -1711,22 +1719,22 @@ void Application::paintGL() { if (isHMDMode()) { mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); _myCamera.setPosition(extractTranslation(camMat)); - _myCamera.setRotation(glm::quat_cast(camMat)); + _myCamera.setOrientation(glm::quat_cast(camMat)); } else { _myCamera.setPosition(myAvatar->getDefaultEyePosition()); - _myCamera.setRotation(myAvatar->getHead()->getCameraOrientation()); + _myCamera.setOrientation(myAvatar->getHead()->getCameraOrientation()); } } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { if (isHMDMode()) { auto hmdWorldMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); - _myCamera.setRotation(glm::normalize(glm::quat_cast(hmdWorldMat))); + _myCamera.setOrientation(glm::normalize(glm::quat_cast(hmdWorldMat))); _myCamera.setPosition(extractTranslation(hmdWorldMat) + myAvatar->getOrientation() * boomOffset); } else { - _myCamera.setRotation(myAvatar->getHead()->getOrientation()); + _myCamera.setOrientation(myAvatar->getHead()->getOrientation()); if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + _myCamera.getRotation() * boomOffset); + + _myCamera.getOrientation() * boomOffset); } else { _myCamera.setPosition(myAvatar->getDefaultEyePosition() + myAvatar->getOrientation() * boomOffset); @@ -1745,7 +1753,7 @@ void Application::paintGL() { glm::quat worldMirrorRotation = mirrorBodyOrientation * mirrorHmdRotation; - _myCamera.setRotation(worldMirrorRotation); + _myCamera.setOrientation(worldMirrorRotation); glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix()); // Mirror HMD lateral offsets @@ -1756,7 +1764,7 @@ void Application::paintGL() { + mirrorBodyOrientation * glm::vec3(0.0f, 0.0f, 1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror + mirrorBodyOrientation * hmdOffset); } else { - _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() + _myCamera.setOrientation(myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); _myCamera.setPosition(myAvatar->getDefaultEyePosition() + glm::vec3(0, _raiseMirror * myAvatar->getUniformScale(), 0) @@ -1769,11 +1777,11 @@ void Application::paintGL() { if (cameraEntity != nullptr) { if (isHMDMode()) { glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix()); - _myCamera.setRotation(cameraEntity->getRotation() * hmdRotation); + _myCamera.setOrientation(cameraEntity->getRotation() * hmdRotation); glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix()); _myCamera.setPosition(cameraEntity->getPosition() + (hmdRotation * hmdOffset)); } else { - _myCamera.setRotation(cameraEntity->getRotation()); + _myCamera.setOrientation(cameraEntity->getRotation()); _myCamera.setPosition(cameraEntity->getPosition()); } } @@ -3309,9 +3317,9 @@ void Application::updateMyAvatarLookAtPosition() { if (isLookingAtSomeone) { deflection *= GAZE_DEFLECTION_REDUCTION_DURING_EYE_CONTACT; } - lookAtSpot = origin + _myCamera.getRotation() * glm::quat(glm::radians(glm::vec3( + lookAtSpot = origin + _myCamera.getOrientation() * glm::quat(glm::radians(glm::vec3( eyePitch * deflection, eyeYaw * deflection, 0.0f))) * - glm::inverse(_myCamera.getRotation()) * (lookAtSpot - origin); + glm::inverse(_myCamera.getOrientation()) * (lookAtSpot - origin); } } @@ -4027,7 +4035,7 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { // Set the viewFrustum up with the correct position and orientation of the camera viewFrustum.setPosition(camera.getPosition()); - viewFrustum.setOrientation(camera.getRotation()); + viewFrustum.setOrientation(camera.getOrientation()); // Ask the ViewFrustum class to calculate our corners viewFrustum.calculate(); @@ -4300,7 +4308,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_REARVIEW_DISTANCE * myAvatar->getScale()); } _mirrorCamera.setProjection(glm::perspective(glm::radians(fov), aspect, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP)); - _mirrorCamera.setRotation(myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f))); + _mirrorCamera.setOrientation(myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f))); // set the bounds of rear mirror view @@ -5343,7 +5351,6 @@ void Application::updateDisplayMode() { _displayPlugin = newDisplayPlugin; } - emit activeDisplayPluginChanged(); // reset the avatar, to set head and hand palms back to a reasonable default pose. diff --git a/interface/src/Camera.cpp b/interface/src/Camera.cpp index 53a3500bff..227bdadb97 100644 --- a/interface/src/Camera.cpp +++ b/interface/src/Camera.cpp @@ -62,14 +62,14 @@ void Camera::update(float deltaTime) { } void Camera::recompose() { - mat4 orientation = glm::mat4_cast(_rotation); + mat4 orientation = glm::mat4_cast(_orientation); mat4 translation = glm::translate(mat4(), _position); _transform = translation * orientation; } void Camera::decompose() { _position = vec3(_transform[3]); - _rotation = glm::quat_cast(_transform); + _orientation = glm::quat_cast(_transform); } void Camera::setTransform(const glm::mat4& transform) { @@ -85,8 +85,8 @@ void Camera::setPosition(const glm::vec3& position) { } } -void Camera::setRotation(const glm::quat& rotation) { - _rotation = rotation; +void Camera::setOrientation(const glm::quat& orientation) { + _orientation = orientation; recompose(); if (_isKeepLookingAt) { lookAt(_lookingAt); @@ -154,9 +154,9 @@ QString Camera::getModeString() const { void Camera::lookAt(const glm::vec3& lookAt) { glm::vec3 up = IDENTITY_UP; glm::mat4 lookAtMatrix = glm::lookAt(_position, lookAt, up); - glm::quat rotation = glm::quat_cast(lookAtMatrix); - rotation.w = -rotation.w; // Rosedale approved - _rotation = rotation; + glm::quat orientation = glm::quat_cast(lookAtMatrix); + orientation.w = -orientation.w; // Rosedale approved + _orientation = orientation; } void Camera::keepLookingAt(const glm::vec3& point) { @@ -171,7 +171,7 @@ void Camera::loadViewFrustum(ViewFrustum& frustum) const { // Set the viewFrustum up with the correct position and orientation of the camera frustum.setPosition(getPosition()); - frustum.setOrientation(getRotation()); + frustum.setOrientation(getOrientation()); // Ask the ViewFrustum class to calculate our corners frustum.calculate(); diff --git a/interface/src/Camera.h b/interface/src/Camera.h index 486b98c100..46cad2efc8 100644 --- a/interface/src/Camera.h +++ b/interface/src/Camera.h @@ -45,7 +45,7 @@ class Camera : public QObject { public: Camera(); - void initialize(); // instantly put the camera at the ideal position and rotation. + void initialize(); // instantly put the camera at the ideal position and orientation. void update( float deltaTime ); @@ -57,25 +57,22 @@ public: EntityItemPointer getCameraEntityPointer() const { return _cameraEntity; } -public slots: - QString getModeString() const; - void setModeString(const QString& mode); - - glm::quat getRotation() const { return _rotation; } - void setRotation(const glm::quat& rotation); - - glm::vec3 getPosition() const { return _position; } - void setPosition(const glm::vec3& position); - - glm::quat getOrientation() const { return getRotation(); } - void setOrientation(const glm::quat& orientation) { setRotation(orientation); } - const glm::mat4& getTransform() const { return _transform; } void setTransform(const glm::mat4& transform); const glm::mat4& getProjection() const { return _projection; } void setProjection(const glm::mat4& projection); +public slots: + QString getModeString() const; + void setModeString(const QString& mode); + + glm::vec3 getPosition() const { return _position; } + void setPosition(const glm::vec3& position); + + glm::quat getOrientation() const { return _orientation; } + void setOrientation(const glm::quat& orientation); + QUuid getCameraEntity() const; void setCameraEntity(QUuid entityID); @@ -105,7 +102,7 @@ private: // derived glm::vec3 _position; - glm::quat _rotation; + glm::quat _orientation; bool _isKeepLookingAt{ false }; glm::vec3 _lookingAt; EntityItemPointer _cameraEntity; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 55d93d5b5b..856e526b4c 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -191,9 +191,11 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties if (success) { emit debitEnergySource(cost); queueEntityMessage(PacketType::EntityAdd, id, propertiesWithSimID); - } - return id; + return id; + } else { + return QUuid(); + } } QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QString& modelUrl, const glm::vec3& position) { diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 7ebfecbe8e..21e5865c09 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -320,6 +320,11 @@ EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const Enti return nullptr; } + if (!properties.getClientOnly() && getIsClient() && + !nodeList->getThisNodeCanRez() && !nodeList->getThisNodeCanRezTmp()) { + return nullptr; + } + bool recordCreationTime = false; if (props.getCreated() == UNKNOWN_CREATED_TIME) { // the entity's creation time was not specified in properties, which means this is a NEW entity diff --git a/libraries/gl/src/gl/GLHelpers.cpp b/libraries/gl/src/gl/GLHelpers.cpp index 79b39a2331..2781d5b9b0 100644 --- a/libraries/gl/src/gl/GLHelpers.cpp +++ b/libraries/gl/src/gl/GLHelpers.cpp @@ -6,6 +6,14 @@ #include #include #include +#include +#ifdef DEBUG +static bool enableDebug = true; +#else +static const QString DEBUG_FLAG("HIFI_ENABLE_OPENGL_45"); +static bool enableDebug = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG); +#endif + const QSurfaceFormat& getDefaultOpenGLSurfaceFormat() { static QSurfaceFormat format; @@ -15,9 +23,9 @@ const QSurfaceFormat& getDefaultOpenGLSurfaceFormat() { format.setDepthBufferSize(DEFAULT_GL_DEPTH_BUFFER_BITS); format.setStencilBufferSize(DEFAULT_GL_STENCIL_BUFFER_BITS); setGLFormatVersion(format); -#ifdef DEBUG - format.setOption(QSurfaceFormat::DebugContext); -#endif + if (enableDebug) { + format.setOption(QSurfaceFormat::DebugContext); + } format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); QSurfaceFormat::setDefaultFormat(format); }); diff --git a/libraries/gl/src/gl/OffscreenGLCanvas.cpp b/libraries/gl/src/gl/OffscreenGLCanvas.cpp index 90ff369cd6..eec3d2bf6b 100644 --- a/libraries/gl/src/gl/OffscreenGLCanvas.cpp +++ b/libraries/gl/src/gl/OffscreenGLCanvas.cpp @@ -12,23 +12,30 @@ #include "OffscreenGLCanvas.h" +#include #include #include #include #include "GLHelpers.h" +#ifdef DEBUG +static bool enableDebugLogger = true; +#else +static const QString DEBUG_FLAG("HIFI_ENABLE_OPENGL_45"); +static bool enableDebugLogger = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG); +#endif + + OffscreenGLCanvas::OffscreenGLCanvas() : _context(new QOpenGLContext), _offscreenSurface(new QOffscreenSurface){ } OffscreenGLCanvas::~OffscreenGLCanvas() { -#ifdef DEBUG if (_logger) { makeCurrent(); delete _logger; _logger = nullptr; } -#endif _context->doneCurrent(); } @@ -60,7 +67,7 @@ bool OffscreenGLCanvas::makeCurrent() { qDebug() << "GL Renderer: " << QString((const char*) glGetString(GL_RENDERER)); }); -#ifdef DEBUG + if (result && !_logger) { _logger = new QOpenGLDebugLogger(this); if (_logger->initialize()) { @@ -71,7 +78,6 @@ bool OffscreenGLCanvas::makeCurrent() { _logger->startLogging(QOpenGLDebugLogger::LoggingMode::SynchronousLogging); } } -#endif return result; } diff --git a/libraries/gl/src/gl/OffscreenGLCanvas.h b/libraries/gl/src/gl/OffscreenGLCanvas.h index 387804bf56..69210f638d 100644 --- a/libraries/gl/src/gl/OffscreenGLCanvas.h +++ b/libraries/gl/src/gl/OffscreenGLCanvas.h @@ -36,10 +36,7 @@ protected: std::once_flag _reportOnce; QOpenGLContext* _context; QOffscreenSurface* _offscreenSurface; -#ifdef DEBUG QOpenGLDebugLogger* _logger{ nullptr }; -#endif - }; #endif // hifi_OffscreenGLCanvas_h diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index e18b784018..ce2f4c8d66 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -17,6 +17,7 @@ #include #include "../gl41/GL41Backend.h" +#include "../gl45/GL45Backend.h" #if defined(NSIGHT_FOUND) #include "nvToolsExt.h" @@ -31,25 +32,21 @@ using namespace gpu; using namespace gpu::gl; - static const QString DEBUG_FLAG("HIFI_ENABLE_OPENGL_45"); -bool enableOpenGL45 = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG); +static bool enableOpenGL45 = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG); Backend* GLBackend::createBackend() { - -#if 0 // FIXME provide a mechanism to override the backend for testing // Where the gpuContext is initialized and where the TRUE Backend is created and assigned auto version = QOpenGLContextWrapper::currentContextVersion(); GLBackend* result; if (enableOpenGL45 && version >= 0x0405) { - result = new gpu::gl45::GLBackend; + qDebug() << "Using OpenGL 4.5 backend"; + result = new gpu::gl45::GL45Backend(); } else { - result = new gpu::gl41::GLBackend; + qDebug() << "Using OpenGL 4.1 backend"; + result = new gpu::gl41::GL41Backend(); } -#else - GLBackend* result = new gpu::gl41::GL41Backend; -#endif result->initInput(); result->initTransform(); gl::GLTexture::initTextureTransferHelper(); diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h index 5255a6cb25..d27ec3808b 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h @@ -186,7 +186,7 @@ protected: virtual void killInput() final; virtual void syncInputStateCache() final; virtual void resetInputStage() final; - virtual void updateInput() = 0; + virtual void updateInput(); struct InputStageState { bool _invalidFormat { true }; diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendInput.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendInput.cpp index 448cc508eb..99c1ff0438 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendInput.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendInput.cpp @@ -150,3 +150,176 @@ void GLBackend::do_setIndirectBuffer(Batch& batch, size_t paramOffset) { (void)CHECK_GL_ERROR(); } + + +// Core 41 doesn't expose the features to really separate the vertex format from the vertex buffers binding +// Core 43 does :) +// FIXME crashing problem with glVertexBindingDivisor / glVertexAttribFormat +// Once resolved, break this up into the GL 4.1 and 4.5 backends +#if 1 || (GPU_INPUT_PROFILE == GPU_CORE_41) +#define NO_SUPPORT_VERTEX_ATTRIB_FORMAT +#else +#define SUPPORT_VERTEX_ATTRIB_FORMAT +#endif + +void GLBackend::updateInput() { +#if defined(SUPPORT_VERTEX_ATTRIB_FORMAT) + if (_input._invalidFormat) { + + InputStageState::ActivationCache newActivation; + + // Assign the vertex format required + if (_input._format) { + for (auto& it : _input._format->getAttributes()) { + const Stream::Attribute& attrib = (it).second; + + GLuint slot = attrib._slot; + GLuint count = attrib._element.getLocationScalarCount(); + uint8_t locationCount = attrib._element.getLocationCount(); + GLenum type = _elementTypeToGL41Type[attrib._element.getType()]; + GLuint offset = attrib._offset;; + GLboolean isNormalized = attrib._element.isNormalized(); + + GLenum perLocationSize = attrib._element.getLocationSize(); + + for (size_t locNum = 0; locNum < locationCount; ++locNum) { + newActivation.set(slot + locNum); + glVertexAttribFormat(slot + locNum, count, type, isNormalized, offset + locNum * perLocationSize); + glVertexAttribBinding(slot + locNum, attrib._channel); + } + glVertexBindingDivisor(attrib._channel, attrib._frequency); + } + (void)CHECK_GL_ERROR(); + } + + // Manage Activation what was and what is expected now + for (size_t i = 0; i < newActivation.size(); i++) { + bool newState = newActivation[i]; + if (newState != _input._attributeActivation[i]) { + if (newState) { + glEnableVertexAttribArray(i); + } else { + glDisableVertexAttribArray(i); + } + _input._attributeActivation.flip(i); + } + } + (void)CHECK_GL_ERROR(); + + _input._invalidFormat = false; + _stats._ISNumFormatChanges++; + } + + if (_input._invalidBuffers.any()) { + int numBuffers = _input._buffers.size(); + auto buffer = _input._buffers.data(); + auto vbo = _input._bufferVBOs.data(); + auto offset = _input._bufferOffsets.data(); + auto stride = _input._bufferStrides.data(); + + for (int bufferNum = 0; bufferNum < numBuffers; bufferNum++) { + if (_input._invalidBuffers.test(bufferNum)) { + glBindVertexBuffer(bufferNum, (*vbo), (*offset), (*stride)); + } + buffer++; + vbo++; + offset++; + stride++; + } + _input._invalidBuffers.reset(); + (void)CHECK_GL_ERROR(); + } +#else + if (_input._invalidFormat || _input._invalidBuffers.any()) { + + if (_input._invalidFormat) { + InputStageState::ActivationCache newActivation; + + _stats._ISNumFormatChanges++; + + // Check expected activation + if (_input._format) { + for (auto& it : _input._format->getAttributes()) { + const Stream::Attribute& attrib = (it).second; + uint8_t locationCount = attrib._element.getLocationCount(); + for (int i = 0; i < locationCount; ++i) { + newActivation.set(attrib._slot + i); + } + } + } + + // Manage Activation what was and what is expected now + for (unsigned int i = 0; i < newActivation.size(); i++) { + bool newState = newActivation[i]; + if (newState != _input._attributeActivation[i]) { + + if (newState) { + glEnableVertexAttribArray(i); + } else { + glDisableVertexAttribArray(i); + } + (void)CHECK_GL_ERROR(); + + _input._attributeActivation.flip(i); + } + } + } + + // now we need to bind the buffers and assign the attrib pointers + if (_input._format) { + const Buffers& buffers = _input._buffers; + const Offsets& offsets = _input._bufferOffsets; + const Offsets& strides = _input._bufferStrides; + + const Stream::Format::AttributeMap& attributes = _input._format->getAttributes(); + auto& inputChannels = _input._format->getChannels(); + _stats._ISNumInputBufferChanges++; + + GLuint boundVBO = 0; + for (auto& channelIt : inputChannels) { + const Stream::Format::ChannelMap::value_type::second_type& channel = (channelIt).second; + if ((channelIt).first < buffers.size()) { + int bufferNum = (channelIt).first; + + if (_input._invalidBuffers.test(bufferNum) || _input._invalidFormat) { + // GLuint vbo = gpu::GL41Backend::getBufferID((*buffers[bufferNum])); + GLuint vbo = _input._bufferVBOs[bufferNum]; + if (boundVBO != vbo) { + glBindBuffer(GL_ARRAY_BUFFER, vbo); + (void)CHECK_GL_ERROR(); + boundVBO = vbo; + } + _input._invalidBuffers[bufferNum] = false; + + for (unsigned int i = 0; i < channel._slots.size(); i++) { + const Stream::Attribute& attrib = attributes.at(channel._slots[i]); + GLuint slot = attrib._slot; + GLuint count = attrib._element.getLocationScalarCount(); + uint8_t locationCount = attrib._element.getLocationCount(); + GLenum type = gl::ELEMENT_TYPE_TO_GL[attrib._element.getType()]; + // GLenum perLocationStride = strides[bufferNum]; + GLenum perLocationStride = attrib._element.getLocationSize(); + GLuint stride = (GLuint)strides[bufferNum]; + GLuint pointer = (GLuint)(attrib._offset + offsets[bufferNum]); + GLboolean isNormalized = attrib._element.isNormalized(); + + for (size_t locNum = 0; locNum < locationCount; ++locNum) { + glVertexAttribPointer(slot + (GLuint)locNum, count, type, isNormalized, stride, + reinterpret_cast(pointer + perLocationStride * (GLuint)locNum)); + glVertexAttribDivisor(slot + (GLuint)locNum, attrib._frequency); + } + + // TODO: Support properly the IAttrib version + + (void)CHECK_GL_ERROR(); + } + } + } + } + } + // everything format related should be in sync now + _input._invalidFormat = false; + } +#endif +} + diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp index 1b0caa7345..d3e86de606 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp @@ -13,173 +13,7 @@ using namespace gpu; using namespace gpu::gl41; -// Core 41 doesn't expose the features to really separate the vertex format from the vertex buffers binding -// Core 43 does :) -// FIXME crashing problem with glVertexBindingDivisor / glVertexAttribFormat -#if 1 || (GPU_INPUT_PROFILE == GPU_CORE_41) -#define NO_SUPPORT_VERTEX_ATTRIB_FORMAT -#else -#define SUPPORT_VERTEX_ATTRIB_FORMAT -#endif - void GL41Backend::updateInput() { -#if defined(SUPPORT_VERTEX_ATTRIB_FORMAT) - if (_input._invalidFormat) { - - InputStageState::ActivationCache newActivation; - - // Assign the vertex format required - if (_input._format) { - for (auto& it : _input._format->getAttributes()) { - const Stream::Attribute& attrib = (it).second; - - GLuint slot = attrib._slot; - GLuint count = attrib._element.getLocationScalarCount(); - uint8_t locationCount = attrib._element.getLocationCount(); - GLenum type = _elementTypeToGL41Type[attrib._element.getType()]; - GLuint offset = attrib._offset;; - GLboolean isNormalized = attrib._element.isNormalized(); - - GLenum perLocationSize = attrib._element.getLocationSize(); - - for (size_t locNum = 0; locNum < locationCount; ++locNum) { - newActivation.set(slot + locNum); - glVertexAttribFormat(slot + locNum, count, type, isNormalized, offset + locNum * perLocationSize); - glVertexAttribBinding(slot + locNum, attrib._channel); - } - glVertexBindingDivisor(attrib._channel, attrib._frequency); - } - (void) CHECK_GL_ERROR(); - } - - // Manage Activation what was and what is expected now - for (size_t i = 0; i < newActivation.size(); i++) { - bool newState = newActivation[i]; - if (newState != _input._attributeActivation[i]) { - if (newState) { - glEnableVertexAttribArray(i); - } else { - glDisableVertexAttribArray(i); - } - _input._attributeActivation.flip(i); - } - } - (void) CHECK_GL_ERROR(); - - _input._invalidFormat = false; - _stats._ISNumFormatChanges++; - } - - if (_input._invalidBuffers.any()) { - int numBuffers = _input._buffers.size(); - auto buffer = _input._buffers.data(); - auto vbo = _input._bufferVBOs.data(); - auto offset = _input._bufferOffsets.data(); - auto stride = _input._bufferStrides.data(); - - for (int bufferNum = 0; bufferNum < numBuffers; bufferNum++) { - if (_input._invalidBuffers.test(bufferNum)) { - glBindVertexBuffer(bufferNum, (*vbo), (*offset), (*stride)); - } - buffer++; - vbo++; - offset++; - stride++; - } - _input._invalidBuffers.reset(); - (void) CHECK_GL_ERROR(); - } -#else - if (_input._invalidFormat || _input._invalidBuffers.any()) { - - if (_input._invalidFormat) { - InputStageState::ActivationCache newActivation; - - _stats._ISNumFormatChanges++; - - // Check expected activation - if (_input._format) { - for (auto& it : _input._format->getAttributes()) { - const Stream::Attribute& attrib = (it).second; - uint8_t locationCount = attrib._element.getLocationCount(); - for (int i = 0; i < locationCount; ++i) { - newActivation.set(attrib._slot + i); - } - } - } - - // Manage Activation what was and what is expected now - for (unsigned int i = 0; i < newActivation.size(); i++) { - bool newState = newActivation[i]; - if (newState != _input._attributeActivation[i]) { - - if (newState) { - glEnableVertexAttribArray(i); - } else { - glDisableVertexAttribArray(i); - } - (void) CHECK_GL_ERROR(); - - _input._attributeActivation.flip(i); - } - } - } - - // now we need to bind the buffers and assign the attrib pointers - if (_input._format) { - const Buffers& buffers = _input._buffers; - const Offsets& offsets = _input._bufferOffsets; - const Offsets& strides = _input._bufferStrides; - - const Stream::Format::AttributeMap& attributes = _input._format->getAttributes(); - auto& inputChannels = _input._format->getChannels(); - _stats._ISNumInputBufferChanges++; - - GLuint boundVBO = 0; - for (auto& channelIt : inputChannels) { - const Stream::Format::ChannelMap::value_type::second_type& channel = (channelIt).second; - if ((channelIt).first < buffers.size()) { - int bufferNum = (channelIt).first; - - if (_input._invalidBuffers.test(bufferNum) || _input._invalidFormat) { - // GLuint vbo = gpu::GL41Backend::getBufferID((*buffers[bufferNum])); - GLuint vbo = _input._bufferVBOs[bufferNum]; - if (boundVBO != vbo) { - glBindBuffer(GL_ARRAY_BUFFER, vbo); - (void) CHECK_GL_ERROR(); - boundVBO = vbo; - } - _input._invalidBuffers[bufferNum] = false; - - for (unsigned int i = 0; i < channel._slots.size(); i++) { - const Stream::Attribute& attrib = attributes.at(channel._slots[i]); - GLuint slot = attrib._slot; - GLuint count = attrib._element.getLocationScalarCount(); - uint8_t locationCount = attrib._element.getLocationCount(); - GLenum type = gl::ELEMENT_TYPE_TO_GL[attrib._element.getType()]; - // GLenum perLocationStride = strides[bufferNum]; - GLenum perLocationStride = attrib._element.getLocationSize(); - GLuint stride = (GLuint)strides[bufferNum]; - GLuint pointer = (GLuint)(attrib._offset + offsets[bufferNum]); - GLboolean isNormalized = attrib._element.isNormalized(); - - for (size_t locNum = 0; locNum < locationCount; ++locNum) { - glVertexAttribPointer(slot + (GLuint)locNum, count, type, isNormalized, stride, - reinterpret_cast(pointer + perLocationStride * (GLuint)locNum)); - glVertexAttribDivisor(slot + (GLuint)locNum, attrib._frequency); - } - - // TODO: Support properly the IAttrib version - - (void) CHECK_GL_ERROR(); - } - } - } - } - } - // everything format related should be in sync now - _input._invalidFormat = false; - } -#endif + Parent::updateInput(); } diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendQuery.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendQuery.cpp index 3c6109bbdf..478d210535 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendQuery.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendQuery.cpp @@ -16,7 +16,7 @@ using namespace gpu; using namespace gpu::gl41; class GL41Query : public gpu::gl::GLQuery { - using Parent = gpu::gl::GLBuffer; + using Parent = gpu::gl::GLQuery; public: static GLuint allocateQuery() { GLuint result; @@ -25,7 +25,7 @@ public: } GL41Query(const Query& query) - : gl::GLQuery(query, allocateQuery()) { } + : Parent(query, allocateQuery()) { } }; gl::GLQuery* GL41Backend::syncGPUObject(const Query& query) { diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp new file mode 100644 index 0000000000..bb6ae67233 --- /dev/null +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp @@ -0,0 +1,149 @@ +// +// Created by Sam Gateau on 10/27/2014. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GL45Backend.h" + +#include +#include +#include +#include +#include + +Q_LOGGING_CATEGORY(gpugl45logging, "hifi.gpu.gl45") + +using namespace gpu; +using namespace gpu::gl45; + +void GL45Backend::do_draw(Batch& batch, size_t paramOffset) { + Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; + GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType]; + uint32 numVertices = batch._params[paramOffset + 1]._uint; + uint32 startVertex = batch._params[paramOffset + 0]._uint; + + if (isStereo()) { + setupStereoSide(0); + glDrawArrays(mode, startVertex, numVertices); + setupStereoSide(1); + glDrawArrays(mode, startVertex, numVertices); + + _stats._DSNumTriangles += 2 * numVertices / 3; + _stats._DSNumDrawcalls += 2; + + } else { + glDrawArrays(mode, startVertex, numVertices); + _stats._DSNumTriangles += numVertices / 3; + _stats._DSNumDrawcalls++; + } + _stats._DSNumAPIDrawcalls++; + + (void) CHECK_GL_ERROR(); +} + +void GL45Backend::do_drawIndexed(Batch& batch, size_t paramOffset) { + Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; + GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType]; + uint32 numIndices = batch._params[paramOffset + 1]._uint; + uint32 startIndex = batch._params[paramOffset + 0]._uint; + + GLenum glType = gl::ELEMENT_TYPE_TO_GL[_input._indexBufferType]; + + auto typeByteSize = TYPE_SIZE[_input._indexBufferType]; + GLvoid* indexBufferByteOffset = reinterpret_cast(startIndex * typeByteSize + _input._indexBufferOffset); + + if (isStereo()) { + setupStereoSide(0); + glDrawElements(mode, numIndices, glType, indexBufferByteOffset); + setupStereoSide(1); + glDrawElements(mode, numIndices, glType, indexBufferByteOffset); + + _stats._DSNumTriangles += 2 * numIndices / 3; + _stats._DSNumDrawcalls += 2; + } else { + glDrawElements(mode, numIndices, glType, indexBufferByteOffset); + _stats._DSNumTriangles += numIndices / 3; + _stats._DSNumDrawcalls++; + } + _stats._DSNumAPIDrawcalls++; + + (void) CHECK_GL_ERROR(); +} + +void GL45Backend::do_drawInstanced(Batch& batch, size_t paramOffset) { + GLint numInstances = batch._params[paramOffset + 4]._uint; + Primitive primitiveType = (Primitive)batch._params[paramOffset + 3]._uint; + GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType]; + uint32 numVertices = batch._params[paramOffset + 2]._uint; + uint32 startVertex = batch._params[paramOffset + 1]._uint; + + + if (isStereo()) { + GLint trueNumInstances = 2 * numInstances; + + setupStereoSide(0); + glDrawArraysInstanced(mode, startVertex, numVertices, numInstances); + setupStereoSide(1); + glDrawArraysInstanced(mode, startVertex, numVertices, numInstances); + + _stats._DSNumTriangles += (trueNumInstances * numVertices) / 3; + _stats._DSNumDrawcalls += trueNumInstances; + } else { + glDrawArraysInstanced(mode, startVertex, numVertices, numInstances); + _stats._DSNumTriangles += (numInstances * numVertices) / 3; + _stats._DSNumDrawcalls += numInstances; + } + _stats._DSNumAPIDrawcalls++; + + (void) CHECK_GL_ERROR(); +} + +void GL45Backend::do_drawIndexedInstanced(Batch& batch, size_t paramOffset) { + GLint numInstances = batch._params[paramOffset + 4]._uint; + GLenum mode = gl::PRIMITIVE_TO_GL[(Primitive)batch._params[paramOffset + 3]._uint]; + uint32 numIndices = batch._params[paramOffset + 2]._uint; + uint32 startIndex = batch._params[paramOffset + 1]._uint; + uint32 startInstance = batch._params[paramOffset + 0]._uint; + GLenum glType = gl::ELEMENT_TYPE_TO_GL[_input._indexBufferType]; + auto typeByteSize = TYPE_SIZE[_input._indexBufferType]; + GLvoid* indexBufferByteOffset = reinterpret_cast(startIndex * typeByteSize + _input._indexBufferOffset); + + if (isStereo()) { + GLint trueNumInstances = 2 * numInstances; + setupStereoSide(0); + glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, indexBufferByteOffset, numInstances, 0, startInstance); + setupStereoSide(1); + glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, indexBufferByteOffset, numInstances, 0, startInstance); + _stats._DSNumTriangles += (trueNumInstances * numIndices) / 3; + _stats._DSNumDrawcalls += trueNumInstances; + } else { + glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, indexBufferByteOffset, numInstances, 0, startInstance); + _stats._DSNumTriangles += (numInstances * numIndices) / 3; + _stats._DSNumDrawcalls += numInstances; + } + + _stats._DSNumAPIDrawcalls++; + + (void)CHECK_GL_ERROR(); +} + +void GL45Backend::do_multiDrawIndirect(Batch& batch, size_t paramOffset) { + uint commandCount = batch._params[paramOffset + 0]._uint; + GLenum mode = gl::PRIMITIVE_TO_GL[(Primitive)batch._params[paramOffset + 1]._uint]; + glMultiDrawArraysIndirect(mode, reinterpret_cast(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride); + _stats._DSNumDrawcalls += commandCount; + _stats._DSNumAPIDrawcalls++; + (void)CHECK_GL_ERROR(); +} + +void GL45Backend::do_multiDrawIndexedIndirect(Batch& batch, size_t paramOffset) { + uint commandCount = batch._params[paramOffset + 0]._uint; + GLenum mode = gl::PRIMITIVE_TO_GL[(Primitive)batch._params[paramOffset + 1]._uint]; + GLenum indexType = gl::ELEMENT_TYPE_TO_GL[_input._indexBufferType]; + glMultiDrawElementsIndirect(mode, indexType, reinterpret_cast(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride); + _stats._DSNumDrawcalls += commandCount; + _stats._DSNumAPIDrawcalls++; + (void)CHECK_GL_ERROR(); +} diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h new file mode 100644 index 0000000000..d0dfbd0e41 --- /dev/null +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -0,0 +1,85 @@ +// +// GL45Backend.h +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 10/27/2014. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_45_GL45Backend_h +#define hifi_gpu_45_GL45Backend_h + +#include "../gl/GLBackend.h" +#include "../gl/GLTexture.h" + +namespace gpu { namespace gl45 { + +class GL45Backend : public gl::GLBackend { + using Parent = gl::GLBackend; + // Context Backend static interface required + friend class Context; + +public: + explicit GL45Backend(bool syncCache) : Parent(syncCache) {} + GL45Backend() : Parent() {} + + class GL45Texture : public gpu::gl::GLTexture { + using Parent = gpu::gl::GLTexture; + GLuint allocate(const Texture& texture); + public: + GL45Texture(const Texture& texture, bool transferrable); + GL45Texture(const Texture& texture, GLTexture* original); + + protected: + void transferMip(uint16_t mipLevel, uint8_t face = 0) const; + void allocateStorage() const override; + void updateSize() const override; + void transfer() const override; + void syncSampler() const override; + void generateMips() const override; + void withPreservedTexture(std::function f) const override; + }; + + +protected: + GLuint getFramebufferID(const FramebufferPointer& framebuffer) override; + gl::GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override; + + GLuint getBufferID(const Buffer& buffer) override; + gl::GLBuffer* syncGPUObject(const Buffer& buffer) override; + + GLuint getTextureID(const TexturePointer& texture, bool needTransfer = true) override; + gl::GLTexture* syncGPUObject(const TexturePointer& texture, bool sync = true) override; + + GLuint getQueryID(const QueryPointer& query) override; + gl::GLQuery* syncGPUObject(const Query& query) override; + + // Draw Stage + void do_draw(Batch& batch, size_t paramOffset) override; + void do_drawIndexed(Batch& batch, size_t paramOffset) override; + void do_drawInstanced(Batch& batch, size_t paramOffset) override; + void do_drawIndexedInstanced(Batch& batch, size_t paramOffset) override; + void do_multiDrawIndirect(Batch& batch, size_t paramOffset) override; + void do_multiDrawIndexedIndirect(Batch& batch, size_t paramOffset) override; + + // Input Stage + void updateInput() override; + + // Synchronize the state cache of this Backend with the actual real state of the GL Context + void transferTransformState(const Batch& batch) const override; + void initTransform() override; + void updateTransform(const Batch& batch); + void resetTransformStage(); + + // Output stage + void do_blit(Batch& batch, size_t paramOffset) override; +}; + +} } + +Q_DECLARE_LOGGING_CATEGORY(gpugl45logging) + + +#endif diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendBuffer.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendBuffer.cpp new file mode 100644 index 0000000000..1676b0ce1c --- /dev/null +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendBuffer.cpp @@ -0,0 +1,50 @@ +// +// Created by Bradley Austin Davis on 2016/05/15 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GL45Backend.h" +#include "../gl/GLBuffer.h" + +using namespace gpu; +using namespace gpu::gl45; + +class GL45Buffer : public gl::GLBuffer { + using Parent = gpu::gl::GLBuffer; + static GLuint allocate() { + GLuint result; + glCreateBuffers(1, &result); + return result; + } + +public: + GL45Buffer(const Buffer& buffer, GLBuffer* original) : Parent(buffer, allocate()) { + glNamedBufferStorage(_buffer, _size, nullptr, GL_DYNAMIC_STORAGE_BIT); + if (original && original->_size) { + glCopyNamedBufferSubData(original->_buffer, _buffer, 0, 0, std::min(original->_size, _size)); + } + Backend::setGPUObject(buffer, this); + } + + void transfer() override { + Size offset; + Size size; + Size currentPage { 0 }; + auto data = _gpuObject.getSysmem().readData(); + while (_gpuObject.getNextTransferBlock(offset, size, currentPage)) { + glNamedBufferSubData(_buffer, (GLintptr)offset, (GLsizeiptr)size, data + offset); + } + (void)CHECK_GL_ERROR(); + _gpuObject._flags &= ~Buffer::DIRTY; + } +}; + +GLuint GL45Backend::getBufferID(const Buffer& buffer) { + return GL45Buffer::getId(buffer); +} + +gl::GLBuffer* GL45Backend::syncGPUObject(const Buffer& buffer) { + return GL45Buffer::sync(buffer); +} diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp new file mode 100644 index 0000000000..b578d7d7a8 --- /dev/null +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp @@ -0,0 +1,18 @@ +// +// GL45BackendInput.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 3/8/2015. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GL45Backend.h" + +using namespace gpu; +using namespace gpu::gl45; + +void GL45Backend::updateInput() { + Parent::updateInput(); +} diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendOutput.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendOutput.cpp new file mode 100644 index 0000000000..b846dd4df3 --- /dev/null +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendOutput.cpp @@ -0,0 +1,145 @@ +// +// GL45BackendTexture.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 1/19/2015. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GL45Backend.h" +#include "../gl/GLFramebuffer.h" +#include "../gl/GLTexture.h" + +#include + +namespace gpu { namespace gl45 { + +class GL45Framebuffer : public gl::GLFramebuffer { + using Parent = gl::GLFramebuffer; + static GLuint allocate() { + GLuint result; + glCreateFramebuffers(1, &result); + return result; + } +public: + void update() override { + gl::GLTexture* gltexture = nullptr; + TexturePointer surface; + if (_gpuObject.getColorStamps() != _colorStamps) { + if (_gpuObject.hasColor()) { + _colorBuffers.clear(); + static const GLenum colorAttachments[] = { + GL_COLOR_ATTACHMENT0, + GL_COLOR_ATTACHMENT1, + GL_COLOR_ATTACHMENT2, + GL_COLOR_ATTACHMENT3, + GL_COLOR_ATTACHMENT4, + GL_COLOR_ATTACHMENT5, + GL_COLOR_ATTACHMENT6, + GL_COLOR_ATTACHMENT7, + GL_COLOR_ATTACHMENT8, + GL_COLOR_ATTACHMENT9, + GL_COLOR_ATTACHMENT10, + GL_COLOR_ATTACHMENT11, + GL_COLOR_ATTACHMENT12, + GL_COLOR_ATTACHMENT13, + GL_COLOR_ATTACHMENT14, + GL_COLOR_ATTACHMENT15 }; + + int unit = 0; + for (auto& b : _gpuObject.getRenderBuffers()) { + surface = b._texture; + if (surface) { + gltexture = gl::GLTexture::sync(surface, false); // Grab the gltexture and don't transfer + } else { + gltexture = nullptr; + } + + if (gltexture) { + glNamedFramebufferTexture(_id, colorAttachments[unit], gltexture->_texture, 0); + _colorBuffers.push_back(colorAttachments[unit]); + } else { + glNamedFramebufferTexture(_id, colorAttachments[unit], 0, 0); + } + unit++; + } + } + _colorStamps = _gpuObject.getColorStamps(); + } + + GLenum attachement = GL_DEPTH_STENCIL_ATTACHMENT; + if (!_gpuObject.hasStencil()) { + attachement = GL_DEPTH_ATTACHMENT; + } else if (!_gpuObject.hasDepth()) { + attachement = GL_STENCIL_ATTACHMENT; + } + + if (_gpuObject.getDepthStamp() != _depthStamp) { + auto surface = _gpuObject.getDepthStencilBuffer(); + if (_gpuObject.hasDepthStencil() && surface) { + gltexture = gl::GLTexture::sync(surface, false); // Grab the gltexture and don't transfer + } + + if (gltexture) { + glNamedFramebufferTexture(_id, attachement, gltexture->_texture, 0); + } else { + glNamedFramebufferTexture(_id, attachement, 0, 0); + } + _depthStamp = _gpuObject.getDepthStamp(); + } + + + // Last but not least, define where we draw + if (!_colorBuffers.empty()) { + glNamedFramebufferDrawBuffers(_id, (GLsizei)_colorBuffers.size(), _colorBuffers.data()); + } else { + glNamedFramebufferDrawBuffer(_id, GL_NONE); + } + + // Now check for completness + _status = glCheckNamedFramebufferStatus(_id, GL_DRAW_FRAMEBUFFER); + + // restore the current framebuffer + checkStatus(GL_DRAW_FRAMEBUFFER); + } + + +public: + GL45Framebuffer(const gpu::Framebuffer& framebuffer) + : Parent(framebuffer, allocate()) { } +}; + +gl::GLFramebuffer* GL45Backend::syncGPUObject(const Framebuffer& framebuffer) { + return gl::GLFramebuffer::sync(framebuffer); +} + +GLuint GL45Backend::getFramebufferID(const FramebufferPointer& framebuffer) { + return framebuffer ? gl::GLFramebuffer::getId(*framebuffer) : 0; +} + +void GL45Backend::do_blit(Batch& batch, size_t paramOffset) { + auto srcframebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint); + Vec4i srcvp; + for (auto i = 0; i < 4; ++i) { + srcvp[i] = batch._params[paramOffset + 1 + i]._int; + } + + auto dstframebuffer = batch._framebuffers.get(batch._params[paramOffset + 5]._uint); + Vec4i dstvp; + for (auto i = 0; i < 4; ++i) { + dstvp[i] = batch._params[paramOffset + 6 + i]._int; + } + + // Assign dest framebuffer if not bound already + auto destFbo = getFramebufferID(dstframebuffer); + auto srcFbo = getFramebufferID(srcframebuffer); + glBlitNamedFramebuffer(srcFbo, destFbo, + srcvp.x, srcvp.y, srcvp.z, srcvp.w, + dstvp.x, dstvp.y, dstvp.z, dstvp.w, + GL_COLOR_BUFFER_BIT, GL_LINEAR); + (void) CHECK_GL_ERROR(); +} + +} } diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendQuery.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendQuery.cpp new file mode 100644 index 0000000000..a7a7c26bed --- /dev/null +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendQuery.cpp @@ -0,0 +1,38 @@ +// +// GL45BackendQuery.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 7/7/2015. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GL45Backend.h" + +#include "../gl/GLQuery.h" + +namespace gpu { namespace gl45 { + +class GL45Query : public gpu::gl::GLQuery { + using Parent = gpu::gl::GLQuery; +public: + static GLuint allocateQuery() { + GLuint result; + glCreateQueries(GL_TIME_ELAPSED, 1, &result); + return result; + } + + GL45Query(const Query& query) + : Parent(query, allocateQuery()) { } +}; + +gl::GLQuery* GL45Backend::syncGPUObject(const Query& query) { + return GL45Query::sync(query); +} + +GLuint GL45Backend::getQueryID(const QueryPointer& query) { + return GL45Query::getId(query); +} + +} } \ No newline at end of file diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp new file mode 100644 index 0000000000..36fb4bfde3 --- /dev/null +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -0,0 +1,181 @@ +// +// GL45BackendTexture.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 1/19/2015. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GL45Backend.h" + +#include +#include +#include + +#include "../gl/GLTexelFormat.h" + +using namespace gpu; +using namespace gpu::gl45; + +using GLTexelFormat = gl::GLTexelFormat; +using GL45Texture = GL45Backend::GL45Texture; + +GLuint GL45Texture::allocate(const Texture& texture) { + Backend::incrementTextureGPUCount(); + GLuint result; + glCreateTextures(getGLTextureType(texture), 1, &result); + return result; +} + +GLuint GL45Backend::getTextureID(const TexturePointer& texture, bool transfer) { + return GL45Texture::getId(texture, transfer); +} + +gl::GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texture, bool transfer) { + return GL45Texture::sync(texture, transfer); +} + +GL45Backend::GL45Texture::GL45Texture(const Texture& texture, bool transferrable) + : gl::GLTexture(texture, allocate(texture), transferrable) {} + +GL45Backend::GL45Texture::GL45Texture(const Texture& texture, GLTexture* original) + : gl::GLTexture(texture, allocate(texture), original) {} + +void GL45Backend::GL45Texture::withPreservedTexture(std::function f) const { + f(); +} + +void GL45Backend::GL45Texture::generateMips() const { + glGenerateTextureMipmap(_id); + (void)CHECK_GL_ERROR(); +} + +void GL45Backend::GL45Texture::allocateStorage() const { + gl::GLTexelFormat texelFormat = gl::GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat()); + glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0); + glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip); + if (_gpuObject.getTexelFormat().isCompressed()) { + qFatal("Compressed textures not yet supported"); + } + // Get the dimensions, accounting for the downgrade level + Vec3u dimensions = _gpuObject.evalMipDimensions(_minMip); + glTextureStorage2D(_id, usedMipLevels(), texelFormat.internalFormat, dimensions.x, dimensions.y); + (void)CHECK_GL_ERROR(); +} + +void GL45Backend::GL45Texture::updateSize() const { + setSize(_virtualSize); + if (!_id) { + return; + } + + if (_gpuObject.getTexelFormat().isCompressed()) { + qFatal("Compressed textures not yet supported"); + } +} + +// Move content bits from the CPU to the GPU for a given mip / face +void GL45Backend::GL45Texture::transferMip(uint16_t mipLevel, uint8_t face) const { + auto mip = _gpuObject.accessStoredMipFace(mipLevel, face); + gl::GLTexelFormat texelFormat = gl::GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mip->getFormat()); + auto size = _gpuObject.evalMipDimensions(mipLevel); + if (GL_TEXTURE_2D == _target) { + glTextureSubImage2D(_id, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData()); + } else if (GL_TEXTURE_CUBE_MAP == _target) { + glTextureSubImage3D(_id, mipLevel, 0, 0, face, size.x, size.y, 1, texelFormat.format, texelFormat.type, mip->readData()); + } else { + Q_ASSERT(false); + } + (void)CHECK_GL_ERROR(); +} + +// This should never happen on the main thread +// Move content bits from the CPU to the GPU +void GL45Backend::GL45Texture::transfer() const { + PROFILE_RANGE(__FUNCTION__); + //qDebug() << "Transferring texture: " << _privateTexture; + // Need to update the content of the GPU object from the source sysmem of the texture + if (_contentStamp >= _gpuObject.getDataStamp()) { + return; + } + + if (_downsampleSource._texture) { + GLuint fbo { 0 }; + glCreateFramebuffers(1, &fbo); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); + // Find the distance between the old min mip and the new one + uint16 mipOffset = _minMip - _downsampleSource._minMip; + for (uint16 i = _minMip; i <= _maxMip; ++i) { + uint16 targetMip = i - _minMip; + uint16 sourceMip = targetMip + mipOffset; + Vec3u dimensions = _gpuObject.evalMipDimensions(i); + for (GLenum target : getFaceTargets(_target)) { + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, _downsampleSource._texture, sourceMip); + (void)CHECK_GL_ERROR(); + glCopyTextureSubImage2D(_id, targetMip, 0, 0, 0, 0, dimensions.x, dimensions.y); + (void)CHECK_GL_ERROR(); + } + } + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &fbo); + } else { + // GO through the process of allocating the correct storage and/or update the content + switch (_gpuObject.getType()) { + case Texture::TEX_2D: + { + for (uint16_t i = _minMip; i <= _maxMip; ++i) { + if (_gpuObject.isStoredMipFaceAvailable(i)) { + transferMip(i); + } + } + } + break; + + case Texture::TEX_CUBE: + // transfer pixels from each faces + for (uint8_t f = 0; f < CUBE_NUM_FACES; f++) { + for (uint16_t i = 0; i < Sampler::MAX_MIP_LEVEL; ++i) { + if (_gpuObject.isStoredMipFaceAvailable(i, f)) { + transferMip(i, f); + } + } + } + break; + + default: + qCWarning(gpugl45logging) << __FUNCTION__ << " case for Texture Type " << _gpuObject.getType() << " not supported"; + break; + } + } + if (_gpuObject.isAutogenerateMips()) { + glGenerateTextureMipmap(_id); + (void)CHECK_GL_ERROR(); + } +} + +void GL45Backend::GL45Texture::syncSampler() const { + const Sampler& sampler = _gpuObject.getSampler(); + + const auto& fm = FILTER_MODES[sampler.getFilter()]; + glTextureParameteri(_id, GL_TEXTURE_MIN_FILTER, fm.minFilter); + glTextureParameteri(_id, GL_TEXTURE_MAG_FILTER, fm.magFilter); + + if (sampler.doComparison()) { + glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + glTextureParameteri(_id, GL_TEXTURE_COMPARE_FUNC, gl::COMPARISON_TO_GL[sampler.getComparisonFunction()]); + } else { + glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_NONE); + } + + glTextureParameteri(_id, GL_TEXTURE_WRAP_S, WRAP_MODES[sampler.getWrapModeU()]); + glTextureParameteri(_id, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]); + glTextureParameteri(_id, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]); + glTextureParameterfv(_id, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); + glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, (uint16)sampler.getMipOffset()); + glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip()); + glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); + glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); +} + diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTransform.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTransform.cpp new file mode 100644 index 0000000000..96afb4cc71 --- /dev/null +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTransform.cpp @@ -0,0 +1,71 @@ +// +// GL45BackendTransform.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 3/8/2015. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GL45Backend.h" + +using namespace gpu; +using namespace gpu::gl45; + +void GL45Backend::initTransform() { + GLuint transformBuffers[3]; + glCreateBuffers(3, transformBuffers); + _transform._objectBuffer = transformBuffers[0]; + _transform._cameraBuffer = transformBuffers[1]; + _transform._drawCallInfoBuffer = transformBuffers[2]; + glCreateTextures(GL_TEXTURE_BUFFER, 1, &_transform._objectBufferTexture); + size_t cameraSize = sizeof(TransformStageState::CameraBufferElement); + while (_transform._cameraUboSize < cameraSize) { + _transform._cameraUboSize += _uboAlignment; + } +} + +void GL45Backend::transferTransformState(const Batch& batch) const { + // FIXME not thread safe + static std::vector bufferData; + if (!_transform._cameras.empty()) { + bufferData.resize(_transform._cameraUboSize * _transform._cameras.size()); + for (size_t i = 0; i < _transform._cameras.size(); ++i) { + memcpy(bufferData.data() + (_transform._cameraUboSize * i), &_transform._cameras[i], sizeof(TransformStageState::CameraBufferElement)); + } + glNamedBufferData(_transform._cameraBuffer, bufferData.size(), bufferData.data(), GL_STREAM_DRAW); + } + + if (!batch._objects.empty()) { + auto byteSize = batch._objects.size() * sizeof(Batch::TransformObject); + bufferData.resize(byteSize); + memcpy(bufferData.data(), batch._objects.data(), byteSize); + glNamedBufferData(_transform._objectBuffer, bufferData.size(), bufferData.data(), GL_STREAM_DRAW); + } + + if (!batch._namedData.empty()) { + bufferData.clear(); + for (auto& data : batch._namedData) { + auto currentSize = bufferData.size(); + auto bytesToCopy = data.second.drawCallInfos.size() * sizeof(Batch::DrawCallInfo); + bufferData.resize(currentSize + bytesToCopy); + memcpy(bufferData.data() + currentSize, data.second.drawCallInfos.data(), bytesToCopy); + _transform._drawCallInfoOffsets[data.first] = (GLvoid*)currentSize; + } + glNamedBufferData(_transform._drawCallInfoBuffer, bufferData.size(), bufferData.data(), GL_STREAM_DRAW); + } + +#ifdef GPU_SSBO_DRAW_CALL_INFO + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, TRANSFORM_OBJECT_SLOT, _transform._objectBuffer); +#else + glTextureBuffer(_transform._objectBufferTexture, GL_RGBA32F, _transform._objectBuffer); + glActiveTexture(GL_TEXTURE0 + TRANSFORM_OBJECT_SLOT); + glBindTexture(GL_TEXTURE_BUFFER, _transform._objectBufferTexture); +#endif + + CHECK_GL_ERROR(); + + // Make sure the current Camera offset is unknown before render Draw + _transform._currentCameraOffset = INVALID_OFFSET; +} diff --git a/libraries/gpu/src/gpu/null/NullBackend.h b/libraries/gpu/src/gpu/null/NullBackend.h new file mode 100644 index 0000000000..097cee27e7 --- /dev/null +++ b/libraries/gpu/src/gpu/null/NullBackend.h @@ -0,0 +1,54 @@ +// +// Created by Bradley Austin Davis on 2016/05/16 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_Null_Backend_h +#define hifi_gpu_Null_Backend_h + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../Context.h" + +namespace gpu { namespace null { + +class Backend : public gpu::Backend { + using Parent = gpu::Backend; + // Context Backend static interface required + friend class gpu::Context; + static void init() {} + static gpu::Backend* createBackend() { return new Backend(); } + static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings) { return true; } + +protected: + explicit Backend(bool syncCache) : Parent() { } + Backend() : Parent() { } +public: + ~Backend() { } + + void render(Batch& batch) final { } + + // This call synchronize the Full Backend cache with the current GLState + // THis is only intended to be used when mixing raw gl calls with the gpu api usage in order to sync + // the gpu::Backend state with the true gl state which has probably been messed up by these ugly naked gl calls + // Let's try to avoid to do that as much as possible! + void syncCache() final { } + + // This is the ugly "download the pixels to sysmem for taking a snapshot" + // Just avoid using it, it's ugly and will break performances + virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) final { } +}; + +} } + +#endif diff --git a/libraries/networking/src/NetworkingConstants.h b/libraries/networking/src/NetworkingConstants.h index a512ae8887..981d5a7b3a 100644 --- a/libraries/networking/src/NetworkingConstants.h +++ b/libraries/networking/src/NetworkingConstants.h @@ -15,7 +15,8 @@ #include namespace NetworkingConstants { - const QUrl METAVERSE_SERVER_URL = QUrl("https://metaverse.highfidelity.com"); + // const QUrl METAVERSE_SERVER_URL = QUrl("https://metaverse.highfidelity.com"); + const QUrl METAVERSE_SERVER_URL = QUrl("http://localhost:3000"); } #endif // hifi_NetworkingConstants_h diff --git a/libraries/shared/src/NumericalConstants.h b/libraries/shared/src/NumericalConstants.h index ca18d8ad5e..d37e1e31c5 100644 --- a/libraries/shared/src/NumericalConstants.h +++ b/libraries/shared/src/NumericalConstants.h @@ -39,6 +39,9 @@ const quint64 NSECS_PER_MSEC = 1000000; const quint64 USECS_PER_MSEC = 1000; const quint64 MSECS_PER_SECOND = 1000; const quint64 USECS_PER_SECOND = USECS_PER_MSEC * MSECS_PER_SECOND; +const quint64 SECS_PER_MINUTE = 60; +const quint64 MINS_PER_HOUR = 60; +const quint64 SECS_PER_HOUR = SECS_PER_MINUTE * MINS_PER_HOUR; const int BITS_IN_BYTE = 8; const int BYTES_PER_KILOBYTE = 1000; diff --git a/script-archive/example/games/planky.js b/script-archive/example/games/planky.js index 742cc3b7d0..9a88c81384 100644 --- a/script-archive/example/games/planky.js +++ b/script-archive/example/games/planky.js @@ -12,7 +12,7 @@ // HIFI_PUBLIC_BUCKET = 'http://s3.amazonaws.com/hifi-public/'; -Script.include('../../libraries/toolBars.js'); +Script.include('/~/system/libraries/toolBars.js'); const DEFAULT_NUM_LAYERS = 16; const DEFAULT_BASE_DIMENSION = { x: 7, y: 2, z: 7 }; diff --git a/scripts/system/users.js b/scripts/system/users.js index f23a0ea215..d25e1b76b4 100644 --- a/scripts/system/users.js +++ b/scripts/system/users.js @@ -599,8 +599,6 @@ var usersWindow = (function () { usersRequest.ontimeout = pollUsersTimedOut; usersRequest.onreadystatechange = processUsers; usersRequest.send(); - - checkLoggedIn(); } processUsers = function () { @@ -646,6 +644,8 @@ var usersWindow = (function () { updateUsersDisplay(); updateOverlayPositions(); + checkLoggedIn(); + } else { print("Error: Request for users status returned " + usersRequest.status + " " + usersRequest.statusText); usersTimer = Script.setTimeout(pollUsers, HTTP_GET_TIMEOUT); // Try again after a longer delay. diff --git a/tests/gpu-test/src/TestFbx.cpp b/tests/gpu-test/src/TestFbx.cpp new file mode 100644 index 0000000000..cea356e125 --- /dev/null +++ b/tests/gpu-test/src/TestFbx.cpp @@ -0,0 +1,187 @@ +// +// Created by Bradley Austin Davis on 2016/05/16 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "TestFbx.h" + +#include + +#include + +#include + +struct MyVertex { + vec3 position; + vec2 texCoords; + vec3 normal; + uint32_t color; + + static gpu::Stream::FormatPointer getVertexFormat() { + static const gpu::Element POSITION_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ }; + static const gpu::Element TEXTURE_ELEMENT { gpu::VEC2, gpu::FLOAT, gpu::UV }; + static const gpu::Element NORMAL_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ }; + static const gpu::Element COLOR_ELEMENT { gpu::VEC4, gpu::NUINT8, gpu::RGBA }; + gpu::Stream::FormatPointer vertexFormat { std::make_shared() }; + vertexFormat->setAttribute(gpu::Stream::POSITION, 0, POSITION_ELEMENT, offsetof(MyVertex, position)); + vertexFormat->setAttribute(gpu::Stream::TEXCOORD, 0, TEXTURE_ELEMENT, offsetof(MyVertex, texCoords)); + vertexFormat->setAttribute(gpu::Stream::COLOR, 0, COLOR_ELEMENT, offsetof(MyVertex, color)); + vertexFormat->setAttribute(gpu::Stream::NORMAL, 0, NORMAL_ELEMENT, offsetof(MyVertex, normal)); + return vertexFormat; + } + +}; + +struct Part { + size_t baseVertex; + size_t baseIndex; + size_t materialId; +}; + +struct DrawElementsIndirectCommand { + uint count { 0 }; + uint instanceCount { 1 }; + uint firstIndex { 0 }; + uint baseVertex { 0 }; + uint baseInstance { 0 }; +}; + + +class FileDownloader : public QObject { + Q_OBJECT +public: + explicit FileDownloader(QUrl imageUrl, QObject *parent = 0) : QObject(parent) { + connect(&m_WebCtrl, SIGNAL(finished(QNetworkReply*)), this, SLOT(fileDownloaded(QNetworkReply*))); + QNetworkRequest request(imageUrl); + m_WebCtrl.get(request); + } + + virtual ~FileDownloader() {} + + const QByteArray& downloadedData() const { + return m_DownloadedData; + } + +signals: + void downloaded(); + +private slots: + void fileDownloaded(QNetworkReply* pReply) { + m_DownloadedData = pReply->readAll(); + pReply->deleteLater(); + emit downloaded(); + } + +private: + QNetworkAccessManager m_WebCtrl; + QByteArray m_DownloadedData; +}; + + +static const QUrl TEST_ASSET = QString("https://s3.amazonaws.com/DreamingContent/assets/models/tardis/console.fbx"); +static const mat4 TEST_ASSET_TRANSFORM = glm::translate(mat4(), vec3(0, -1.5f, 0)) * glm::scale(mat4(), vec3(0.01f)); +//static const QUrl TEST_ASSET = QString("https://s3.amazonaws.com/DreamingContent/assets/simple/SimpleMilitary/Models/Vehicles/tank_02_c.fbx"); +//static const mat4 TEST_ASSET_TRANSFORM = glm::translate(mat4(), vec3(0, -0.5f, 0)) * glm::scale(mat4(), vec3(0.1f)); + +TestFbx::TestFbx(const render::ShapePlumberPointer& shapePlumber) : _shapePlumber(shapePlumber) { + FileDownloader* downloader = new FileDownloader(TEST_ASSET, qApp); + QObject::connect(downloader, &FileDownloader::downloaded, [this, downloader] { + parseFbx(downloader->downloadedData()); + }); +} + +bool TestFbx::isReady() const { + return _partCount != 0; +} + +void TestFbx::parseFbx(const QByteArray& fbxData) { + QVariantHash mapping; + FBXGeometry* fbx = readFBX(fbxData, mapping); + size_t totalVertexCount = 0; + size_t totalIndexCount = 0; + size_t totalPartCount = 0; + size_t highestIndex = 0; + for (const auto& mesh : fbx->meshes) { + size_t vertexCount = mesh.vertices.size(); + totalVertexCount += mesh.vertices.size(); + highestIndex = std::max(highestIndex, vertexCount); + totalPartCount += mesh.parts.size(); + for (const auto& part : mesh.parts) { + totalIndexCount += part.quadTrianglesIndices.size(); + totalIndexCount += part.triangleIndices.size(); + } + } + size_t baseVertex = 0; + std::vector vertices; + vertices.reserve(totalVertexCount); + std::vector indices; + indices.reserve(totalIndexCount); + std::vector parts; + parts.reserve(totalPartCount); + _partCount = totalPartCount; + for (const auto& mesh : fbx->meshes) { + baseVertex = vertices.size(); + + vec3 color; + for (const auto& part : mesh.parts) { + DrawElementsIndirectCommand partIndirect; + partIndirect.baseVertex = (uint)baseVertex; + partIndirect.firstIndex = (uint)indices.size(); + partIndirect.baseInstance = (uint)parts.size(); + _partTransforms.push_back(mesh.modelTransform); + auto material = fbx->materials[part.materialID]; + color = material.diffuseColor; + for (auto index : part.quadTrianglesIndices) { + indices.push_back(index); + } + for (auto index : part.triangleIndices) { + indices.push_back(index); + } + size_t triangles = (indices.size() - partIndirect.firstIndex); + Q_ASSERT(0 == (triangles % 3)); + //triangles /= 3; + partIndirect.count = (uint)triangles; + parts.push_back(partIndirect); + } + + size_t vertexCount = mesh.vertices.size(); + for (size_t i = 0; i < vertexCount; ++i) { + MyVertex vertex; + vertex.position = mesh.vertices[(int)i]; + vec3 n = mesh.normals[(int)i]; + vertex.normal = n; + vertex.texCoords = mesh.texCoords[(int)i]; + vertex.color = toCompactColor(vec4(color, 1)); + vertices.push_back(vertex); + } + } + + _vertexBuffer->append(vertices); + _indexBuffer->append(indices); + _indirectBuffer->append(parts); + delete fbx; +} + +void TestFbx::renderTest(size_t testId, RenderArgs* args) { + gpu::Batch& batch = *(args->_batch); + //pipeline->pipeline + if (_partCount) { + for (size_t i = 0; i < _partCount; ++i) { + batch.setModelTransform(TEST_ASSET_TRANSFORM * _partTransforms[i]); + batch.setupNamedCalls(__FUNCTION__, [this](gpu::Batch& batch, gpu::Batch::NamedBatchData&) { + RenderArgs args; args._batch = &batch; + _shapePlumber->pickPipeline(&args, render::ShapeKey()); + batch.setInputBuffer(0, _vertexBuffer, 0, sizeof(MyVertex)); + batch.setIndexBuffer(gpu::UINT16, _indexBuffer, 0); + batch.setInputFormat(MyVertex::getVertexFormat()); + batch.setIndirectBuffer(_indirectBuffer, 0); + batch.multiDrawIndexedIndirect((uint)_partCount, gpu::TRIANGLES); + }); + } + } +} + +#include "TestFbx.moc" diff --git a/tests/gpu-test/src/TestFbx.h b/tests/gpu-test/src/TestFbx.h new file mode 100644 index 0000000000..1f3c0bb50e --- /dev/null +++ b/tests/gpu-test/src/TestFbx.h @@ -0,0 +1,35 @@ +// +// Created by Bradley Austin Davis on 2016/05/16 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#pragma once + +#include "TestHelpers.h" + +#include + +class FBXGeometry; + +class TestFbx : public GpuTestBase { + size_t _partCount { 0 }; + model::Material _material; + render::ShapeKey _shapeKey; + std::vector _partTransforms; + render::ShapePlumberPointer _shapePlumber; + gpu::Stream::FormatPointer _vertexFormat { std::make_shared() }; + gpu::BufferPointer _vertexBuffer { std::make_shared() }; + gpu::BufferPointer _indexBuffer { std::make_shared() }; + gpu::BufferPointer _indirectBuffer { std::make_shared() }; +public: + TestFbx(const render::ShapePlumberPointer& shapePlumber); + bool isReady() const override; + void renderTest(size_t test, RenderArgs* args) override; + +private: + void parseFbx(const QByteArray& fbxData); +}; + + diff --git a/tests/gpu-test/src/TestFloorGrid.cpp b/tests/gpu-test/src/TestFloorGrid.cpp new file mode 100644 index 0000000000..a24b4778d4 --- /dev/null +++ b/tests/gpu-test/src/TestFloorGrid.cpp @@ -0,0 +1,54 @@ +// +// Created by Bradley Austin Davis on 2016/05/16 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "TestFloorGrid.h" + + +TestFloorGrid::TestFloorGrid() { + auto geometryCache = DependencyManager::get(); + // Render grid on xz plane (not the optimal way to do things, but w/e) + // Note: GeometryCache::renderGrid will *not* work, as it is apparenly unaffected by batch rotations and renders xy only + static const std::string GRID_INSTANCE = "Grid"; + static auto compactColor1 = toCompactColor(vec4 { 0.35f, 0.25f, 0.15f, 1.0f }); + static auto compactColor2 = toCompactColor(vec4 { 0.15f, 0.25f, 0.35f, 1.0f }); + static std::vector transforms; + static gpu::BufferPointer colorBuffer; + if (!transforms.empty()) { + transforms.reserve(200); + colorBuffer = std::make_shared(); + for (int i = 0; i < 100; ++i) { + { + glm::mat4 transform = glm::translate(mat4(), vec3(0, -1, -50 + i)); + transform = glm::scale(transform, vec3(100, 1, 1)); + transforms.push_back(transform); + colorBuffer->append(compactColor1); + } + + { + glm::mat4 transform = glm::mat4_cast(quat(vec3(0, PI / 2.0f, 0))); + transform = glm::translate(transform, vec3(0, -1, -50 + i)); + transform = glm::scale(transform, vec3(100, 1, 1)); + transforms.push_back(transform); + colorBuffer->append(compactColor2); + } + } + } + +} + +void TestFloorGrid::renderTest(size_t testId, RenderArgs* args) { + //gpu::Batch& batch = *(args->_batch); + //auto pipeline = geometryCache->getSimplePipeline(); + //for (auto& transform : transforms) { + // batch.setModelTransform(transform); + // batch.setupNamedCalls(GRID_INSTANCE, [=](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + // batch.setPipeline(_pipeline); + // geometryCache->renderWireShapeInstances(batch, GeometryCache::Line, data.count(), colorBuffer); + // }); + //} +} diff --git a/tests/gpu-test/src/TestFloorGrid.h b/tests/gpu-test/src/TestFloorGrid.h new file mode 100644 index 0000000000..566c8f0968 --- /dev/null +++ b/tests/gpu-test/src/TestFloorGrid.h @@ -0,0 +1,26 @@ +// +// Created by Bradley Austin Davis on 2016/05/16 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once + +#include +#include +#include + +#include +#include + +#include "TestHelpers.h" + +class TestFloorGrid : public GpuTestBase { +public: + TestFloorGrid(); + void renderTest(size_t testId, RenderArgs* args) override; +}; + + diff --git a/tests/gpu-test/src/TestFloorTexture.cpp b/tests/gpu-test/src/TestFloorTexture.cpp new file mode 100644 index 0000000000..884be5ec30 --- /dev/null +++ b/tests/gpu-test/src/TestFloorTexture.cpp @@ -0,0 +1,88 @@ +// +// Created by Bradley Austin Davis on 2016/05/16 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "TestFloorTexture.h" + +struct Vertex { + vec4 position; + vec4 texture; + vec4 normal; + vec4 color; +}; +static const uint TEXTURE_OFFSET = offsetof(Vertex, texture); +static const uint NORMAL_OFFSET = offsetof(Vertex, normal); +static const uint POSITION_OFFSET = offsetof(Vertex, position); +static const uint COLOR_OFFSET = offsetof(Vertex, color); +static const gpu::Element POSITION_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ }; +static const gpu::Element TEXTURE_ELEMENT { gpu::VEC2, gpu::FLOAT, gpu::UV }; +static const gpu::Element NORMAL_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ }; +static const gpu::Element COLOR_ELEMENT { gpu::VEC4, gpu::FLOAT, gpu::RGBA }; + +FloorTextureTest::FloorTextureTest() { + auto geometryCache = DependencyManager::get(); + std::vector vertices; + const int MINX = -1000; + const int MAXX = 1000; + + vertices.push_back({ + vec4(MAXX, 0, MAXX, 1), + vec4(MAXX, MAXX, 0, 0), + vec4(0, 1, 0, 1), + vec4(1), + }); + + vertices.push_back({ + vec4(MAXX, 0, MINX, 1), + vec4(MAXX, 0, 0, 0), + vec4(0, 1, 0, 1), + vec4(1), + }); + + vertices.push_back({ + vec4(MINX, 0, MINX, 1), + vec4(0, 0, 0, 0), + vec4(0, 1, 0, 1), + vec4(1), + }); + + vertices.push_back({ + vec4(MINX, 0, MAXX, 1), + vec4(0, MAXX, 0, 0), + vec4(0, 1, 0, 1), + vec4(1), + }); + + vertexBuffer->append(vertices); + indexBuffer->append(std::vector({ 0, 1, 2, 2, 3, 0 })); + texture = DependencyManager::get()->getImageTexture("C:/Users/bdavis/Git/openvr/samples/bin/cube_texture.png"); + //texture = DependencyManager::get()->getImageTexture("H:/test.png"); + //texture = DependencyManager::get()->getImageTexture("H:/crate_blue.fbm/lambert8SG_Normal_OpenGL.png"); + vertexFormat->setAttribute(gpu::Stream::POSITION, 0, POSITION_ELEMENT, POSITION_OFFSET); + vertexFormat->setAttribute(gpu::Stream::TEXCOORD, 0, TEXTURE_ELEMENT, TEXTURE_OFFSET); + vertexFormat->setAttribute(gpu::Stream::COLOR, 0, COLOR_ELEMENT, COLOR_OFFSET); + vertexFormat->setAttribute(gpu::Stream::NORMAL, 0, NORMAL_ELEMENT, NORMAL_OFFSET); +} + +void FloorTextureTest::renderTest(size_t testId, RenderArgs* args) { + gpu::Batch& batch = *(args->_batch); + auto geometryCache = DependencyManager::get(); + static auto start = usecTimestampNow(); + auto now = usecTimestampNow(); + if ((now - start) > USECS_PER_SECOND * 1) { + start = now; + texture->incremementMinMip(); + } + + geometryCache->bindSimpleProgram(batch, true, true, true); + batch.setInputBuffer(0, vertexBuffer, 0, sizeof(Vertex)); + batch.setInputFormat(vertexFormat); + batch.setIndexBuffer(gpu::UINT16, indexBuffer, 0); + batch.setResourceTexture(0, texture); + batch.setModelTransform(glm::translate(glm::mat4(), vec3(0, -0.1, 0))); + batch.drawIndexed(gpu::TRIANGLES, 6, 0); +} diff --git a/tests/gpu-test/src/TestFloorTexture.h b/tests/gpu-test/src/TestFloorTexture.h new file mode 100644 index 0000000000..99eaf902b8 --- /dev/null +++ b/tests/gpu-test/src/TestFloorTexture.h @@ -0,0 +1,22 @@ +// +// Created by Bradley Austin Davis on 2016/05/16 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#pragma once + +#include "TestHelpers.h" + +class FloorTextureTest : public GpuTestBase { + gpu::BufferPointer vertexBuffer { std::make_shared() }; + gpu::BufferPointer indexBuffer { std::make_shared() }; + gpu::Stream::FormatPointer vertexFormat { std::make_shared() }; + gpu::TexturePointer texture; +public: + FloorTextureTest(); + void renderTest(size_t testId, RenderArgs* args) override; +}; + + diff --git a/tests/gpu-test/src/main.cpp b/tests/gpu-test/src/main.cpp index e672fe3c86..0f06546327 100644 --- a/tests/gpu-test/src/main.cpp +++ b/tests/gpu-test/src/main.cpp @@ -62,6 +62,9 @@ #include #include "TestWindow.h" +#include "TestFbx.h" +#include "TestFloorGrid.h" +#include "TestFloorTexture.h" #include "TestInstancedShapes.h" #include "TestShapes.h" @@ -90,8 +93,8 @@ class MyTestWindow : public TestWindow { #endif updateCamera(); _testBuilders = TestBuilders({ - //[this] { return new TestFbx(_shapePlumber); }, - [] { return new TestShapes(); }, + [this] { return new TestFbx(_shapePlumber); }, + [] { return new TestInstancedShapes(); }, }); } diff --git a/tests/gpu-test/src/unlit.slf b/tests/gpu-test/src/unlit.slf deleted file mode 100644 index f88fcb510b..0000000000 --- a/tests/gpu-test/src/unlit.slf +++ /dev/null @@ -1,28 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// simple.frag -// fragment shader -// -// Created by Andrzej Kapolka on 9/15/14. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -<@include DeferredBufferWrite.slh@> -<@include model/Material.slh@> - -// the interpolated normal -in vec3 _normal; -in vec3 _color; - -void main(void) { - packDeferredFragment( - normalize(_normal.xyz), - 1.0, - _color.rgb, - DEFAULT_ROUGHNESS, DEFAULT_METALLIC, DEFAULT_EMISSIVE, DEFAULT_OCCLUSION); -} diff --git a/tests/gpu-test/src/unlit.slv b/tests/gpu-test/src/unlit.slv deleted file mode 100644 index d51d817429..0000000000 --- a/tests/gpu-test/src/unlit.slv +++ /dev/null @@ -1,36 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// simple.vert -// vertex shader -// -// Created by Andrzej Kapolka on 9/15/14. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -<@include gpu/Inputs.slh@> - -<@include gpu/Transform.slh@> - -<$declareStandardTransform()$> - -// the interpolated normal -out vec3 _normal; -out vec3 _color; -out vec2 _texCoord0; - -void main(void) { - _color = inColor.rgb; - _texCoord0 = inTexCoord0.st; - - // standard transform - TransformCamera cam = getTransformCamera(); - TransformObject obj = getTransformObject(); - <$transformModelToClipPos(cam, obj, inPosition, gl_Position)$> - <$transformModelToEyeDir(cam, obj, inNormal.xyz, _normal)$> - _normal = vec3(0.0, 0.0, 1.0); -} \ No newline at end of file