merge from upstream

This commit is contained in:
Seth Alves 2016-06-29 18:49:33 -07:00
commit 408a77dd13
43 changed files with 1674 additions and 368 deletions

72
.eslintrc.js Normal file
View file

@ -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"]
}
};

View file

@ -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',

View file

@ -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<QVariantList>()) {
return;
}
auto& deltaList = *static_cast<QVariantList*>(delta.data());
if (deltaList.isEmpty()) {
return;
}
auto& deltaHours = *static_cast<QVariantMap*>(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<QVariantList*>(static_cast<QVariantList*>(target.data())->first().data());
hours[OPEN_INDEX] = open.value();
hours[CLOSE_INDEX] = close.value();
assert(hours[OPEN_INDEX].canConvert<QString>());
assert(hours[CLOSE_INDEX].canConvert<QString>());
}
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<QVariantList>());
auto& targetList = *static_cast<QVariantList*>(target.data());
// if/when multiple ranges are allowed, this list will need to be iterated
assert(targetList[0].canConvert<QVariantList>());
auto& hours = *static_cast<QVariantList*>(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<QString>());
auto close = deltaHours.find(Hours::CLOSE);
if (close != deltaHours.end()) {
hours[CLOSE_INDEX] = close.value();
}
assert(hours[CLOSE_INDEX].canConvert<QString>());
}
void DomainMetadata::descriptorsChanged() {
// get descriptors
assert(_metadata[DESCRIPTORS].canConvert<QVariantMap>());
auto& state = *static_cast<QVariantMap*>(_metadata[DESCRIPTORS].data());
auto settings = static_cast<DomainServer*>(parent())->_settingsManager.getSettingsMap();
auto descriptors = settings[DESCRIPTORS].toMap();
auto& settings = static_cast<DomainServer*>(parent())->_settingsManager.getSettingsMap();
auto& descriptors = static_cast<DomainServer*>(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<QVariantMap>());
auto& hours = *static_cast<QVariantMap*>(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());

View file

@ -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),

View file

@ -27,6 +27,7 @@
#include <HifiConfigVariantMap.h>
#include <HTTPConnection.h>
#include <NLPacketList.h>
#include <NumericalConstants.h>
#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<QVariantMap*>(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) {

View file

@ -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);

View file

@ -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();

View file

@ -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;
}

View file

@ -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>();
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.

View file

@ -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();

View file

@ -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;

View file

@ -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) {

View file

@ -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

View file

@ -6,6 +6,14 @@
#include <QtOpenGL/QGL>
#include <QOpenGLContext>
#include <QtCore/QRegularExpression>
#include <QtCore/QProcessEnvironment>
#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);
});

View file

@ -12,23 +12,30 @@
#include "OffscreenGLCanvas.h"
#include <QtCore/QProcessEnvironment>
#include <QtGui/QOffscreenSurface>
#include <QtGui/QOpenGLDebugLogger>
#include <QtGui/QOpenGLContext>
#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;
}

View file

@ -36,10 +36,7 @@ protected:
std::once_flag _reportOnce;
QOpenGLContext* _context;
QOffscreenSurface* _offscreenSurface;
#ifdef DEBUG
QOpenGLDebugLogger* _logger{ nullptr };
#endif
};
#endif // hifi_OffscreenGLCanvas_h

View file

@ -17,6 +17,7 @@
#include <glm/gtc/type_ptr.hpp>
#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();

View file

@ -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 };

View file

@ -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<GLvoid*>(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
}

View file

@ -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<GLvoid*>(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();
}

View file

@ -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) {

View file

@ -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 <mutex>
#include <queue>
#include <list>
#include <functional>
#include <glm/gtc/type_ptr.hpp>
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<GLvoid*>(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<GLvoid*>(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<GLvoid*>(_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<GLvoid*>(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride);
_stats._DSNumDrawcalls += commandCount;
_stats._DSNumAPIDrawcalls++;
(void)CHECK_GL_ERROR();
}

View file

@ -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<void()> 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

View file

@ -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<GL45Buffer>(buffer);
}
gl::GLBuffer* GL45Backend::syncGPUObject(const Buffer& buffer) {
return GL45Buffer::sync<GL45Buffer>(buffer);
}

View file

@ -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();
}

View file

@ -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 <QtGui/QImage>
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<GL45Backend::GL45Texture>(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<GL45Backend::GL45Texture>(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<GL45Framebuffer>(framebuffer);
}
GLuint GL45Backend::getFramebufferID(const FramebufferPointer& framebuffer) {
return framebuffer ? gl::GLFramebuffer::getId<GL45Framebuffer>(*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();
}
} }

View file

@ -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<GL45Query>(query);
}
GLuint GL45Backend::getQueryID(const QueryPointer& query) {
return GL45Query::getId<GL45Query>(query);
}
} }

View file

@ -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 <unordered_set>
#include <unordered_map>
#include <QtCore/QThread>
#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<GL45Texture>(texture, transfer);
}
gl::GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texture, bool transfer) {
return GL45Texture::sync<GL45Texture>(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<void()> 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());
}

View file

@ -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<uint8_t> 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;
}

View file

@ -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 <assert.h>
#include <functional>
#include <bitset>
#include <queue>
#include <utility>
#include <list>
#include <array>
#include <QtCore/QLoggingCategory>
#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

View file

@ -15,7 +15,8 @@
#include <QtCore/QUrl>
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

View file

@ -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;

View file

@ -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 };

View file

@ -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.

View file

@ -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 <glm/gtc/matrix_transform.hpp>
#include <QtCore/QFile>
#include <FBXReader.h>
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<gpu::Stream::Format>() };
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<MyVertex> vertices;
vertices.reserve(totalVertexCount);
std::vector<uint16_t> indices;
indices.reserve(totalIndexCount);
std::vector<DrawElementsIndirectCommand> 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"

View file

@ -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 <render/ShapePipeline.h>
class FBXGeometry;
class TestFbx : public GpuTestBase {
size_t _partCount { 0 };
model::Material _material;
render::ShapeKey _shapeKey;
std::vector<mat4> _partTransforms;
render::ShapePlumberPointer _shapePlumber;
gpu::Stream::FormatPointer _vertexFormat { std::make_shared<gpu::Stream::Format>() };
gpu::BufferPointer _vertexBuffer { std::make_shared<gpu::Buffer>() };
gpu::BufferPointer _indexBuffer { std::make_shared<gpu::Buffer>() };
gpu::BufferPointer _indirectBuffer { std::make_shared<gpu::Buffer>() };
public:
TestFbx(const render::ShapePlumberPointer& shapePlumber);
bool isReady() const override;
void renderTest(size_t test, RenderArgs* args) override;
private:
void parseFbx(const QByteArray& fbxData);
};

View file

@ -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<GeometryCache>();
// 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<glm::mat4> transforms;
static gpu::BufferPointer colorBuffer;
if (!transforms.empty()) {
transforms.reserve(200);
colorBuffer = std::make_shared<gpu::Buffer>();
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);
// });
//}
}

View file

@ -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 <vector>
#include <GLMHelpers.h>
#include <Transform.h>
#include <gpu/Resource.h>
#include <gpu/Stream.h>
#include "TestHelpers.h"
class TestFloorGrid : public GpuTestBase {
public:
TestFloorGrid();
void renderTest(size_t testId, RenderArgs* args) override;
};

View file

@ -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<GeometryCache>();
std::vector<Vertex> 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<uint16_t>({ 0, 1, 2, 2, 3, 0 }));
texture = DependencyManager::get<TextureCache>()->getImageTexture("C:/Users/bdavis/Git/openvr/samples/bin/cube_texture.png");
//texture = DependencyManager::get<TextureCache>()->getImageTexture("H:/test.png");
//texture = DependencyManager::get<TextureCache>()->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<GeometryCache>();
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);
}

View file

@ -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::Buffer>() };
gpu::BufferPointer indexBuffer { std::make_shared<gpu::Buffer>() };
gpu::Stream::FormatPointer vertexFormat { std::make_shared<gpu::Stream::Format>() };
gpu::TexturePointer texture;
public:
FloorTextureTest();
void renderTest(size_t testId, RenderArgs* args) override;
};

View file

@ -62,6 +62,9 @@
#include <render/CullTask.h>
#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(); },
});
}

View file

@ -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);
}

View file

@ -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);
}