mirror of
https://github.com/lubosz/overte.git
synced 2025-04-07 04:42:49 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into skin
This commit is contained in:
commit
ed67fe4051
36 changed files with 1508 additions and 403 deletions
BIN
interface/resources/images/Loading-Inner-H.png
Normal file
BIN
interface/resources/images/Loading-Inner-H.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
interface/resources/images/Loading-Outer-Ring.png
Normal file
BIN
interface/resources/images/Loading-Outer-Ring.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
BIN
interface/resources/images/preview.png
Normal file
BIN
interface/resources/images/preview.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 110 KiB |
|
@ -3,12 +3,14 @@ import QtQuick.Controls 1.2
|
|||
import QtWebEngine 1.1
|
||||
|
||||
import "controls-uit"
|
||||
import "styles" as HifiStyles
|
||||
import "styles-uit"
|
||||
import "windows"
|
||||
|
||||
ScrollingWindow {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
HifiStyles.HifiConstants { id: hifistyles }
|
||||
title: "Browser"
|
||||
resizable: true
|
||||
destroyOnHidden: true
|
||||
|
@ -46,7 +48,7 @@ ScrollingWindow {
|
|||
id: back;
|
||||
enabled: webview.canGoBack;
|
||||
text: hifi.glyphs.backward
|
||||
color: enabled ? hifi.colors.text : hifi.colors.disabledText
|
||||
color: enabled ? hifistyles.colors.text : hifistyles.colors.disabledText
|
||||
size: 48
|
||||
MouseArea { anchors.fill: parent; onClicked: webview.goBack() }
|
||||
}
|
||||
|
@ -55,7 +57,7 @@ ScrollingWindow {
|
|||
id: forward;
|
||||
enabled: webview.canGoForward;
|
||||
text: hifi.glyphs.forward
|
||||
color: enabled ? hifi.colors.text : hifi.colors.disabledText
|
||||
color: enabled ? hifistyles.colors.text : hifistyles.colors.disabledText
|
||||
size: 48
|
||||
MouseArea { anchors.fill: parent; onClicked: webview.goForward() }
|
||||
}
|
||||
|
@ -64,7 +66,7 @@ ScrollingWindow {
|
|||
id: reload;
|
||||
enabled: webview.canGoForward;
|
||||
text: webview.loading ? hifi.glyphs.close : hifi.glyphs.reload
|
||||
color: enabled ? hifi.colors.text : hifi.colors.disabledText
|
||||
color: enabled ? hifistyles.colors.text : hifistyles.colors.disabledText
|
||||
size: 48
|
||||
MouseArea { anchors.fill: parent; onClicked: webview.goForward() }
|
||||
}
|
||||
|
@ -105,7 +107,7 @@ ScrollingWindow {
|
|||
focus: true
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
placeholderText: "Enter URL"
|
||||
Component.onCompleted: scriptsModel.filterRegExp = new RegExp("^.*$", "i")
|
||||
Component.onCompleted: ScriptDiscoveryService.scriptsModelFilter.filterRegExp = new RegExp("^.*$", "i")
|
||||
Keys.onPressed: {
|
||||
switch(event.key) {
|
||||
case Qt.Key_Enter:
|
||||
|
|
|
@ -3,13 +3,16 @@ import QtQuick 2.3
|
|||
import QtQuick.Controls 1.3
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import "controls-uit"
|
||||
import "styles" as HifiStyles
|
||||
import "styles-uit"
|
||||
import "windows"
|
||||
|
||||
ScrollingWindow {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
HifiStyles.HifiConstants { id: hifistyles }
|
||||
objectName: "UpdateDialog"
|
||||
width: updateDialog.implicitWidth
|
||||
height: updateDialog.implicitHeight
|
||||
|
@ -40,22 +43,6 @@ ScrollingWindow {
|
|||
|
||||
width: updateDialog.contentWidth + updateDialog.borderWidth * 2
|
||||
height: mainContent.height + updateDialog.borderWidth * 2 - updateDialog.closeMargin / 2
|
||||
|
||||
MouseArea {
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
drag {
|
||||
target: root
|
||||
minimumX: 0
|
||||
minimumY: 0
|
||||
maximumX: root.parent ? root.maximumX : 0
|
||||
maximumY: root.parent ? root.maximumY : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
|
@ -89,7 +76,7 @@ ScrollingWindow {
|
|||
text: "Update Available"
|
||||
font {
|
||||
family: updateDialog.fontFamily
|
||||
pixelSize: hifi.fonts.pixelSize * 1.5
|
||||
pixelSize: hifistyles.fonts.pixelSize * 1.5
|
||||
weight: Font.DemiBold
|
||||
}
|
||||
color: "#303030"
|
||||
|
@ -100,10 +87,10 @@ ScrollingWindow {
|
|||
text: updateDialog.updateAvailableDetails
|
||||
font {
|
||||
family: updateDialog.fontFamily
|
||||
pixelSize: hifi.fonts.pixelSize * 0.6
|
||||
pixelSize: hifistyles.fonts.pixelSize * 0.6
|
||||
letterSpacing: -0.5
|
||||
}
|
||||
color: hifi.colors.text
|
||||
color: hifistyles.colors.text
|
||||
anchors {
|
||||
top: updateAvailable.bottom
|
||||
}
|
||||
|
@ -130,12 +117,12 @@ ScrollingWindow {
|
|||
Text {
|
||||
id: releaseNotes
|
||||
wrapMode: Text.Wrap
|
||||
width: parent.width - updateDialog.closeMargin
|
||||
width: parent.parent.width - updateDialog.closeMargin
|
||||
text: updateDialog.releaseNotes
|
||||
color: hifi.colors.text
|
||||
color: hifistyles.colors.text
|
||||
font {
|
||||
family: updateDialog.fontFamily
|
||||
pixelSize: hifi.fonts.pixelSize * 0.65
|
||||
pixelSize: hifistyles.fonts.pixelSize * 0.65
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +144,7 @@ ScrollingWindow {
|
|||
color: "#0c9ab4" // Same as logo
|
||||
font {
|
||||
family: updateDialog.fontFamily
|
||||
pixelSize: hifi.fonts.pixelSize * 1.2
|
||||
pixelSize: hifistyles.fonts.pixelSize * 1.2
|
||||
weight: Font.DemiBold
|
||||
}
|
||||
anchors {
|
||||
|
@ -169,7 +156,7 @@ ScrollingWindow {
|
|||
MouseArea {
|
||||
id: cancelButtonAction
|
||||
anchors.fill: parent
|
||||
onClicked: updateDialog.closeDialog()
|
||||
onClicked: root.shown = false
|
||||
cursorShape: "PointingHandCursor"
|
||||
}
|
||||
}
|
||||
|
@ -185,7 +172,7 @@ ScrollingWindow {
|
|||
color: "#0c9ab4" // Same as logo
|
||||
font {
|
||||
family: updateDialog.fontFamily
|
||||
pixelSize: hifi.fonts.pixelSize * 1.2
|
||||
pixelSize: hifistyles.fonts.pixelSize * 1.2
|
||||
weight: Font.DemiBold
|
||||
}
|
||||
anchors {
|
||||
|
|
|
@ -209,6 +209,9 @@ Fadable {
|
|||
|
||||
var targetVisibility = getTargetVisibility();
|
||||
if (targetVisibility === visible) {
|
||||
if (force) {
|
||||
window.raise();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -3049,17 +3049,20 @@ bool Application::exportEntities(const QString& filename, const QVector<EntityIt
|
|||
}
|
||||
|
||||
bool Application::exportEntities(const QString& filename, float x, float y, float z, float scale) {
|
||||
glm::vec3 offset(x, y, z);
|
||||
glm::vec3 center(x, y, z);
|
||||
glm::vec3 minCorner = center - vec3(scale);
|
||||
float cubeSize = scale * 2;
|
||||
AACube boundingCube(minCorner, cubeSize);
|
||||
QVector<EntityItemPointer> entities;
|
||||
QVector<EntityItemID> ids;
|
||||
auto entityTree = getEntities()->getTree();
|
||||
entityTree->withReadLock([&] {
|
||||
entityTree->findEntities(AACube(offset, scale), entities);
|
||||
entityTree->findEntities(boundingCube, entities);
|
||||
foreach(EntityItemPointer entity, entities) {
|
||||
ids << entity->getEntityItemID();
|
||||
}
|
||||
});
|
||||
return exportEntities(filename, ids, &offset);
|
||||
return exportEntities(filename, ids, ¢er);
|
||||
}
|
||||
|
||||
void Application::loadSettings() {
|
||||
|
|
|
@ -48,14 +48,6 @@ const QString& UpdateDialog::releaseNotes() const {
|
|||
return _releaseNotes;
|
||||
}
|
||||
|
||||
void UpdateDialog::closeDialog() {
|
||||
hide();
|
||||
}
|
||||
|
||||
void UpdateDialog::hide() {
|
||||
((QQuickItem*)parent())->setVisible(false);
|
||||
}
|
||||
|
||||
void UpdateDialog::triggerUpgrade() {
|
||||
auto applicationUpdater = DependencyManager::get<AutoUpdater>();
|
||||
applicationUpdater.data()->performAutoUpdate(applicationUpdater.data()->getBuildData().lastKey());
|
||||
|
|
|
@ -21,22 +21,20 @@ class UpdateDialog : public OffscreenQmlDialog {
|
|||
Q_OBJECT
|
||||
HIFI_QML_DECL
|
||||
|
||||
Q_PROPERTY(QString updateAvailableDetails READ updateAvailableDetails)
|
||||
Q_PROPERTY(QString releaseNotes READ releaseNotes)
|
||||
Q_PROPERTY(QString updateAvailableDetails READ updateAvailableDetails CONSTANT)
|
||||
Q_PROPERTY(QString releaseNotes READ releaseNotes CONSTANT)
|
||||
|
||||
public:
|
||||
UpdateDialog(QQuickItem* parent = nullptr);
|
||||
const QString& updateAvailableDetails() const;
|
||||
const QString& releaseNotes() const;
|
||||
|
||||
|
||||
private:
|
||||
QString _updateAvailableDetails;
|
||||
QString _releaseNotes;
|
||||
|
||||
protected:
|
||||
void hide();
|
||||
Q_INVOKABLE void triggerUpgrade();
|
||||
Q_INVOKABLE void closeDialog();
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ void ModelOverlay::update(float deltatime) {
|
|||
_updateModel = false;
|
||||
|
||||
_model->setSnapModelToCenter(true);
|
||||
_model->setScale(getDimensions());
|
||||
_model->setScaleToFit(true, getDimensions());
|
||||
_model->setRotation(getRotation());
|
||||
_model->setTranslation(getPosition());
|
||||
_model->setURL(_url);
|
||||
|
@ -100,7 +100,6 @@ void ModelOverlay::setProperties(const QVariantMap& properties) {
|
|||
if (newScale.x <= 0 || newScale.y <= 0 || newScale.z <= 0) {
|
||||
setDimensions(scale);
|
||||
} else {
|
||||
_model->setScaleToFit(true, getDimensions());
|
||||
_updateModel = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ void Sphere3DOverlay::render(RenderArgs* args) {
|
|||
}
|
||||
|
||||
const render::ShapeKey Sphere3DOverlay::getShapeKey() {
|
||||
auto builder = render::ShapeKey::Builder().withOwnPipeline();
|
||||
auto builder = render::ShapeKey::Builder();
|
||||
if (getAlpha() != 1.0f) {
|
||||
builder.withTranslucent();
|
||||
}
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
#include <QtOpenGL/QGLWidget>
|
||||
#include <QtGui/QImage>
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
#include <OpenGL/CGLCurrent.h>
|
||||
#endif
|
||||
#include <gl/QOpenGLContextWrapper.h>
|
||||
#include <gpu/Texture.h>
|
||||
#include <gl/GLWidget.h>
|
||||
|
@ -612,8 +615,14 @@ void OpenGLDisplayPlugin::enableVsync(bool enable) {
|
|||
if (!_vsyncSupported) {
|
||||
return;
|
||||
}
|
||||
#ifdef Q_OS_WIN
|
||||
#if defined(Q_OS_WIN)
|
||||
wglSwapIntervalEXT(enable ? 1 : 0);
|
||||
#elif defined(Q_OS_MAC)
|
||||
GLint interval = enable ? 1 : 0;
|
||||
CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &interval);
|
||||
#else
|
||||
// TODO: Fill in for linux
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -621,9 +630,14 @@ bool OpenGLDisplayPlugin::isVsyncEnabled() {
|
|||
if (!_vsyncSupported) {
|
||||
return true;
|
||||
}
|
||||
#ifdef Q_OS_WIN
|
||||
#if defined(Q_OS_WIN)
|
||||
return wglGetSwapIntervalEXT() != 0;
|
||||
#elif defined(Q_OS_MAC)
|
||||
GLint interval;
|
||||
CGLGetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &interval);
|
||||
return interval != 0;
|
||||
#else
|
||||
// TODO: Fill in for linux
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -21,6 +21,11 @@
|
|||
#include <gl/GLWidget.h>
|
||||
#include <shared/NsightHelpers.h>
|
||||
|
||||
#include <gpu/DrawUnitQuadTexcoord_vert.h>
|
||||
#include <gpu/DrawTexture_frag.h>
|
||||
|
||||
#include <PathUtils.h>
|
||||
|
||||
#include "../Logging.h"
|
||||
#include "../CompositorHelper.h"
|
||||
|
||||
|
@ -58,9 +63,33 @@ bool HmdDisplayPlugin::internalActivate() {
|
|||
_eyeInverseProjections[eye] = glm::inverse(_eyeProjections[eye]);
|
||||
});
|
||||
|
||||
if (_previewTextureID == 0) {
|
||||
QImage previewTexture(PathUtils::resourcesPath() + "images/preview.png");
|
||||
if (!previewTexture.isNull()) {
|
||||
glGenTextures(1, &_previewTextureID);
|
||||
glBindTexture(GL_TEXTURE_2D, _previewTextureID);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, previewTexture.width(), previewTexture.height(), 0,
|
||||
GL_BGRA, GL_UNSIGNED_BYTE, previewTexture.mirrored(false, true).bits());
|
||||
using namespace oglplus;
|
||||
Texture::MinFilter(TextureTarget::_2D, TextureMinFilter::Linear);
|
||||
Texture::MagFilter(TextureTarget::_2D, TextureMagFilter::Linear);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
_previewAspect = ((float)previewTexture.width())/((float)previewTexture.height());
|
||||
_firstPreview = true;
|
||||
}
|
||||
}
|
||||
|
||||
return Parent::internalActivate();
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::internalDeactivate() {
|
||||
if (_previewTextureID != 0) {
|
||||
glDeleteTextures(1, &_previewTextureID);
|
||||
_previewTextureID = 0;
|
||||
}
|
||||
Parent::internalDeactivate();
|
||||
}
|
||||
|
||||
|
||||
static const char * REPROJECTION_VS = R"VS(#version 410 core
|
||||
in vec3 Position;
|
||||
|
@ -196,6 +225,7 @@ static ProgramPtr getReprojectionProgram() {
|
|||
}
|
||||
#endif
|
||||
|
||||
static GLint PREVIEW_TEXTURE_LOCATION = -1;
|
||||
|
||||
static const char * LASER_VS = R"VS(#version 410 core
|
||||
uniform mat4 mvp = mat4(1);
|
||||
|
@ -227,14 +257,24 @@ void main() {
|
|||
void HmdDisplayPlugin::customizeContext() {
|
||||
Parent::customizeContext();
|
||||
// Only enable mirroring if we know vsync is disabled
|
||||
// On Mac, this won't work due to how the contexts are handled, so don't try
|
||||
#if !defined(Q_OS_MAC)
|
||||
enableVsync(false);
|
||||
#endif
|
||||
_enablePreview = !isVsyncEnabled();
|
||||
_sphereSection = loadSphereSection(_program, CompositorHelper::VIRTUAL_UI_TARGET_FOV.y, CompositorHelper::VIRTUAL_UI_ASPECT_RATIO);
|
||||
compileProgram(_laserProgram, LASER_VS, LASER_FS);
|
||||
_laserGeometry = loadLaser(_laserProgram);
|
||||
compileProgram(_reprojectionProgram, REPROJECTION_VS, REPROJECTION_FS);
|
||||
|
||||
using namespace oglplus;
|
||||
if (!_enablePreview) {
|
||||
const std::string version("#version 410 core\n");
|
||||
compileProgram(_previewProgram, version + DrawUnitQuadTexcoord_vert, version + DrawTexture_frag);
|
||||
PREVIEW_TEXTURE_LOCATION = Uniform<int>(*_previewProgram, "colorMap").Location();
|
||||
}
|
||||
|
||||
compileProgram(_laserProgram, LASER_VS, LASER_FS);
|
||||
_laserGeometry = loadLaser(_laserProgram);
|
||||
|
||||
compileProgram(_reprojectionProgram, REPROJECTION_VS, REPROJECTION_FS);
|
||||
REPROJECTION_MATRIX_LOCATION = Uniform<glm::mat3>(*_reprojectionProgram, "reprojection").Location();
|
||||
INVERSE_PROJECTION_MATRIX_LOCATION = Uniform<glm::mat4>(*_reprojectionProgram, "inverseProjections").Location();
|
||||
PROJECTION_MATRIX_LOCATION = Uniform<glm::mat4>(*_reprojectionProgram, "projections").Location();
|
||||
|
@ -243,6 +283,7 @@ void HmdDisplayPlugin::customizeContext() {
|
|||
void HmdDisplayPlugin::uncustomizeContext() {
|
||||
_sphereSection.reset();
|
||||
_compositeFramebuffer.reset();
|
||||
_previewProgram.reset();
|
||||
_reprojectionProgram.reset();
|
||||
_laserProgram.reset();
|
||||
_laserGeometry.reset();
|
||||
|
@ -335,30 +376,32 @@ void HmdDisplayPlugin::internalPresent() {
|
|||
hmdPresent();
|
||||
|
||||
// screen preview mirroring
|
||||
auto window = _container->getPrimaryWidget();
|
||||
auto devicePixelRatio = window->devicePixelRatio();
|
||||
auto windowSize = toGlm(window->size());
|
||||
windowSize *= devicePixelRatio;
|
||||
float windowAspect = aspect(windowSize);
|
||||
float sceneAspect = _enablePreview ? aspect(_renderTargetSize) : _previewAspect;
|
||||
if (_enablePreview && _monoPreview) {
|
||||
sceneAspect /= 2.0f;
|
||||
}
|
||||
float aspectRatio = sceneAspect / windowAspect;
|
||||
|
||||
uvec2 targetViewportSize = windowSize;
|
||||
if (aspectRatio < 1.0f) {
|
||||
targetViewportSize.x *= aspectRatio;
|
||||
} else {
|
||||
targetViewportSize.y /= aspectRatio;
|
||||
}
|
||||
|
||||
uvec2 targetViewportPosition;
|
||||
if (targetViewportSize.x < windowSize.x) {
|
||||
targetViewportPosition.x = (windowSize.x - targetViewportSize.x) / 2;
|
||||
} else if (targetViewportSize.y < windowSize.y) {
|
||||
targetViewportPosition.y = (windowSize.y - targetViewportSize.y) / 2;
|
||||
}
|
||||
|
||||
if (_enablePreview) {
|
||||
auto window = _container->getPrimaryWidget();
|
||||
auto windowSize = toGlm(window->size());
|
||||
float windowAspect = aspect(windowSize);
|
||||
float sceneAspect = aspect(_renderTargetSize);
|
||||
if (_monoPreview) {
|
||||
sceneAspect /= 2.0f;
|
||||
}
|
||||
float aspectRatio = sceneAspect / windowAspect;
|
||||
|
||||
uvec2 targetViewportSize = windowSize;
|
||||
if (aspectRatio < 1.0f) {
|
||||
targetViewportSize.x *= aspectRatio;
|
||||
} else {
|
||||
targetViewportSize.y /= aspectRatio;
|
||||
}
|
||||
|
||||
uvec2 targetViewportPosition;
|
||||
if (targetViewportSize.x < windowSize.x) {
|
||||
targetViewportPosition.x = (windowSize.x - targetViewportSize.x) / 2;
|
||||
} else if (targetViewportSize.y < windowSize.y) {
|
||||
targetViewportPosition.y = (windowSize.y - targetViewportSize.y) / 2;
|
||||
}
|
||||
|
||||
using namespace oglplus;
|
||||
Context::Clear().ColorBuffer();
|
||||
auto sourceSize = _compositeFramebuffer->size;
|
||||
|
@ -373,6 +416,21 @@ void HmdDisplayPlugin::internalPresent() {
|
|||
BufferSelectBit::ColorBuffer, BlitFilter::Nearest);
|
||||
});
|
||||
swapBuffers();
|
||||
} else if (_firstPreview || windowSize != _prevWindowSize || devicePixelRatio != _prevDevicePixelRatio) {
|
||||
useProgram(_previewProgram);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glViewport(targetViewportPosition.x, targetViewportPosition.y, targetViewportSize.x, targetViewportSize.y);
|
||||
glUniform1i(PREVIEW_TEXTURE_LOCATION, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, _previewTextureID);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
swapBuffers();
|
||||
_firstPreview = false;
|
||||
_prevWindowSize = windowSize;
|
||||
_prevDevicePixelRatio = devicePixelRatio;
|
||||
}
|
||||
|
||||
postPreview();
|
||||
|
|
|
@ -40,6 +40,7 @@ protected:
|
|||
virtual void updatePresentPose();
|
||||
|
||||
bool internalActivate() override;
|
||||
void internalDeactivate() override;
|
||||
void compositeScene() override;
|
||||
void compositeOverlay() override;
|
||||
void compositePointer() override;
|
||||
|
@ -89,8 +90,17 @@ private:
|
|||
bool _enablePreview { false };
|
||||
bool _monoPreview { true };
|
||||
bool _enableReprojection { true };
|
||||
ShapeWrapperPtr _sphereSection;
|
||||
bool _firstPreview { true };
|
||||
|
||||
ProgramPtr _previewProgram;
|
||||
float _previewAspect { 0 };
|
||||
GLuint _previewTextureID { 0 };
|
||||
glm::uvec2 _prevWindowSize { 0, 0 };
|
||||
qreal _prevDevicePixelRatio { 0 };
|
||||
|
||||
ProgramPtr _reprojectionProgram;
|
||||
ShapeWrapperPtr _sphereSection;
|
||||
|
||||
ProgramPtr _laserProgram;
|
||||
ShapeWrapperPtr _laserGeometry;
|
||||
};
|
||||
|
|
|
@ -291,7 +291,9 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() {
|
|||
foreach(const EntityItemID& entityID, _currentEntitiesInside) {
|
||||
if (!entitiesContainingAvatar.contains(entityID)) {
|
||||
emit leaveEntity(entityID);
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "leaveEntity");
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "leaveEntity");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -299,7 +301,9 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() {
|
|||
foreach(const EntityItemID& entityID, entitiesContainingAvatar) {
|
||||
if (!_currentEntitiesInside.contains(entityID)) {
|
||||
emit enterEntity(entityID);
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "enterEntity");
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "enterEntity");
|
||||
}
|
||||
}
|
||||
}
|
||||
_currentEntitiesInside = entitiesContainingAvatar;
|
||||
|
@ -315,7 +319,9 @@ void EntityTreeRenderer::leaveAllEntities() {
|
|||
// for all of our previous containing entities, if they are no longer containing then send them a leave event
|
||||
foreach(const EntityItemID& entityID, _currentEntitiesInside) {
|
||||
emit leaveEntity(entityID);
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "leaveEntity");
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "leaveEntity");
|
||||
}
|
||||
}
|
||||
_currentEntitiesInside.clear();
|
||||
forceRecheckEntities();
|
||||
|
@ -652,11 +658,15 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event) {
|
|||
}
|
||||
|
||||
emit mousePressOnEntity(rayPickResult, event);
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mousePressOnEntity", MouseEvent(*event));
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mousePressOnEntity", MouseEvent(*event));
|
||||
}
|
||||
|
||||
_currentClickingOnEntityID = rayPickResult.entityID;
|
||||
emit clickDownOnEntity(_currentClickingOnEntityID, MouseEvent(*event));
|
||||
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "clickDownOnEntity", MouseEvent(*event));
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "clickDownOnEntity", MouseEvent(*event));
|
||||
}
|
||||
} else {
|
||||
emit mousePressOffEntity(rayPickResult, event);
|
||||
}
|
||||
|
@ -677,14 +687,18 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) {
|
|||
if (rayPickResult.intersects) {
|
||||
//qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID;
|
||||
emit mouseReleaseOnEntity(rayPickResult, event);
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseReleaseOnEntity", MouseEvent(*event));
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseReleaseOnEntity", MouseEvent(*event));
|
||||
}
|
||||
}
|
||||
|
||||
// Even if we're no longer intersecting with an entity, if we started clicking on it, and now
|
||||
// we're releasing the button, then this is considered a clickOn event
|
||||
if (!_currentClickingOnEntityID.isInvalidID()) {
|
||||
emit clickReleaseOnEntity(_currentClickingOnEntityID, MouseEvent(*event));
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "clickReleaseOnEntity", MouseEvent(*event));
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "clickReleaseOnEntity", MouseEvent(*event));
|
||||
}
|
||||
}
|
||||
|
||||
// makes it the unknown ID, we just released so we can't be clicking on anything
|
||||
|
@ -707,8 +721,10 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
|
|||
RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking);
|
||||
if (rayPickResult.intersects) {
|
||||
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveEvent", MouseEvent(*event));
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveOnEntity", MouseEvent(*event));
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveEvent", MouseEvent(*event));
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "mouseMoveOnEntity", MouseEvent(*event));
|
||||
}
|
||||
|
||||
// handle the hover logic...
|
||||
|
||||
|
@ -716,19 +732,25 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
|
|||
// then we need to send the hover leave.
|
||||
if (!_currentHoverOverEntityID.isInvalidID() && rayPickResult.entityID != _currentHoverOverEntityID) {
|
||||
emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event));
|
||||
_entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", MouseEvent(*event));
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", MouseEvent(*event));
|
||||
}
|
||||
}
|
||||
|
||||
// If the new hover entity does not match the previous hover entity then we are entering the new one
|
||||
// this is true if the _currentHoverOverEntityID is known or unknown
|
||||
if (rayPickResult.entityID != _currentHoverOverEntityID) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverEnterEntity", MouseEvent(*event));
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverEnterEntity", MouseEvent(*event));
|
||||
}
|
||||
}
|
||||
|
||||
// and finally, no matter what, if we're intersecting an entity then we're definitely hovering over it, and
|
||||
// we should send our hover over event
|
||||
emit hoverOverEntity(rayPickResult.entityID, MouseEvent(*event));
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverOverEntity", MouseEvent(*event));
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(rayPickResult.entityID, "hoverOverEntity", MouseEvent(*event));
|
||||
}
|
||||
|
||||
// remember what we're hovering over
|
||||
_currentHoverOverEntityID = rayPickResult.entityID;
|
||||
|
@ -739,7 +761,9 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
|
|||
// send the hover leave for our previous entity
|
||||
if (!_currentHoverOverEntityID.isInvalidID()) {
|
||||
emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event));
|
||||
_entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", MouseEvent(*event));
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(_currentHoverOverEntityID, "hoverLeaveEntity", MouseEvent(*event));
|
||||
}
|
||||
_currentHoverOverEntityID = UNKNOWN_ENTITY_ID; // makes it the unknown ID
|
||||
}
|
||||
}
|
||||
|
@ -748,14 +772,16 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
|
|||
// not yet released the hold then this is still considered a holdingClickOnEntity event
|
||||
if (!_currentClickingOnEntityID.isInvalidID()) {
|
||||
emit holdingClickOnEntity(_currentClickingOnEntityID, MouseEvent(*event));
|
||||
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "holdingClickOnEntity", MouseEvent(*event));
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(_currentClickingOnEntityID, "holdingClickOnEntity", MouseEvent(*event));
|
||||
}
|
||||
}
|
||||
_lastMouseEvent = MouseEvent(*event);
|
||||
_lastMouseEventValid = true;
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
|
||||
if (_tree && !_shuttingDown) {
|
||||
if (_tree && !_shuttingDown && _entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->unloadEntityScript(entityID);
|
||||
}
|
||||
|
||||
|
@ -801,7 +827,7 @@ void EntityTreeRenderer::entitySciptChanging(const EntityItemID& entityID, const
|
|||
void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID, const bool reload) {
|
||||
if (_tree && !_shuttingDown) {
|
||||
EntityItemPointer entity = getTree()->findEntityByEntityItemID(entityID);
|
||||
if (entity && entity->shouldPreloadScript()) {
|
||||
if (entity && entity->shouldPreloadScript() && _entitiesScriptEngine) {
|
||||
QString scriptUrl = entity->getScript();
|
||||
scriptUrl = ResourceManager::normalizeURL(scriptUrl);
|
||||
ScriptEngine::loadEntityScript(_entitiesScriptEngine, entityID, scriptUrl, reload);
|
||||
|
@ -910,12 +936,16 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons
|
|||
// And now the entity scripts
|
||||
if (isCollisionOwner(myNodeID, entityTree, idA, collision)) {
|
||||
emit collisionWithEntity(idA, idB, collision);
|
||||
_entitiesScriptEngine->callEntityScriptMethod(idA, "collisionWithEntity", idB, collision);
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(idA, "collisionWithEntity", idB, collision);
|
||||
}
|
||||
}
|
||||
|
||||
if (isCollisionOwner(myNodeID, entityTree, idA, collision)) {
|
||||
emit collisionWithEntity(idB, idA, collision);
|
||||
_entitiesScriptEngine->callEntityScriptMethod(idB, "collisionWithEntity", idA, collision);
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(idB, "collisionWithEntity", idA, collision);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -941,7 +971,9 @@ void EntityTreeRenderer::updateZone(const EntityItemID& id) {
|
|||
if (zone && zone->contains(_lastAvatarPosition)) {
|
||||
_currentEntitiesInside << id;
|
||||
emit enterEntity(id);
|
||||
_entitiesScriptEngine->callEntityScriptMethod(id, "enterEntity");
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(id, "enterEntity");
|
||||
}
|
||||
if (zone->getVisible()) {
|
||||
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(zone);
|
||||
}
|
||||
|
|
|
@ -342,16 +342,23 @@ void RenderableModelEntityItem::updateModelBounds() {
|
|||
if (!hasModel() || !_model) {
|
||||
return;
|
||||
}
|
||||
if (!_dimensionsInitialized || !_model->isActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
bool movingOrAnimating = isMovingRelativeToParent() || isAnimatingSomething();
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
if ((movingOrAnimating ||
|
||||
bool success;
|
||||
auto transform = getTransform(success);
|
||||
|
||||
if (movingOrAnimating ||
|
||||
_needsInitialSimulation ||
|
||||
_needsJointSimulation ||
|
||||
_model->getTranslation() != getPosition() ||
|
||||
_model->getTranslation() != transform.getTranslation() ||
|
||||
_model->getScaleToFitDimensions() != dimensions ||
|
||||
_model->getRotation() != getRotation() ||
|
||||
_model->getRegistrationPoint() != getRegistrationPoint())
|
||||
&& _model->isActive() && _dimensionsInitialized) {
|
||||
_model->getRotation() != transform.getRotation() ||
|
||||
_model->getRegistrationPoint() != getRegistrationPoint()) {
|
||||
doInitialModelSimulation();
|
||||
_needsJointSimulation = false;
|
||||
}
|
||||
|
@ -423,7 +430,8 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
|||
|
||||
// check to see if when we added our models to the scene they were ready, if they were not ready, then
|
||||
// fix them up in the scene
|
||||
bool shouldShowCollisionHull = (args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS) > 0;
|
||||
bool shouldShowCollisionHull = (args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS) > 0
|
||||
&& getShapeType() == SHAPE_TYPE_COMPOUND;
|
||||
if (_model->needsFixupInScene() || _showCollisionHull != shouldShowCollisionHull) {
|
||||
_showCollisionHull = shouldShowCollisionHull;
|
||||
render::PendingChanges pendingChanges;
|
||||
|
@ -593,7 +601,7 @@ bool RenderableModelEntityItem::isReadyToComputeShape() {
|
|||
|
||||
// the model is still being downloaded.
|
||||
return false;
|
||||
} else if (type == SHAPE_TYPE_STATIC_MESH) {
|
||||
} else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) {
|
||||
return (_model && _model->isLoaded());
|
||||
}
|
||||
return true;
|
||||
|
@ -607,7 +615,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
|||
|
||||
// should never fall in here when collision model not fully loaded
|
||||
// hence we assert that all geometries exist and are loaded
|
||||
assert(_model->isLoaded() && _model->isCollisionLoaded());
|
||||
assert(_model && _model->isLoaded() && _model->isCollisionLoaded());
|
||||
const FBXGeometry& collisionGeometry = _model->getCollisionFBXGeometry();
|
||||
|
||||
ShapeInfo::PointCollection& pointCollection = info.getPointCollection();
|
||||
|
@ -691,14 +699,19 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
|||
}
|
||||
}
|
||||
info.setParams(type, dimensions, _compoundShapeURL);
|
||||
} else if (type == SHAPE_TYPE_STATIC_MESH) {
|
||||
} else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) {
|
||||
updateModelBounds();
|
||||
|
||||
// should never fall in here when model not fully loaded
|
||||
assert(_model && _model->isLoaded());
|
||||
|
||||
// compute meshPart local transforms
|
||||
QVector<glm::mat4> localTransforms;
|
||||
const FBXGeometry& geometry = _model->getFBXGeometry();
|
||||
int numberOfMeshes = geometry.meshes.size();
|
||||
const FBXGeometry& fbxGeometry = _model->getFBXGeometry();
|
||||
int numberOfMeshes = fbxGeometry.meshes.size();
|
||||
int totalNumVertices = 0;
|
||||
for (int i = 0; i < numberOfMeshes; i++) {
|
||||
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||
const FBXMesh& mesh = fbxGeometry.meshes.at(i);
|
||||
if (mesh.clusters.size() > 0) {
|
||||
const FBXCluster& cluster = mesh.clusters.at(0);
|
||||
auto jointMatrix = _model->getRig()->getJointTransform(cluster.jointIndex);
|
||||
|
@ -716,30 +729,42 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
|||
return;
|
||||
}
|
||||
|
||||
updateModelBounds();
|
||||
|
||||
// should never fall in here when collision model not fully loaded
|
||||
assert(_model->isLoaded());
|
||||
auto& meshes = _model->getGeometry()->getGeometry()->getMeshes();
|
||||
int32_t numMeshes = (int32_t)(meshes.size());
|
||||
|
||||
ShapeInfo::PointCollection& pointCollection = info.getPointCollection();
|
||||
pointCollection.clear();
|
||||
|
||||
ShapeInfo::PointList points;
|
||||
ShapeInfo::TriangleIndices& triangleIndices = info.getTriangleIndices();
|
||||
auto& meshes = _model->getGeometry()->getGeometry()->getMeshes();
|
||||
if (type == SHAPE_TYPE_SIMPLE_COMPOUND) {
|
||||
pointCollection.resize(numMeshes);
|
||||
} else {
|
||||
pointCollection.resize(1);
|
||||
}
|
||||
|
||||
Extents extents;
|
||||
int meshCount = 0;
|
||||
int pointListIndex = 0;
|
||||
for (auto& mesh : meshes) {
|
||||
const gpu::BufferView& vertices = mesh->getVertexBuffer();
|
||||
const gpu::BufferView& indices = mesh->getIndexBuffer();
|
||||
const gpu::BufferView& parts = mesh->getPartBuffer();
|
||||
|
||||
ShapeInfo::PointList& points = pointCollection[pointListIndex];
|
||||
|
||||
// reserve room
|
||||
int32_t sizeToReserve = (int32_t)(vertices.getNumElements());
|
||||
if (type == SHAPE_TYPE_SIMPLE_COMPOUND) {
|
||||
// a list of points for each mesh
|
||||
pointListIndex++;
|
||||
} else {
|
||||
// only one list of points
|
||||
sizeToReserve += (int32_t)((gpu::Size)points.size());
|
||||
}
|
||||
points.reserve(sizeToReserve);
|
||||
|
||||
// copy points
|
||||
const glm::mat4& localTransform = localTransforms[meshCount];
|
||||
uint32_t meshIndexOffset = (uint32_t)points.size();
|
||||
const glm::mat4& localTransform = localTransforms[meshCount];
|
||||
gpu::BufferView::Iterator<const glm::vec3> vertexItr = vertices.cbegin<const glm::vec3>();
|
||||
points.reserve((int32_t)((gpu::Size)points.size() + vertices.getNumElements()));
|
||||
while (vertexItr != vertices.cend<const glm::vec3>()) {
|
||||
glm::vec3 point = extractTranslation(localTransform * glm::translate(*vertexItr));
|
||||
points.push_back(point);
|
||||
|
@ -747,55 +772,57 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
|||
++vertexItr;
|
||||
}
|
||||
|
||||
// copy triangleIndices
|
||||
triangleIndices.reserve((int32_t)((gpu::Size)(triangleIndices.size()) + indices.getNumElements()));
|
||||
gpu::BufferView::Iterator<const model::Mesh::Part> partItr = parts.cbegin<const model::Mesh::Part>();
|
||||
while (partItr != parts.cend<const model::Mesh::Part>()) {
|
||||
|
||||
if (partItr->_topology == model::Mesh::TRIANGLES) {
|
||||
assert(partItr->_numIndices % 3 == 0);
|
||||
auto indexItr = indices.cbegin<const gpu::BufferView::Index>() + partItr->_startIndex;
|
||||
auto indexEnd = indexItr + partItr->_numIndices;
|
||||
while (indexItr != indexEnd) {
|
||||
triangleIndices.push_back(*indexItr + meshIndexOffset);
|
||||
++indexItr;
|
||||
}
|
||||
} else if (partItr->_topology == model::Mesh::TRIANGLE_STRIP) {
|
||||
assert(partItr->_numIndices > 2);
|
||||
uint32_t approxNumIndices = 3 * partItr->_numIndices;
|
||||
if (approxNumIndices > (uint32_t)(triangleIndices.capacity() - triangleIndices.size())) {
|
||||
// we underestimated the final size of triangleIndices so we pre-emptively expand it
|
||||
triangleIndices.reserve(triangleIndices.size() + approxNumIndices);
|
||||
}
|
||||
|
||||
auto indexItr = indices.cbegin<const gpu::BufferView::Index>() + partItr->_startIndex;
|
||||
auto indexEnd = indexItr + (partItr->_numIndices - 2);
|
||||
|
||||
// first triangle uses the first three indices
|
||||
triangleIndices.push_back(*(indexItr++) + meshIndexOffset);
|
||||
triangleIndices.push_back(*(indexItr++) + meshIndexOffset);
|
||||
triangleIndices.push_back(*(indexItr++) + meshIndexOffset);
|
||||
|
||||
// the rest use previous and next index
|
||||
uint32_t triangleCount = 1;
|
||||
while (indexItr != indexEnd) {
|
||||
if ((*indexItr) != model::Mesh::PRIMITIVE_RESTART_INDEX) {
|
||||
if (triangleCount % 2 == 0) {
|
||||
// even triangles use first two indices in order
|
||||
triangleIndices.push_back(*(indexItr - 2) + meshIndexOffset);
|
||||
triangleIndices.push_back(*(indexItr - 1) + meshIndexOffset);
|
||||
} else {
|
||||
// odd triangles swap order of first two indices
|
||||
triangleIndices.push_back(*(indexItr - 1) + meshIndexOffset);
|
||||
triangleIndices.push_back(*(indexItr - 2) + meshIndexOffset);
|
||||
}
|
||||
if (type == SHAPE_TYPE_STATIC_MESH) {
|
||||
// copy into triangleIndices
|
||||
ShapeInfo::TriangleIndices& triangleIndices = info.getTriangleIndices();
|
||||
triangleIndices.reserve((int32_t)((gpu::Size)(triangleIndices.size()) + indices.getNumElements()));
|
||||
gpu::BufferView::Iterator<const model::Mesh::Part> partItr = parts.cbegin<const model::Mesh::Part>();
|
||||
while (partItr != parts.cend<const model::Mesh::Part>()) {
|
||||
if (partItr->_topology == model::Mesh::TRIANGLES) {
|
||||
assert(partItr->_numIndices % 3 == 0);
|
||||
auto indexItr = indices.cbegin<const gpu::BufferView::Index>() + partItr->_startIndex;
|
||||
auto indexEnd = indexItr + partItr->_numIndices;
|
||||
while (indexItr != indexEnd) {
|
||||
triangleIndices.push_back(*indexItr + meshIndexOffset);
|
||||
++triangleCount;
|
||||
++indexItr;
|
||||
}
|
||||
} else if (partItr->_topology == model::Mesh::TRIANGLE_STRIP) {
|
||||
assert(partItr->_numIndices > 2);
|
||||
uint32_t approxNumIndices = 3 * partItr->_numIndices;
|
||||
if (approxNumIndices > (uint32_t)(triangleIndices.capacity() - triangleIndices.size())) {
|
||||
// we underestimated the final size of triangleIndices so we pre-emptively expand it
|
||||
triangleIndices.reserve(triangleIndices.size() + approxNumIndices);
|
||||
}
|
||||
|
||||
auto indexItr = indices.cbegin<const gpu::BufferView::Index>() + partItr->_startIndex;
|
||||
auto indexEnd = indexItr + (partItr->_numIndices - 2);
|
||||
|
||||
// first triangle uses the first three indices
|
||||
triangleIndices.push_back(*(indexItr++) + meshIndexOffset);
|
||||
triangleIndices.push_back(*(indexItr++) + meshIndexOffset);
|
||||
triangleIndices.push_back(*(indexItr++) + meshIndexOffset);
|
||||
|
||||
// the rest use previous and next index
|
||||
uint32_t triangleCount = 1;
|
||||
while (indexItr != indexEnd) {
|
||||
if ((*indexItr) != model::Mesh::PRIMITIVE_RESTART_INDEX) {
|
||||
if (triangleCount % 2 == 0) {
|
||||
// even triangles use first two indices in order
|
||||
triangleIndices.push_back(*(indexItr - 2) + meshIndexOffset);
|
||||
triangleIndices.push_back(*(indexItr - 1) + meshIndexOffset);
|
||||
} else {
|
||||
// odd triangles swap order of first two indices
|
||||
triangleIndices.push_back(*(indexItr - 1) + meshIndexOffset);
|
||||
triangleIndices.push_back(*(indexItr - 2) + meshIndexOffset);
|
||||
}
|
||||
triangleIndices.push_back(*indexItr + meshIndexOffset);
|
||||
++triangleCount;
|
||||
}
|
||||
++indexItr;
|
||||
}
|
||||
++indexItr;
|
||||
}
|
||||
++partItr;
|
||||
}
|
||||
++partItr;
|
||||
}
|
||||
++meshCount;
|
||||
}
|
||||
|
@ -808,12 +835,13 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
|||
scaleToFit[i] = 1.0f;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < points.size(); ++i) {
|
||||
points[i] = (points[i] * scaleToFit);
|
||||
for (auto points : pointCollection) {
|
||||
for (int i = 0; i < points.size(); ++i) {
|
||||
points[i] = (points[i] * scaleToFit);
|
||||
}
|
||||
}
|
||||
|
||||
pointCollection.push_back(points);
|
||||
info.setParams(SHAPE_TYPE_STATIC_MESH, 0.5f * dimensions, _modelURL);
|
||||
info.setParams(type, 0.5f * dimensions, _modelURL);
|
||||
} else {
|
||||
ModelEntityItem::computeShapeInfo(info);
|
||||
info.setParams(type, 0.5f * dimensions);
|
||||
|
|
|
@ -101,6 +101,8 @@ const char* shapeTypeNames[] = {
|
|||
"hull",
|
||||
"plane",
|
||||
"compound",
|
||||
"simple-hull",
|
||||
"simple-compound",
|
||||
"static-mesh"
|
||||
};
|
||||
|
||||
|
@ -123,6 +125,8 @@ void buildStringToShapeTypeLookup() {
|
|||
addShapeType(SHAPE_TYPE_HULL);
|
||||
addShapeType(SHAPE_TYPE_PLANE);
|
||||
addShapeType(SHAPE_TYPE_COMPOUND);
|
||||
addShapeType(SHAPE_TYPE_SIMPLE_HULL);
|
||||
addShapeType(SHAPE_TYPE_SIMPLE_COMPOUND);
|
||||
addShapeType(SHAPE_TYPE_STATIC_MESH);
|
||||
}
|
||||
|
||||
|
|
|
@ -904,7 +904,9 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c
|
|||
endDecode = usecTimestampNow();
|
||||
|
||||
const quint64 LAST_EDITED_SERVERSIDE_BUMP = 1; // usec
|
||||
if (!senderNode->getCanRez() && senderNode->getCanRezTmp()) {
|
||||
if ((message.getType() == PacketType::EntityAdd ||
|
||||
(message.getType() == PacketType::EntityEdit && properties.lifetimeChanged())) &&
|
||||
!senderNode->getCanRez() && senderNode->getCanRezTmp()) {
|
||||
// this node is only allowed to rez temporary entities. if need be, cap the lifetime.
|
||||
if (properties.getLifetime() == ENTITY_ITEM_IMMORTAL_LIFETIME ||
|
||||
properties.getLifetime() > _maxTmpEntityLifetime) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <OpenGL/gl.h>
|
||||
#include <OpenGL/glext.h>
|
||||
#include <OpenGL/OpenGL.h>
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -47,13 +47,16 @@ void GLWidget::initializeGL() {
|
|||
// Note, we *DO NOT* want Qt to automatically swap buffers for us. This results in the "ringing" bug mentioned in WL#19514 when we're throttling the framerate.
|
||||
setAutoBufferSwap(false);
|
||||
|
||||
// TODO: write the proper code for linux
|
||||
makeCurrent();
|
||||
#if defined(Q_OS_WIN)
|
||||
if (isValid() && context() && context()->contextHandle()) {
|
||||
_vsyncSupported = context()->contextHandle()->hasExtension("WGL_EXT_swap_control");;
|
||||
}
|
||||
#if defined(Q_OS_WIN)
|
||||
_vsyncSupported = context()->contextHandle()->hasExtension("WGL_EXT_swap_control");
|
||||
#elif defined(Q_OS_MAC)
|
||||
_vsyncSupported = true;
|
||||
#else
|
||||
// TODO: write the proper code for linux
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void GLWidget::paintEvent(QPaintEvent* event) {
|
||||
|
|
|
@ -26,28 +26,43 @@ ProfileRangeBatch::~ProfileRangeBatch() {
|
|||
}
|
||||
#endif
|
||||
|
||||
#define ADD_COMMAND(call) _commands.push_back(COMMAND_##call); _commandOffsets.push_back(_params.size());
|
||||
#define ADD_COMMAND(call) _commands.emplace_back(COMMAND_##call); _commandOffsets.emplace_back(_params.size());
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
Batch::Batch(const CacheState& cacheState) : Batch() {
|
||||
_commands.reserve(cacheState.commandsSize);
|
||||
_commandOffsets.reserve(cacheState.offsetsSize);
|
||||
_params.reserve(cacheState.paramsSize);
|
||||
_data.reserve(cacheState.dataSize);
|
||||
}
|
||||
size_t Batch::_commandsMax { BATCH_PREALLOCATE_MIN };
|
||||
size_t Batch::_commandOffsetsMax { BATCH_PREALLOCATE_MIN };
|
||||
size_t Batch::_paramsMax { BATCH_PREALLOCATE_MIN };
|
||||
size_t Batch::_dataMax { BATCH_PREALLOCATE_MIN };
|
||||
size_t Batch::_objectsMax { BATCH_PREALLOCATE_MIN };
|
||||
size_t Batch::_drawCallInfosMax { BATCH_PREALLOCATE_MIN };
|
||||
|
||||
Batch::CacheState Batch::getCacheState() {
|
||||
return CacheState(_commands.size(), _commandOffsets.size(), _params.size(), _data.size(),
|
||||
_buffers.size(), _textures.size(), _streamFormats.size(), _transforms.size(), _pipelines.size(),
|
||||
_framebuffers.size(), _queries.size());
|
||||
Batch::Batch() {
|
||||
_commands.reserve(_commandsMax);
|
||||
_commandOffsets.reserve(_commandOffsetsMax);
|
||||
_params.reserve(_paramsMax);
|
||||
_data.reserve(_dataMax);
|
||||
_objects.reserve(_objectsMax);
|
||||
_drawCallInfos.reserve(_drawCallInfosMax);
|
||||
}
|
||||
|
||||
Batch::~Batch() {
|
||||
//qDebug() << "Batch::~Batch()... " << getCacheState();
|
||||
_commandsMax = std::max(_commands.size(), _commandsMax);
|
||||
_commandOffsetsMax = std::max(_commandOffsets.size(), _commandOffsetsMax);
|
||||
_paramsMax = std::max(_params.size(), _paramsMax);
|
||||
_dataMax = std::max(_data.size(), _dataMax);
|
||||
_objectsMax = std::max(_objects.size(), _objectsMax);
|
||||
_drawCallInfosMax = std::max(_drawCallInfos.size(), _drawCallInfosMax);
|
||||
}
|
||||
|
||||
void Batch::clear() {
|
||||
_commandsMax = std::max(_commands.size(), _commandsMax);
|
||||
_commandOffsetsMax = std::max(_commandOffsets.size(), _commandOffsetsMax);
|
||||
_paramsMax = std::max(_params.size(), _paramsMax);
|
||||
_dataMax = std::max(_data.size(), _dataMax);
|
||||
_objectsMax = std::max(_objects.size(), _objectsMax);
|
||||
_drawCallInfosMax = std::max(_drawCallInfos.size(), _drawCallInfosMax);
|
||||
|
||||
_commands.clear();
|
||||
_commandOffsets.clear();
|
||||
_params.clear();
|
||||
|
@ -58,6 +73,8 @@ void Batch::clear() {
|
|||
_transforms.clear();
|
||||
_pipelines.clear();
|
||||
_framebuffers.clear();
|
||||
_objects.clear();
|
||||
_drawCallInfos.clear();
|
||||
}
|
||||
|
||||
size_t Batch::cacheData(size_t size, const void* data) {
|
||||
|
@ -72,9 +89,9 @@ size_t Batch::cacheData(size_t size, const void* data) {
|
|||
void Batch::draw(Primitive primitiveType, uint32 numVertices, uint32 startVertex) {
|
||||
ADD_COMMAND(draw);
|
||||
|
||||
_params.push_back(startVertex);
|
||||
_params.push_back(numVertices);
|
||||
_params.push_back(primitiveType);
|
||||
_params.emplace_back(startVertex);
|
||||
_params.emplace_back(numVertices);
|
||||
_params.emplace_back(primitiveType);
|
||||
|
||||
captureDrawCallInfo();
|
||||
}
|
||||
|
@ -82,9 +99,9 @@ void Batch::draw(Primitive primitiveType, uint32 numVertices, uint32 startVertex
|
|||
void Batch::drawIndexed(Primitive primitiveType, uint32 numIndices, uint32 startIndex) {
|
||||
ADD_COMMAND(drawIndexed);
|
||||
|
||||
_params.push_back(startIndex);
|
||||
_params.push_back(numIndices);
|
||||
_params.push_back(primitiveType);
|
||||
_params.emplace_back(startIndex);
|
||||
_params.emplace_back(numIndices);
|
||||
_params.emplace_back(primitiveType);
|
||||
|
||||
captureDrawCallInfo();
|
||||
}
|
||||
|
@ -92,11 +109,11 @@ void Batch::drawIndexed(Primitive primitiveType, uint32 numIndices, uint32 start
|
|||
void Batch::drawInstanced(uint32 numInstances, Primitive primitiveType, uint32 numVertices, uint32 startVertex, uint32 startInstance) {
|
||||
ADD_COMMAND(drawInstanced);
|
||||
|
||||
_params.push_back(startInstance);
|
||||
_params.push_back(startVertex);
|
||||
_params.push_back(numVertices);
|
||||
_params.push_back(primitiveType);
|
||||
_params.push_back(numInstances);
|
||||
_params.emplace_back(startInstance);
|
||||
_params.emplace_back(startVertex);
|
||||
_params.emplace_back(numVertices);
|
||||
_params.emplace_back(primitiveType);
|
||||
_params.emplace_back(numInstances);
|
||||
|
||||
captureDrawCallInfo();
|
||||
}
|
||||
|
@ -104,11 +121,11 @@ void Batch::drawInstanced(uint32 numInstances, Primitive primitiveType, uint32 n
|
|||
void Batch::drawIndexedInstanced(uint32 numInstances, Primitive primitiveType, uint32 numIndices, uint32 startIndex, uint32 startInstance) {
|
||||
ADD_COMMAND(drawIndexedInstanced);
|
||||
|
||||
_params.push_back(startInstance);
|
||||
_params.push_back(startIndex);
|
||||
_params.push_back(numIndices);
|
||||
_params.push_back(primitiveType);
|
||||
_params.push_back(numInstances);
|
||||
_params.emplace_back(startInstance);
|
||||
_params.emplace_back(startIndex);
|
||||
_params.emplace_back(numIndices);
|
||||
_params.emplace_back(primitiveType);
|
||||
_params.emplace_back(numInstances);
|
||||
|
||||
captureDrawCallInfo();
|
||||
}
|
||||
|
@ -116,16 +133,16 @@ void Batch::drawIndexedInstanced(uint32 numInstances, Primitive primitiveType, u
|
|||
|
||||
void Batch::multiDrawIndirect(uint32 numCommands, Primitive primitiveType) {
|
||||
ADD_COMMAND(multiDrawIndirect);
|
||||
_params.push_back(numCommands);
|
||||
_params.push_back(primitiveType);
|
||||
_params.emplace_back(numCommands);
|
||||
_params.emplace_back(primitiveType);
|
||||
|
||||
captureDrawCallInfo();
|
||||
}
|
||||
|
||||
void Batch::multiDrawIndexedIndirect(uint32 nbCommands, Primitive primitiveType) {
|
||||
ADD_COMMAND(multiDrawIndexedIndirect);
|
||||
_params.push_back(nbCommands);
|
||||
_params.push_back(primitiveType);
|
||||
_params.emplace_back(nbCommands);
|
||||
_params.emplace_back(primitiveType);
|
||||
|
||||
captureDrawCallInfo();
|
||||
}
|
||||
|
@ -133,16 +150,16 @@ void Batch::multiDrawIndexedIndirect(uint32 nbCommands, Primitive primitiveType)
|
|||
void Batch::setInputFormat(const Stream::FormatPointer& format) {
|
||||
ADD_COMMAND(setInputFormat);
|
||||
|
||||
_params.push_back(_streamFormats.cache(format));
|
||||
_params.emplace_back(_streamFormats.cache(format));
|
||||
}
|
||||
|
||||
void Batch::setInputBuffer(Slot channel, const BufferPointer& buffer, Offset offset, Offset stride) {
|
||||
ADD_COMMAND(setInputBuffer);
|
||||
|
||||
_params.push_back(stride);
|
||||
_params.push_back(offset);
|
||||
_params.push_back(_buffers.cache(buffer));
|
||||
_params.push_back(channel);
|
||||
_params.emplace_back(stride);
|
||||
_params.emplace_back(offset);
|
||||
_params.emplace_back(_buffers.cache(buffer));
|
||||
_params.emplace_back(channel);
|
||||
}
|
||||
|
||||
void Batch::setInputBuffer(Slot channel, const BufferView& view) {
|
||||
|
@ -163,9 +180,9 @@ void Batch::setInputStream(Slot startChannel, const BufferStream& stream) {
|
|||
void Batch::setIndexBuffer(Type type, const BufferPointer& buffer, Offset offset) {
|
||||
ADD_COMMAND(setIndexBuffer);
|
||||
|
||||
_params.push_back(offset);
|
||||
_params.push_back(_buffers.cache(buffer));
|
||||
_params.push_back(type);
|
||||
_params.emplace_back(offset);
|
||||
_params.emplace_back(_buffers.cache(buffer));
|
||||
_params.emplace_back(type);
|
||||
}
|
||||
|
||||
void Batch::setIndexBuffer(const BufferView& buffer) {
|
||||
|
@ -175,9 +192,9 @@ void Batch::setIndexBuffer(const BufferView& buffer) {
|
|||
void Batch::setIndirectBuffer(const BufferPointer& buffer, Offset offset, Offset stride) {
|
||||
ADD_COMMAND(setIndirectBuffer);
|
||||
|
||||
_params.push_back(_buffers.cache(buffer));
|
||||
_params.push_back(offset);
|
||||
_params.push_back(stride);
|
||||
_params.emplace_back(_buffers.cache(buffer));
|
||||
_params.emplace_back(offset);
|
||||
_params.emplace_back(stride);
|
||||
}
|
||||
|
||||
|
||||
|
@ -191,56 +208,56 @@ void Batch::setModelTransform(const Transform& model) {
|
|||
void Batch::setViewTransform(const Transform& view) {
|
||||
ADD_COMMAND(setViewTransform);
|
||||
|
||||
_params.push_back(_transforms.cache(view));
|
||||
_params.emplace_back(_transforms.cache(view));
|
||||
}
|
||||
|
||||
void Batch::setProjectionTransform(const Mat4& proj) {
|
||||
ADD_COMMAND(setProjectionTransform);
|
||||
|
||||
_params.push_back(cacheData(sizeof(Mat4), &proj));
|
||||
_params.emplace_back(cacheData(sizeof(Mat4), &proj));
|
||||
}
|
||||
|
||||
void Batch::setViewportTransform(const Vec4i& viewport) {
|
||||
ADD_COMMAND(setViewportTransform);
|
||||
|
||||
_params.push_back(cacheData(sizeof(Vec4i), &viewport));
|
||||
_params.emplace_back(cacheData(sizeof(Vec4i), &viewport));
|
||||
}
|
||||
|
||||
void Batch::setDepthRangeTransform(float nearDepth, float farDepth) {
|
||||
ADD_COMMAND(setDepthRangeTransform);
|
||||
|
||||
_params.push_back(farDepth);
|
||||
_params.push_back(nearDepth);
|
||||
_params.emplace_back(farDepth);
|
||||
_params.emplace_back(nearDepth);
|
||||
}
|
||||
|
||||
void Batch::setPipeline(const PipelinePointer& pipeline) {
|
||||
ADD_COMMAND(setPipeline);
|
||||
|
||||
_params.push_back(_pipelines.cache(pipeline));
|
||||
_params.emplace_back(_pipelines.cache(pipeline));
|
||||
}
|
||||
|
||||
void Batch::setStateBlendFactor(const Vec4& factor) {
|
||||
ADD_COMMAND(setStateBlendFactor);
|
||||
|
||||
_params.push_back(factor.x);
|
||||
_params.push_back(factor.y);
|
||||
_params.push_back(factor.z);
|
||||
_params.push_back(factor.w);
|
||||
_params.emplace_back(factor.x);
|
||||
_params.emplace_back(factor.y);
|
||||
_params.emplace_back(factor.z);
|
||||
_params.emplace_back(factor.w);
|
||||
}
|
||||
|
||||
void Batch::setStateScissorRect(const Vec4i& rect) {
|
||||
ADD_COMMAND(setStateScissorRect);
|
||||
|
||||
_params.push_back(cacheData(sizeof(Vec4i), &rect));
|
||||
_params.emplace_back(cacheData(sizeof(Vec4i), &rect));
|
||||
}
|
||||
|
||||
void Batch::setUniformBuffer(uint32 slot, const BufferPointer& buffer, Offset offset, Offset size) {
|
||||
ADD_COMMAND(setUniformBuffer);
|
||||
|
||||
_params.push_back(size);
|
||||
_params.push_back(offset);
|
||||
_params.push_back(_buffers.cache(buffer));
|
||||
_params.push_back(slot);
|
||||
_params.emplace_back(size);
|
||||
_params.emplace_back(offset);
|
||||
_params.emplace_back(_buffers.cache(buffer));
|
||||
_params.emplace_back(slot);
|
||||
}
|
||||
|
||||
void Batch::setUniformBuffer(uint32 slot, const BufferView& view) {
|
||||
|
@ -251,8 +268,8 @@ void Batch::setUniformBuffer(uint32 slot, const BufferView& view) {
|
|||
void Batch::setResourceTexture(uint32 slot, const TexturePointer& texture) {
|
||||
ADD_COMMAND(setResourceTexture);
|
||||
|
||||
_params.push_back(_textures.cache(texture));
|
||||
_params.push_back(slot);
|
||||
_params.emplace_back(_textures.cache(texture));
|
||||
_params.emplace_back(slot);
|
||||
}
|
||||
|
||||
void Batch::setResourceTexture(uint32 slot, const TextureView& view) {
|
||||
|
@ -262,21 +279,21 @@ void Batch::setResourceTexture(uint32 slot, const TextureView& view) {
|
|||
void Batch::setFramebuffer(const FramebufferPointer& framebuffer) {
|
||||
ADD_COMMAND(setFramebuffer);
|
||||
|
||||
_params.push_back(_framebuffers.cache(framebuffer));
|
||||
_params.emplace_back(_framebuffers.cache(framebuffer));
|
||||
|
||||
}
|
||||
|
||||
void Batch::clearFramebuffer(Framebuffer::Masks targets, const Vec4& color, float depth, int stencil, bool enableScissor) {
|
||||
ADD_COMMAND(clearFramebuffer);
|
||||
|
||||
_params.push_back(enableScissor);
|
||||
_params.push_back(stencil);
|
||||
_params.push_back(depth);
|
||||
_params.push_back(color.w);
|
||||
_params.push_back(color.z);
|
||||
_params.push_back(color.y);
|
||||
_params.push_back(color.x);
|
||||
_params.push_back(targets);
|
||||
_params.emplace_back(enableScissor);
|
||||
_params.emplace_back(stencil);
|
||||
_params.emplace_back(depth);
|
||||
_params.emplace_back(color.w);
|
||||
_params.emplace_back(color.z);
|
||||
_params.emplace_back(color.y);
|
||||
_params.emplace_back(color.x);
|
||||
_params.emplace_back(targets);
|
||||
}
|
||||
|
||||
void Batch::clearColorFramebuffer(Framebuffer::Masks targets, const Vec4& color, bool enableScissor) {
|
||||
|
@ -299,40 +316,40 @@ void Batch::blit(const FramebufferPointer& src, const Vec4i& srcViewport,
|
|||
const FramebufferPointer& dst, const Vec4i& dstViewport) {
|
||||
ADD_COMMAND(blit);
|
||||
|
||||
_params.push_back(_framebuffers.cache(src));
|
||||
_params.push_back(srcViewport.x);
|
||||
_params.push_back(srcViewport.y);
|
||||
_params.push_back(srcViewport.z);
|
||||
_params.push_back(srcViewport.w);
|
||||
_params.push_back(_framebuffers.cache(dst));
|
||||
_params.push_back(dstViewport.x);
|
||||
_params.push_back(dstViewport.y);
|
||||
_params.push_back(dstViewport.z);
|
||||
_params.push_back(dstViewport.w);
|
||||
_params.emplace_back(_framebuffers.cache(src));
|
||||
_params.emplace_back(srcViewport.x);
|
||||
_params.emplace_back(srcViewport.y);
|
||||
_params.emplace_back(srcViewport.z);
|
||||
_params.emplace_back(srcViewport.w);
|
||||
_params.emplace_back(_framebuffers.cache(dst));
|
||||
_params.emplace_back(dstViewport.x);
|
||||
_params.emplace_back(dstViewport.y);
|
||||
_params.emplace_back(dstViewport.z);
|
||||
_params.emplace_back(dstViewport.w);
|
||||
}
|
||||
|
||||
void Batch::generateTextureMips(const TexturePointer& texture) {
|
||||
ADD_COMMAND(generateTextureMips);
|
||||
|
||||
_params.push_back(_textures.cache(texture));
|
||||
_params.emplace_back(_textures.cache(texture));
|
||||
}
|
||||
|
||||
void Batch::beginQuery(const QueryPointer& query) {
|
||||
ADD_COMMAND(beginQuery);
|
||||
|
||||
_params.push_back(_queries.cache(query));
|
||||
_params.emplace_back(_queries.cache(query));
|
||||
}
|
||||
|
||||
void Batch::endQuery(const QueryPointer& query) {
|
||||
ADD_COMMAND(endQuery);
|
||||
|
||||
_params.push_back(_queries.cache(query));
|
||||
_params.emplace_back(_queries.cache(query));
|
||||
}
|
||||
|
||||
void Batch::getQuery(const QueryPointer& query) {
|
||||
ADD_COMMAND(getQuery);
|
||||
|
||||
_params.push_back(_queries.cache(query));
|
||||
_params.emplace_back(_queries.cache(query));
|
||||
}
|
||||
|
||||
void Batch::resetStages() {
|
||||
|
@ -341,12 +358,12 @@ void Batch::resetStages() {
|
|||
|
||||
void Batch::runLambda(std::function<void()> f) {
|
||||
ADD_COMMAND(runLambda);
|
||||
_params.push_back(_lambdas.cache(f));
|
||||
_params.emplace_back(_lambdas.cache(f));
|
||||
}
|
||||
|
||||
void Batch::startNamedCall(const std::string& name) {
|
||||
ADD_COMMAND(startNamedCall);
|
||||
_params.push_back(_names.cache(name));
|
||||
_params.emplace_back(_names.cache(name));
|
||||
|
||||
_currentNamedCall = name;
|
||||
}
|
||||
|
@ -422,14 +439,14 @@ void Batch::captureDrawCallInfoImpl() {
|
|||
//_model.getInverseMatrix(_object._modelInverse);
|
||||
object._modelInverse = glm::inverse(object._model);
|
||||
|
||||
_objects.push_back(object);
|
||||
_objects.emplace_back(object);
|
||||
|
||||
// Flag is clean
|
||||
_invalidModel = false;
|
||||
}
|
||||
|
||||
auto& drawCallInfos = getDrawCallInfoBuffer();
|
||||
drawCallInfos.push_back((uint16)_objects.size() - 1);
|
||||
drawCallInfos.emplace_back((uint16)_objects.size() - 1);
|
||||
}
|
||||
|
||||
void Batch::captureDrawCallInfo() {
|
||||
|
@ -458,22 +475,11 @@ void Batch::preExecute() {
|
|||
}
|
||||
}
|
||||
|
||||
QDebug& operator<<(QDebug& debug, const Batch::CacheState& cacheState) {
|
||||
debug << "Batch::CacheState[ "
|
||||
<< "commandsSize:" << cacheState.commandsSize
|
||||
<< "offsetsSize:" << cacheState.offsetsSize
|
||||
<< "paramsSize:" << cacheState.paramsSize
|
||||
<< "dataSize:" << cacheState.dataSize
|
||||
<< "]";
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
||||
// Debugging
|
||||
void Batch::pushProfileRange(const char* name) {
|
||||
#if defined(NSIGHT_FOUND)
|
||||
ADD_COMMAND(pushProfileRange);
|
||||
_params.push_back(_profileRanges.cache(name));
|
||||
_params.emplace_back(_profileRanges.cache(name));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -490,9 +496,9 @@ void Batch::_glActiveBindTexture(uint32 unit, uint32 target, uint32 texture) {
|
|||
setResourceTexture(unit - GL_TEXTURE0, nullptr);
|
||||
|
||||
ADD_COMMAND(glActiveBindTexture);
|
||||
_params.push_back(texture);
|
||||
_params.push_back(target);
|
||||
_params.push_back(unit);
|
||||
_params.emplace_back(texture);
|
||||
_params.emplace_back(target);
|
||||
_params.emplace_back(unit);
|
||||
}
|
||||
|
||||
void Batch::_glUniform1i(int32 location, int32 v0) {
|
||||
|
@ -500,8 +506,8 @@ void Batch::_glUniform1i(int32 location, int32 v0) {
|
|||
return;
|
||||
}
|
||||
ADD_COMMAND(glUniform1i);
|
||||
_params.push_back(v0);
|
||||
_params.push_back(location);
|
||||
_params.emplace_back(v0);
|
||||
_params.emplace_back(location);
|
||||
}
|
||||
|
||||
void Batch::_glUniform1f(int32 location, float v0) {
|
||||
|
@ -509,89 +515,89 @@ void Batch::_glUniform1f(int32 location, float v0) {
|
|||
return;
|
||||
}
|
||||
ADD_COMMAND(glUniform1f);
|
||||
_params.push_back(v0);
|
||||
_params.push_back(location);
|
||||
_params.emplace_back(v0);
|
||||
_params.emplace_back(location);
|
||||
}
|
||||
|
||||
void Batch::_glUniform2f(int32 location, float v0, float v1) {
|
||||
ADD_COMMAND(glUniform2f);
|
||||
|
||||
_params.push_back(v1);
|
||||
_params.push_back(v0);
|
||||
_params.push_back(location);
|
||||
_params.emplace_back(v1);
|
||||
_params.emplace_back(v0);
|
||||
_params.emplace_back(location);
|
||||
}
|
||||
|
||||
void Batch::_glUniform3f(int32 location, float v0, float v1, float v2) {
|
||||
ADD_COMMAND(glUniform3f);
|
||||
|
||||
_params.push_back(v2);
|
||||
_params.push_back(v1);
|
||||
_params.push_back(v0);
|
||||
_params.push_back(location);
|
||||
_params.emplace_back(v2);
|
||||
_params.emplace_back(v1);
|
||||
_params.emplace_back(v0);
|
||||
_params.emplace_back(location);
|
||||
}
|
||||
|
||||
void Batch::_glUniform4f(int32 location, float v0, float v1, float v2, float v3) {
|
||||
ADD_COMMAND(glUniform4f);
|
||||
|
||||
_params.push_back(v3);
|
||||
_params.push_back(v2);
|
||||
_params.push_back(v1);
|
||||
_params.push_back(v0);
|
||||
_params.push_back(location);
|
||||
_params.emplace_back(v3);
|
||||
_params.emplace_back(v2);
|
||||
_params.emplace_back(v1);
|
||||
_params.emplace_back(v0);
|
||||
_params.emplace_back(location);
|
||||
}
|
||||
|
||||
void Batch::_glUniform3fv(int32 location, int count, const float* value) {
|
||||
ADD_COMMAND(glUniform3fv);
|
||||
|
||||
const int VEC3_SIZE = 3 * sizeof(float);
|
||||
_params.push_back(cacheData(count * VEC3_SIZE, value));
|
||||
_params.push_back(count);
|
||||
_params.push_back(location);
|
||||
_params.emplace_back(cacheData(count * VEC3_SIZE, value));
|
||||
_params.emplace_back(count);
|
||||
_params.emplace_back(location);
|
||||
}
|
||||
|
||||
void Batch::_glUniform4fv(int32 location, int count, const float* value) {
|
||||
ADD_COMMAND(glUniform4fv);
|
||||
|
||||
const int VEC4_SIZE = 4 * sizeof(float);
|
||||
_params.push_back(cacheData(count * VEC4_SIZE, value));
|
||||
_params.push_back(count);
|
||||
_params.push_back(location);
|
||||
_params.emplace_back(cacheData(count * VEC4_SIZE, value));
|
||||
_params.emplace_back(count);
|
||||
_params.emplace_back(location);
|
||||
}
|
||||
|
||||
void Batch::_glUniform4iv(int32 location, int count, const int32* value) {
|
||||
ADD_COMMAND(glUniform4iv);
|
||||
|
||||
const int VEC4_SIZE = 4 * sizeof(int);
|
||||
_params.push_back(cacheData(count * VEC4_SIZE, value));
|
||||
_params.push_back(count);
|
||||
_params.push_back(location);
|
||||
_params.emplace_back(cacheData(count * VEC4_SIZE, value));
|
||||
_params.emplace_back(count);
|
||||
_params.emplace_back(location);
|
||||
}
|
||||
|
||||
void Batch::_glUniformMatrix3fv(int32 location, int count, uint8 transpose, const float* value) {
|
||||
ADD_COMMAND(glUniformMatrix3fv);
|
||||
|
||||
const int MATRIX3_SIZE = 9 * sizeof(float);
|
||||
_params.push_back(cacheData(count * MATRIX3_SIZE, value));
|
||||
_params.push_back(transpose);
|
||||
_params.push_back(count);
|
||||
_params.push_back(location);
|
||||
_params.emplace_back(cacheData(count * MATRIX3_SIZE, value));
|
||||
_params.emplace_back(transpose);
|
||||
_params.emplace_back(count);
|
||||
_params.emplace_back(location);
|
||||
}
|
||||
|
||||
void Batch::_glUniformMatrix4fv(int32 location, int count, uint8 transpose, const float* value) {
|
||||
ADD_COMMAND(glUniformMatrix4fv);
|
||||
|
||||
const int MATRIX4_SIZE = 16 * sizeof(float);
|
||||
_params.push_back(cacheData(count * MATRIX4_SIZE, value));
|
||||
_params.push_back(transpose);
|
||||
_params.push_back(count);
|
||||
_params.push_back(location);
|
||||
_params.emplace_back(cacheData(count * MATRIX4_SIZE, value));
|
||||
_params.emplace_back(transpose);
|
||||
_params.emplace_back(count);
|
||||
_params.emplace_back(location);
|
||||
}
|
||||
|
||||
void Batch::_glColor4f(float red, float green, float blue, float alpha) {
|
||||
ADD_COMMAND(glColor4f);
|
||||
|
||||
_params.push_back(alpha);
|
||||
_params.push_back(blue);
|
||||
_params.push_back(green);
|
||||
_params.push_back(red);
|
||||
}
|
||||
_params.emplace_back(alpha);
|
||||
_params.emplace_back(blue);
|
||||
_params.emplace_back(green);
|
||||
_params.emplace_back(red);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include "Transform.h"
|
||||
|
||||
class QDebug;
|
||||
|
||||
#define BATCH_PREALLOCATE_MIN 128
|
||||
namespace gpu {
|
||||
|
||||
enum ReservedSlot {
|
||||
|
@ -87,6 +87,7 @@ public:
|
|||
using NamedBatchDataMap = std::map<std::string, NamedBatchData>;
|
||||
|
||||
DrawCallInfoBuffer _drawCallInfos;
|
||||
static size_t _drawCallInfosMax;
|
||||
|
||||
std::string _currentNamedCall;
|
||||
|
||||
|
@ -96,34 +97,7 @@ public:
|
|||
void captureDrawCallInfo();
|
||||
void captureNamedDrawCallInfo(std::string name);
|
||||
|
||||
class CacheState {
|
||||
public:
|
||||
size_t commandsSize;
|
||||
size_t offsetsSize;
|
||||
size_t paramsSize;
|
||||
size_t dataSize;
|
||||
|
||||
size_t buffersSize;
|
||||
size_t texturesSize;
|
||||
size_t streamFormatsSize;
|
||||
size_t transformsSize;
|
||||
size_t pipelinesSize;
|
||||
size_t framebuffersSize;
|
||||
size_t queriesSize;
|
||||
|
||||
CacheState() : commandsSize(0), offsetsSize(0), paramsSize(0), dataSize(0), buffersSize(0), texturesSize(0),
|
||||
streamFormatsSize(0), transformsSize(0), pipelinesSize(0), framebuffersSize(0), queriesSize(0) { }
|
||||
|
||||
CacheState(size_t commandsSize, size_t offsetsSize, size_t paramsSize, size_t dataSize, size_t buffersSize,
|
||||
size_t texturesSize, size_t streamFormatsSize, size_t transformsSize, size_t pipelinesSize,
|
||||
size_t framebuffersSize, size_t queriesSize) :
|
||||
commandsSize(commandsSize), offsetsSize(offsetsSize), paramsSize(paramsSize), dataSize(dataSize),
|
||||
buffersSize(buffersSize), texturesSize(texturesSize), streamFormatsSize(streamFormatsSize),
|
||||
transformsSize(transformsSize), pipelinesSize(pipelinesSize), framebuffersSize(framebuffersSize), queriesSize(queriesSize) { }
|
||||
};
|
||||
|
||||
Batch() {}
|
||||
Batch(const CacheState& cacheState);
|
||||
Batch();
|
||||
explicit Batch(const Batch& batch);
|
||||
~Batch();
|
||||
|
||||
|
@ -131,9 +105,6 @@ public:
|
|||
|
||||
void preExecute();
|
||||
|
||||
CacheState getCacheState();
|
||||
|
||||
|
||||
// Batches may need to override the context level stereo settings
|
||||
// if they're performing framebuffer copy operations, like the
|
||||
// deferred lighting resolution mechanism
|
||||
|
@ -401,15 +372,25 @@ public:
|
|||
typedef T Data;
|
||||
Data _data;
|
||||
Cache<T>(const Data& data) : _data(data) {}
|
||||
static size_t _max;
|
||||
|
||||
class Vector {
|
||||
public:
|
||||
std::vector< Cache<T> > _items;
|
||||
|
||||
Vector() {
|
||||
_items.reserve(_max);
|
||||
}
|
||||
|
||||
~Vector() {
|
||||
_max = std::max(_items.size(), _max);
|
||||
}
|
||||
|
||||
|
||||
size_t size() const { return _items.size(); }
|
||||
size_t cache(const Data& data) {
|
||||
size_t offset = _items.size();
|
||||
_items.push_back(Cache<T>(data));
|
||||
_items.emplace_back(data);
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
@ -449,9 +430,16 @@ public:
|
|||
}
|
||||
|
||||
Commands _commands;
|
||||
static size_t _commandsMax;
|
||||
|
||||
CommandOffsets _commandOffsets;
|
||||
static size_t _commandOffsetsMax;
|
||||
|
||||
Params _params;
|
||||
static size_t _paramsMax;
|
||||
|
||||
Bytes _data;
|
||||
static size_t _dataMax;
|
||||
|
||||
// SSBO class... layout MUST match the layout in Transform.slh
|
||||
class TransformObject {
|
||||
|
@ -464,6 +452,7 @@ public:
|
|||
bool _invalidModel { true };
|
||||
Transform _currentModel;
|
||||
TransformObjects _objects;
|
||||
static size_t _objectsMax;
|
||||
|
||||
BufferCaches _buffers;
|
||||
TextureCaches _textures;
|
||||
|
@ -491,6 +480,9 @@ protected:
|
|||
void captureDrawCallInfoImpl();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
size_t Batch::Cache<T>::_max = BATCH_PREALLOCATE_MIN;
|
||||
|
||||
}
|
||||
|
||||
#if defined(NSIGHT_FOUND)
|
||||
|
@ -512,6 +504,4 @@ private:
|
|||
|
||||
#endif
|
||||
|
||||
QDebug& operator<<(QDebug& debug, const gpu::Batch::CacheState& cacheState);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -232,11 +232,9 @@ typedef std::shared_ptr<Context> ContextPointer;
|
|||
|
||||
template<typename F>
|
||||
void doInBatch(std::shared_ptr<gpu::Context> context, F f) {
|
||||
static gpu::Batch::CacheState cacheState;
|
||||
gpu::Batch batch(cacheState);
|
||||
gpu::Batch batch;
|
||||
f(batch);
|
||||
context->render(batch);
|
||||
cacheState = batch.getCacheState();
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -49,7 +49,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
case PacketType::EntityAdd:
|
||||
case PacketType::EntityEdit:
|
||||
case PacketType::EntityData:
|
||||
return VERSION_MODEL_ENTITIES_SUPPORT_STATIC_MESH;
|
||||
return VERSION_MODEL_ENTITIES_SUPPORT_SIMPLE_HULLS;
|
||||
case PacketType::AvatarIdentity:
|
||||
case PacketType::AvatarData:
|
||||
case PacketType::BulkAvatarData:
|
||||
|
|
|
@ -181,6 +181,7 @@ const PacketVersion VERSION_ENTITIES_NO_FLY_ZONES = 58;
|
|||
const PacketVersion VERSION_ENTITIES_MORE_SHAPES = 59;
|
||||
const PacketVersion VERSION_ENTITIES_PROPERLY_ENCODE_SHAPE_EDITS = 60;
|
||||
const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_STATIC_MESH = 61;
|
||||
const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_SIMPLE_HULLS = 62;
|
||||
|
||||
enum class AvatarMixerPacketVersion : PacketVersion {
|
||||
TranslationSupport = 17,
|
||||
|
|
|
@ -204,7 +204,7 @@ btTriangleIndexVertexArray* createStaticMeshArray(const ShapeInfo& info) {
|
|||
if (numIndices < INT16_MAX) {
|
||||
int16_t* indices = static_cast<int16_t*>((void*)(mesh.m_triangleIndexBase));
|
||||
for (int32_t i = 0; i < numIndices; ++i) {
|
||||
indices[i] = triangleIndices[i];
|
||||
indices[i] = (int16_t)triangleIndices[i];
|
||||
}
|
||||
} else {
|
||||
int32_t* indices = static_cast<int32_t*>((void*)(mesh.m_triangleIndexBase));
|
||||
|
@ -257,7 +257,9 @@ btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) {
|
|||
shape = new btCapsuleShape(radius, height);
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_COMPOUND: {
|
||||
case SHAPE_TYPE_COMPOUND:
|
||||
case SHAPE_TYPE_SIMPLE_HULL:
|
||||
case SHAPE_TYPE_SIMPLE_COMPOUND: {
|
||||
const ShapeInfo::PointCollection& pointCollection = info.getPointCollection();
|
||||
uint32_t numSubShapes = info.getNumSubShapes();
|
||||
if (numSubShapes == 1) {
|
||||
|
|
|
@ -83,12 +83,19 @@ void ShapeInfo::setOffset(const glm::vec3& offset) {
|
|||
}
|
||||
|
||||
uint32_t ShapeInfo::getNumSubShapes() const {
|
||||
if (_type == SHAPE_TYPE_NONE) {
|
||||
return 0;
|
||||
} else if (_type == SHAPE_TYPE_COMPOUND) {
|
||||
return _pointCollection.size();
|
||||
switch (_type) {
|
||||
case SHAPE_TYPE_NONE:
|
||||
return 0;
|
||||
case SHAPE_TYPE_COMPOUND:
|
||||
case SHAPE_TYPE_SIMPLE_COMPOUND:
|
||||
return _pointCollection.size();
|
||||
case SHAPE_TYPE_SIMPLE_HULL:
|
||||
case SHAPE_TYPE_STATIC_MESH:
|
||||
assert(_pointCollection.size() == 1);
|
||||
// yes fall through to default
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ShapeInfo::getLargestSubshapePointCount() const {
|
||||
|
|
|
@ -39,6 +39,8 @@ enum ShapeType {
|
|||
SHAPE_TYPE_HULL,
|
||||
SHAPE_TYPE_PLANE,
|
||||
SHAPE_TYPE_COMPOUND,
|
||||
SHAPE_TYPE_SIMPLE_HULL,
|
||||
SHAPE_TYPE_SIMPLE_COMPOUND,
|
||||
SHAPE_TYPE_STATIC_MESH
|
||||
};
|
||||
|
||||
|
|
|
@ -68,18 +68,48 @@ bool OculusLegacyDisplayPlugin::isSupported() const {
|
|||
}
|
||||
|
||||
auto hmd = ovrHmd_Create(0);
|
||||
|
||||
// The Oculus SDK seems to have trouble finding the right screen sometimes, so we have to guess
|
||||
// Guesses, in order of best match:
|
||||
// - resolution and position match
|
||||
// - resolution and one component of position match
|
||||
// - resolution matches
|
||||
// - position matches
|
||||
// If it still picks the wrong screen, you'll have to mess with your monitor configuration
|
||||
QList<int> matches({ -1, -1, -1, -1 });
|
||||
if (hmd) {
|
||||
QPoint targetPosition{ hmd->WindowsPos.x, hmd->WindowsPos.y };
|
||||
QSize targetResolution{ hmd->Resolution.w, hmd->Resolution.h };
|
||||
auto screens = qApp->screens();
|
||||
for(int i = 0; i < screens.size(); ++i) {
|
||||
auto screen = screens[i];
|
||||
QPoint position = screen->geometry().topLeft();
|
||||
if (position == targetPosition) {
|
||||
_hmdScreen = i;
|
||||
break;
|
||||
QSize resolution = screen->geometry().size();
|
||||
|
||||
if (position == targetPosition && resolution == targetResolution) {
|
||||
matches[0] = i;
|
||||
} else if ((position.x() == targetPosition.x() || position.y() == targetPosition.y()) &&
|
||||
resolution == targetResolution) {
|
||||
matches[1] = i;
|
||||
} else if (resolution == targetResolution) {
|
||||
matches[2] = i;
|
||||
} else if (position == targetPosition) {
|
||||
matches[3] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int screen : matches) {
|
||||
if (screen != -1) {
|
||||
_hmdScreen = screen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_hmdScreen == -1) {
|
||||
qDebug() << "Could not find Rift screen";
|
||||
result = false;
|
||||
}
|
||||
|
||||
ovr_Shutdown();
|
||||
return result;
|
||||
|
|
192
scripts/developer/tests/loadedMachine.js
Normal file
192
scripts/developer/tests/loadedMachine.js
Normal file
|
@ -0,0 +1,192 @@
|
|||
"use strict";
|
||||
/*jslint vars: true, plusplus: true*/
|
||||
/*globals Script, MyAvatar, Quat, Render, ScriptDiscoveryService, Window, LODManager, Entities, print*/
|
||||
//
|
||||
// loadedMachine.js
|
||||
// scripts/developer/tests/
|
||||
//
|
||||
// Created by Howard Stearns on 6/6/16.
|
||||
// Copyright 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
|
||||
//
|
||||
// Characterises the performance of heavily loaded or struggling machines.
|
||||
// There is no point in running this on a machine that producing the target 60 or 90 hz rendering rate.
|
||||
//
|
||||
// The script examines several source of load, including each running script and a couple of Entity types.
|
||||
// It turns all of these off, as well as LOD management, and twirls in place to get a baseline render rate.
|
||||
// Then it turns each load on, one at a time, and records a new render rate.
|
||||
// At the end, it reports the ordered results (in a popup), restores the original loads and LOD management, and quits.
|
||||
//
|
||||
// Small performance changes are not meaningful.
|
||||
// If you think you find something that is significant, you should probably run again to make sure that it isn't random variation.
|
||||
// You can also compare (e.g., the baseline) for different conditions such as domain, version, server settings, etc.
|
||||
// This does not profile scripts as they are used -- it merely measures the effect of having the script loaded and running quietly.
|
||||
|
||||
var NUMBER_OF_TWIRLS_PER_LOAD = 10;
|
||||
var MILLISECONDS_PER_SECOND = 1000;
|
||||
var WAIT_TIME_MILLISECONDS = MILLISECONDS_PER_SECOND;
|
||||
var accumulatedRotation = 0;
|
||||
var start;
|
||||
var frames = 0;
|
||||
var config = Render.getConfig("Stats");
|
||||
var thisPath = Script.resolvePath('');
|
||||
var scriptData = ScriptDiscoveryService.getRunning();
|
||||
var scripts = scriptData.filter(function (datum) { return datum.name !== 'defaultScripts.js'; }).map(function (script) { return script.path; });
|
||||
// If defaultScripts.js is running, we leave it running, because restarting it safely is a mess.
|
||||
var otherScripts = scripts.filter(function (path) { return path !== thisPath; });
|
||||
var numberLeftRunning = scriptData.length - otherScripts.length;
|
||||
print('initially running', otherScripts.length, 'scripts. Leaving', numberLeftRunning, 'and stopping', otherScripts);
|
||||
var typedEntities = {Light: [], ParticleEffect: []};
|
||||
var interestingTypes = Object.keys(typedEntities);
|
||||
var propertiedEntities = {dynamic: []};
|
||||
var interestingProperties = Object.keys(propertiedEntities);
|
||||
var loads = ['ignore', 'baseline'].concat(otherScripts, interestingTypes, interestingProperties);
|
||||
var loadIndex = 0, nLoads = loads.length, load;
|
||||
var results = [];
|
||||
var initialLodIsAutomatic = LODManager.getAutomaticLODAdjust();
|
||||
var SEARCH_RADIUS = 17000;
|
||||
var DEFAULT_LOD = 32768 * 400;
|
||||
LODManager.setAutomaticLODAdjust(false);
|
||||
LODManager.setOctreeSizeScale(DEFAULT_LOD);
|
||||
|
||||
// Fill the typedEnties with the entityIDs that are already visible. It would be nice if this were more efficient.
|
||||
var allEntities = Entities.findEntities(MyAvatar.position, SEARCH_RADIUS);
|
||||
print('Searching', allEntities.length, 'entities for', interestingTypes, 'and', interestingProperties);
|
||||
var propertiesToGet = ['type', 'visible'].concat(interestingProperties);
|
||||
allEntities.forEach(function (entityID) {
|
||||
var properties = Entities.getEntityProperties(entityID, propertiesToGet);
|
||||
if (properties.visible) {
|
||||
if (interestingTypes.indexOf(properties.type) >= 0) {
|
||||
typedEntities[properties.type].push(entityID);
|
||||
} else {
|
||||
interestingProperties.forEach(function (property) {
|
||||
if (entityID && properties[property]) {
|
||||
propertiedEntities[property].push(entityID);
|
||||
entityID = false; // Put in only one bin
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
allEntities = undefined; // free them
|
||||
interestingTypes.forEach(function (type) {
|
||||
print('There are', typedEntities[type].length, type, 'entities.');
|
||||
});
|
||||
interestingProperties.forEach(function (property) {
|
||||
print('There are', propertiedEntities[property].length, property, 'entities.');
|
||||
});
|
||||
function toggleVisibility(type, on) {
|
||||
typedEntities[type].forEach(function (entityID) {
|
||||
Entities.editEntity(entityID, {visible: on});
|
||||
});
|
||||
}
|
||||
function toggleProperty(property, on) {
|
||||
propertiedEntities[property].forEach(function (entityID) {
|
||||
var properties = {};
|
||||
properties[property] = on;
|
||||
Entities.editEntity(entityID, properties);
|
||||
});
|
||||
}
|
||||
function restoreOneTest(load) {
|
||||
print('restore', load);
|
||||
switch (load) {
|
||||
case 'baseline':
|
||||
case 'ignore': // ignore is used to do a twirl to make sure everything is loaded.
|
||||
break;
|
||||
case 'Light':
|
||||
case 'ParticleEffect':
|
||||
toggleVisibility(load, true);
|
||||
break;
|
||||
case 'dynamic':
|
||||
toggleProperty(load, 1);
|
||||
break;
|
||||
default:
|
||||
Script.load(load);
|
||||
}
|
||||
}
|
||||
function undoOneTest(load) {
|
||||
print('stop', load);
|
||||
switch (load) {
|
||||
case 'baseline':
|
||||
case 'ignore':
|
||||
break;
|
||||
case 'Light':
|
||||
case 'ParticleEffect':
|
||||
toggleVisibility(load, false);
|
||||
break;
|
||||
case 'dynamic':
|
||||
toggleProperty(load, 0);
|
||||
break;
|
||||
default:
|
||||
ScriptDiscoveryService.stopScript(load);
|
||||
}
|
||||
}
|
||||
loads.forEach(undoOneTest);
|
||||
|
||||
function finalReport() {
|
||||
var baseline = results[0];
|
||||
results.forEach(function (result) {
|
||||
result.ratio = (baseline.fps / result.fps);
|
||||
});
|
||||
results.sort(function (a, b) { return b.ratio - a.ratio; });
|
||||
var report = 'Performance Report:\nBaseline: ' + baseline.fps.toFixed(1) + ' fps.';
|
||||
results.forEach(function (result) {
|
||||
report += '\n' + result.ratio.toFixed(2) + ' (' + result.fps.toFixed(1) + ' fps over ' + result.elapsed + ' seconds) for ' + result.name;
|
||||
});
|
||||
Window.alert(report);
|
||||
LODManager.setAutomaticLODAdjust(initialLodIsAutomatic);
|
||||
loads.forEach(restoreOneTest);
|
||||
Script.stop();
|
||||
}
|
||||
|
||||
function onNewStats() { // Accumulates frames on signal during load test
|
||||
frames++;
|
||||
}
|
||||
var DEGREES_PER_FULL_TWIRL = 360;
|
||||
var DEGREES_PER_UPDATE = 6;
|
||||
function onUpdate() { // Spins on update signal during load test
|
||||
MyAvatar.orientation = Quat.fromPitchYawRollDegrees(0, accumulatedRotation, 0);
|
||||
accumulatedRotation += DEGREES_PER_UPDATE;
|
||||
if (accumulatedRotation >= (DEGREES_PER_FULL_TWIRL * NUMBER_OF_TWIRLS_PER_LOAD)) {
|
||||
tearDown();
|
||||
}
|
||||
}
|
||||
function startTest() {
|
||||
print('start', load);
|
||||
accumulatedRotation = frames = 0;
|
||||
start = Date.now();
|
||||
Script.update.connect(onUpdate);
|
||||
config.newStats.connect(onNewStats);
|
||||
}
|
||||
|
||||
function setup() {
|
||||
if (loadIndex >= nLoads) {
|
||||
return finalReport();
|
||||
}
|
||||
load = loads[loadIndex];
|
||||
restoreOneTest(load);
|
||||
Script.setTimeout(startTest, WAIT_TIME_MILLISECONDS);
|
||||
}
|
||||
function tearDown() {
|
||||
var now = Date.now();
|
||||
var elapsed = (now - start) / MILLISECONDS_PER_SECOND;
|
||||
Script.update.disconnect(onUpdate);
|
||||
config.newStats.disconnect(onNewStats);
|
||||
if (load !== 'ignore') {
|
||||
results.push({name: load, fps: frames / elapsed, elapsed: elapsed});
|
||||
}
|
||||
undoOneTest(load);
|
||||
loadIndex++;
|
||||
setup();
|
||||
}
|
||||
function waitUntilStopped() { // Wait until all the scripts have stopped
|
||||
var count = ScriptDiscoveryService.getRunning().length;
|
||||
if (count === numberLeftRunning) {
|
||||
return setup();
|
||||
}
|
||||
print('Still', count, 'scripts running');
|
||||
Script.setTimeout(waitUntilStopped, WAIT_TIME_MILLISECONDS);
|
||||
}
|
||||
waitUntilStopped();
|
|
@ -221,6 +221,14 @@ function entityHasActions(entityID) {
|
|||
return Entities.getActionIDs(entityID).length > 0;
|
||||
}
|
||||
|
||||
function findRayIntersection(pickRay, precise, include, exclude) {
|
||||
var entities = Entities.findRayIntersection(pickRay, precise, include, exclude);
|
||||
var overlays = Overlays.findRayIntersection(pickRay);
|
||||
if (!overlays.intersects || (entities.intersects && (entities.distance <= overlays.distance))) {
|
||||
return entities;
|
||||
}
|
||||
return overlays;
|
||||
}
|
||||
function entityIsGrabbedByOther(entityID) {
|
||||
// by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*.
|
||||
var actionIDs = Entities.getActionIDs(entityID);
|
||||
|
@ -251,6 +259,10 @@ function propsArePhysical(props) {
|
|||
// If another script is managing the reticle (as is done by HandControllerPointer), we should not be setting it here,
|
||||
// and we should not be showing lasers when someone else is using the Reticle to indicate a 2D minor mode.
|
||||
var EXTERNALLY_MANAGED_2D_MINOR_MODE = true;
|
||||
var EDIT_SETTING = "io.highfidelity.isEditting";
|
||||
function isEditing() {
|
||||
return EXTERNALLY_MANAGED_2D_MINOR_MODE && Settings.getValue(EDIT_SETTING);
|
||||
}
|
||||
function isIn2DMode() {
|
||||
// In this version, we make our own determination of whether we're aimed a HUD element,
|
||||
// because other scripts (such as handControllerPointer) might be using some other visualization
|
||||
|
@ -1069,20 +1081,15 @@ function MyController(hand) {
|
|||
|
||||
var intersection;
|
||||
if (USE_BLACKLIST === true && blacklist.length !== 0) {
|
||||
intersection = Entities.findRayIntersection(pickRayBacked, true, [], blacklist);
|
||||
intersection = findRayIntersection(pickRayBacked, true, [], blacklist);
|
||||
} else {
|
||||
intersection = Entities.findRayIntersection(pickRayBacked, true);
|
||||
}
|
||||
|
||||
var overlayIntersection = Overlays.findRayIntersection(pickRayBacked);
|
||||
if (!intersection.intersects ||
|
||||
(overlayIntersection.intersects && (intersection.distance > overlayIntersection.distance))) {
|
||||
intersection = overlayIntersection;
|
||||
intersection = findRayIntersection(pickRayBacked, true);
|
||||
}
|
||||
|
||||
if (intersection.intersects) {
|
||||
return {
|
||||
entityID: intersection.entityID,
|
||||
overlayID: intersection.overlayID,
|
||||
searchRay: pickRay,
|
||||
distance: Vec3.distance(pickRay.origin, intersection.intersection)
|
||||
};
|
||||
|
@ -1326,6 +1333,8 @@ function MyController(hand) {
|
|||
if (this.entityIsGrabbable(rayPickInfo.entityID) && rayPickInfo.distance < NEAR_GRAB_PICK_RADIUS) {
|
||||
grabbableEntities.push(rayPickInfo.entityID);
|
||||
}
|
||||
} else if (rayPickInfo.overlayID) {
|
||||
this.intersectionDistance = rayPickInfo.distance;
|
||||
} else {
|
||||
this.intersectionDistance = 0;
|
||||
}
|
||||
|
@ -1382,7 +1391,7 @@ function MyController(hand) {
|
|||
// TODO: highlight the far-triggerable object?
|
||||
}
|
||||
} else if (this.entityIsDistanceGrabbable(rayPickInfo.entityID, handPosition)) {
|
||||
if (this.triggerSmoothedGrab()) {
|
||||
if (this.triggerSmoothedGrab() && !isEditing()) {
|
||||
this.grabbedEntity = entity;
|
||||
this.setState(STATE_DISTANCE_HOLDING, "distance hold '" + name + "'");
|
||||
return;
|
||||
|
@ -1942,8 +1951,8 @@ function MyController(hand) {
|
|||
|
||||
var now = Date.now();
|
||||
if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) {
|
||||
var intersection = Entities.findRayIntersection(pickRay, true);
|
||||
if (intersection.accurate) {
|
||||
var intersection = findRayIntersection(pickRay, true);
|
||||
if (intersection.accurate || intersection.overlayID) {
|
||||
this.lastPickTime = now;
|
||||
if (intersection.entityID != this.grabbedEntity) {
|
||||
this.callEntityMethodOnGrabbed("stopFarTrigger");
|
||||
|
|
|
@ -332,6 +332,8 @@ var toolBar = (function() {
|
|||
entityListTool.clearEntityList();
|
||||
};
|
||||
|
||||
var EDIT_SETTING = "io.highfidelity.isEditting"; // for communication with other scripts
|
||||
Settings.setValue(EDIT_SETTING, false);
|
||||
that.setActive = function(active) {
|
||||
if (active != isActive) {
|
||||
if (active && !Entities.canRez() && !Entities.canRezTmp()) {
|
||||
|
@ -341,6 +343,7 @@ var toolBar = (function() {
|
|||
enabled: active
|
||||
}));
|
||||
isActive = active;
|
||||
Settings.setValue(EDIT_SETTING, active);
|
||||
if (!isActive) {
|
||||
entityListTool.setVisible(false);
|
||||
gridTool.setVisible(false);
|
||||
|
@ -348,6 +351,7 @@ var toolBar = (function() {
|
|||
propertiesTool.setVisible(false);
|
||||
selectionManager.clearSelections();
|
||||
cameraManager.disable();
|
||||
selectionDisplay.triggerMapping.disable();
|
||||
} else {
|
||||
UserActivityLogger.enabledEdit();
|
||||
hasShownPropertiesTool = false;
|
||||
|
@ -356,6 +360,7 @@ var toolBar = (function() {
|
|||
grid.setEnabled(true);
|
||||
propertiesTool.setVisible(true);
|
||||
// Not sure what the following was meant to accomplish, but it currently causes
|
||||
selectionDisplay.triggerMapping.enable();
|
||||
// everybody else to think that Interface has lost focus overall. fogbugzid:558
|
||||
// Window.setFocus();
|
||||
}
|
||||
|
@ -1438,6 +1443,9 @@ function pushCommandForSelections(createdEntityData, deletedEntityData) {
|
|||
var entityID = SelectionManager.selections[i];
|
||||
var initialProperties = SelectionManager.savedProperties[entityID];
|
||||
var currentProperties = Entities.getEntityProperties(entityID);
|
||||
if (!initialProperties) {
|
||||
continue;
|
||||
}
|
||||
undoData.setProperties.push({
|
||||
entityID: entityID,
|
||||
properties: {
|
||||
|
|
|
@ -1646,6 +1646,8 @@
|
|||
<option value="box">Box</option>
|
||||
<option value="sphere">Sphere</option>
|
||||
<option value="compound">Compound</option>
|
||||
<option value="simple-hull">One Hull</option>
|
||||
<option value="simple-compound">Hull Per Submesh</option>
|
||||
<option value="static-mesh">Static Mesh</option>
|
||||
</select>
|
||||
</div>
|
||||
|
|
|
@ -1005,6 +1005,56 @@ SelectionDisplay = (function() {
|
|||
var activeTool = null;
|
||||
var grabberTools = {};
|
||||
|
||||
// We get mouseMoveEvents from the handControllers, via handControllerPointer.
|
||||
// But we dont' get mousePressEvents.
|
||||
that.triggerMapping = Controller.newMapping(Script.resolvePath('') + '-click');
|
||||
Script.scriptEnding.connect(that.triggerMapping.disable);
|
||||
that.TRIGGER_GRAB_VALUE = 0.85; // From handControllerGrab/Pointer.js. Should refactor.
|
||||
that.TRIGGER_ON_VALUE = 0.4;
|
||||
that.TRIGGER_OFF_VALUE = 0.15;
|
||||
that.triggered = false;
|
||||
var activeHand = Controller.Standard.RightHand;
|
||||
function makeTriggerHandler(hand) {
|
||||
return function (value) {
|
||||
if (!that.triggered && (value > that.TRIGGER_GRAB_VALUE)) { // should we smooth?
|
||||
that.triggered = true;
|
||||
if (activeHand !== hand) {
|
||||
// No switching while the other is already triggered, so no need to release.
|
||||
activeHand = (activeHand === Controller.Standard.RightHand) ? Controller.Standard.LeftHand : Controller.Standard.RightHand;
|
||||
}
|
||||
var eventResult = that.mousePressEvent({});
|
||||
if (!eventResult || (eventResult === 'selectionBox')) {
|
||||
var pickRay = controllerComputePickRay();
|
||||
if (pickRay) {
|
||||
var entityIntersection = Entities.findRayIntersection(pickRay, true);
|
||||
var overlayIntersection = Overlays.findRayIntersection(pickRay);
|
||||
if (entityIntersection.intersects &&
|
||||
(!overlayIntersection.intersects || (entityIntersection.distance < overlayIntersection.distance))) {
|
||||
selectionManager.setSelections([entityIntersection.entityID]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (that.triggered && (value < that.TRIGGER_OFF_VALUE)) {
|
||||
that.triggered = false;
|
||||
that.mouseReleaseEvent({});
|
||||
}
|
||||
};
|
||||
}
|
||||
that.triggerMapping.from(Controller.Standard.RT).peek().to(makeTriggerHandler(Controller.Standard.RightHand));
|
||||
that.triggerMapping.from(Controller.Standard.LT).peek().to(makeTriggerHandler(Controller.Standard.LeftHand));
|
||||
function controllerComputePickRay() {
|
||||
var controllerPose = Controller.getPoseValue(activeHand);
|
||||
if (controllerPose.valid && that.triggered) {
|
||||
var controllerPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, controllerPose.translation),
|
||||
MyAvatar.position);
|
||||
// This gets point direction right, but if you want general quaternion it would be more complicated:
|
||||
var controllerDirection = Quat.getUp(Quat.multiply(MyAvatar.orientation, controllerPose.rotation));
|
||||
return {origin: controllerPosition, direction: controllerDirection};
|
||||
}
|
||||
}
|
||||
function generalComputePickRay(x, y) {
|
||||
return controllerComputePickRay() || Camera.computePickRay(x, y);
|
||||
}
|
||||
function addGrabberTool(overlay, tool) {
|
||||
grabberTools[overlay] = {
|
||||
mode: tool.mode,
|
||||
|
@ -1047,7 +1097,7 @@ SelectionDisplay = (function() {
|
|||
lastCameraOrientation = Camera.getOrientation();
|
||||
|
||||
if (event !== false) {
|
||||
pickRay = Camera.computePickRay(event.x, event.y);
|
||||
pickRay = generalComputePickRay(event.x, event.y);
|
||||
|
||||
var wantDebug = false;
|
||||
if (wantDebug) {
|
||||
|
@ -2269,7 +2319,7 @@ SelectionDisplay = (function() {
|
|||
startPosition = SelectionManager.worldPosition;
|
||||
var dimensions = SelectionManager.worldDimensions;
|
||||
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
var pickRay = generalComputePickRay(event.x, event.y);
|
||||
initialXZPick = rayPlaneIntersection(pickRay, translateXZTool.pickPlanePosition, {
|
||||
x: 0,
|
||||
y: 1,
|
||||
|
@ -2312,7 +2362,7 @@ SelectionDisplay = (function() {
|
|||
},
|
||||
onMove: function(event) {
|
||||
var wantDebug = false;
|
||||
pickRay = Camera.computePickRay(event.x, event.y);
|
||||
pickRay = generalComputePickRay(event.x, event.y);
|
||||
|
||||
var pick = rayPlaneIntersection2(pickRay, translateXZTool.pickPlanePosition, {
|
||||
x: 0,
|
||||
|
@ -2422,6 +2472,9 @@ SelectionDisplay = (function() {
|
|||
|
||||
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
||||
var properties = SelectionManager.savedProperties[SelectionManager.selections[i]];
|
||||
if (!properties) {
|
||||
continue;
|
||||
}
|
||||
var newPosition = Vec3.sum(properties.position, {
|
||||
x: vector.x,
|
||||
y: 0,
|
||||
|
@ -2448,7 +2501,7 @@ SelectionDisplay = (function() {
|
|||
addGrabberTool(grabberMoveUp, {
|
||||
mode: "TRANSLATE_UP_DOWN",
|
||||
onBegin: function(event) {
|
||||
pickRay = Camera.computePickRay(event.x, event.y);
|
||||
pickRay = generalComputePickRay(event.x, event.y);
|
||||
|
||||
upDownPickNormal = Quat.getFront(lastCameraOrientation);
|
||||
// Remove y component so the y-axis lies along the plane we picking on - this will
|
||||
|
@ -2481,7 +2534,7 @@ SelectionDisplay = (function() {
|
|||
pushCommandForSelections(duplicatedEntityIDs);
|
||||
},
|
||||
onMove: function(event) {
|
||||
pickRay = Camera.computePickRay(event.x, event.y);
|
||||
pickRay = generalComputePickRay(event.x, event.y);
|
||||
|
||||
// translate mode left/right based on view toward entity
|
||||
var newIntersection = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, upDownPickNormal);
|
||||
|
@ -2690,7 +2743,7 @@ SelectionDisplay = (function() {
|
|||
}
|
||||
}
|
||||
planeNormal = Vec3.multiplyQbyV(rotation, planeNormal);
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
var pickRay = generalComputePickRay(event.x, event.y);
|
||||
lastPick = rayPlaneIntersection(pickRay,
|
||||
pickRayPosition,
|
||||
planeNormal);
|
||||
|
@ -2726,7 +2779,7 @@ SelectionDisplay = (function() {
|
|||
rotation = SelectionManager.worldRotation;
|
||||
}
|
||||
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
var pickRay = generalComputePickRay(event.x, event.y);
|
||||
newPick = rayPlaneIntersection(pickRay,
|
||||
pickRayPosition,
|
||||
planeNormal);
|
||||
|
@ -2782,10 +2835,10 @@ SelectionDisplay = (function() {
|
|||
var wantDebug = false;
|
||||
if (wantDebug) {
|
||||
print(stretchMode);
|
||||
Vec3.print(" newIntersection:", newIntersection);
|
||||
//Vec3.print(" newIntersection:", newIntersection);
|
||||
Vec3.print(" vector:", vector);
|
||||
Vec3.print(" oldPOS:", oldPOS);
|
||||
Vec3.print(" newPOS:", newPOS);
|
||||
//Vec3.print(" oldPOS:", oldPOS);
|
||||
//Vec3.print(" newPOS:", newPOS);
|
||||
Vec3.print(" changeInDimensions:", changeInDimensions);
|
||||
Vec3.print(" newDimensions:", newDimensions);
|
||||
|
||||
|
@ -3350,7 +3403,7 @@ SelectionDisplay = (function() {
|
|||
pushCommandForSelections();
|
||||
},
|
||||
onMove: function(event) {
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
var pickRay = generalComputePickRay(event.x, event.y);
|
||||
Overlays.editOverlay(selectionBox, {
|
||||
ignoreRayIntersection: true,
|
||||
visible: false
|
||||
|
@ -3520,7 +3573,7 @@ SelectionDisplay = (function() {
|
|||
pushCommandForSelections();
|
||||
},
|
||||
onMove: function(event) {
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
var pickRay = generalComputePickRay(event.x, event.y);
|
||||
Overlays.editOverlay(selectionBox, {
|
||||
ignoreRayIntersection: true,
|
||||
visible: false
|
||||
|
@ -3682,7 +3735,7 @@ SelectionDisplay = (function() {
|
|||
pushCommandForSelections();
|
||||
},
|
||||
onMove: function(event) {
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
var pickRay = generalComputePickRay(event.x, event.y);
|
||||
Overlays.editOverlay(selectionBox, {
|
||||
ignoreRayIntersection: true,
|
||||
visible: false
|
||||
|
@ -3797,13 +3850,13 @@ SelectionDisplay = (function() {
|
|||
|
||||
that.mousePressEvent = function(event) {
|
||||
var wantDebug = false;
|
||||
if (!event.isLeftButton) {
|
||||
if (!event.isLeftButton && !that.triggered) {
|
||||
// if another mouse button than left is pressed ignore it
|
||||
return false;
|
||||
}
|
||||
|
||||
var somethingClicked = false;
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
var pickRay = generalComputePickRay(event.x, event.y);
|
||||
|
||||
// before we do a ray test for grabbers, disable the ray intersection for our selection box
|
||||
Overlays.editOverlay(selectionBox, {
|
||||
|
@ -3837,7 +3890,7 @@ SelectionDisplay = (function() {
|
|||
if (tool) {
|
||||
activeTool = tool;
|
||||
mode = tool.mode;
|
||||
somethingClicked = true;
|
||||
somethingClicked = 'tool';
|
||||
if (activeTool && activeTool.onBegin) {
|
||||
activeTool.onBegin(event);
|
||||
}
|
||||
|
@ -3845,7 +3898,7 @@ SelectionDisplay = (function() {
|
|||
switch (result.overlayID) {
|
||||
case grabberMoveUp:
|
||||
mode = "TRANSLATE_UP_DOWN";
|
||||
somethingClicked = true;
|
||||
somethingClicked = mode;
|
||||
|
||||
// in translate mode, we hide our stretch handles...
|
||||
for (var i = 0; i < stretchHandles.length; i++) {
|
||||
|
@ -3860,34 +3913,34 @@ SelectionDisplay = (function() {
|
|||
case grabberEdgeTN: // TODO: maybe this should be TOP+NEAR stretching?
|
||||
case grabberEdgeBN: // TODO: maybe this should be BOTTOM+FAR stretching?
|
||||
mode = "STRETCH_NEAR";
|
||||
somethingClicked = true;
|
||||
somethingClicked = mode;
|
||||
break;
|
||||
|
||||
case grabberFAR:
|
||||
case grabberEdgeTF: // TODO: maybe this should be TOP+FAR stretching?
|
||||
case grabberEdgeBF: // TODO: maybe this should be BOTTOM+FAR stretching?
|
||||
mode = "STRETCH_FAR";
|
||||
somethingClicked = true;
|
||||
somethingClicked = mode;
|
||||
break;
|
||||
case grabberTOP:
|
||||
mode = "STRETCH_TOP";
|
||||
somethingClicked = true;
|
||||
somethingClicked = mode;
|
||||
break;
|
||||
case grabberBOTTOM:
|
||||
mode = "STRETCH_BOTTOM";
|
||||
somethingClicked = true;
|
||||
somethingClicked = mode;
|
||||
break;
|
||||
case grabberRIGHT:
|
||||
case grabberEdgeTR: // TODO: maybe this should be TOP+RIGHT stretching?
|
||||
case grabberEdgeBR: // TODO: maybe this should be BOTTOM+RIGHT stretching?
|
||||
mode = "STRETCH_RIGHT";
|
||||
somethingClicked = true;
|
||||
somethingClicked = mode;
|
||||
break;
|
||||
case grabberLEFT:
|
||||
case grabberEdgeTL: // TODO: maybe this should be TOP+LEFT stretching?
|
||||
case grabberEdgeBL: // TODO: maybe this should be BOTTOM+LEFT stretching?
|
||||
mode = "STRETCH_LEFT";
|
||||
somethingClicked = true;
|
||||
somethingClicked = mode;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -3955,7 +4008,7 @@ SelectionDisplay = (function() {
|
|||
if (tool) {
|
||||
activeTool = tool;
|
||||
mode = tool.mode;
|
||||
somethingClicked = true;
|
||||
somethingClicked = 'tool';
|
||||
if (activeTool && activeTool.onBegin) {
|
||||
activeTool.onBegin(event);
|
||||
}
|
||||
|
@ -3963,7 +4016,7 @@ SelectionDisplay = (function() {
|
|||
switch (result.overlayID) {
|
||||
case yawHandle:
|
||||
mode = "ROTATE_YAW";
|
||||
somethingClicked = true;
|
||||
somethingClicked = mode;
|
||||
overlayOrientation = yawHandleRotation;
|
||||
overlayCenter = yawCenter;
|
||||
yawZero = result.intersection;
|
||||
|
@ -3973,7 +4026,7 @@ SelectionDisplay = (function() {
|
|||
case pitchHandle:
|
||||
mode = "ROTATE_PITCH";
|
||||
initialPosition = SelectionManager.worldPosition;
|
||||
somethingClicked = true;
|
||||
somethingClicked = mode;
|
||||
overlayOrientation = pitchHandleRotation;
|
||||
overlayCenter = pitchCenter;
|
||||
pitchZero = result.intersection;
|
||||
|
@ -3982,7 +4035,7 @@ SelectionDisplay = (function() {
|
|||
|
||||
case rollHandle:
|
||||
mode = "ROTATE_ROLL";
|
||||
somethingClicked = true;
|
||||
somethingClicked = mode;
|
||||
overlayOrientation = rollHandleRotation;
|
||||
overlayCenter = rollCenter;
|
||||
rollZero = result.intersection;
|
||||
|
@ -4156,7 +4209,7 @@ SelectionDisplay = (function() {
|
|||
|
||||
mode = translateXZTool.mode;
|
||||
activeTool.onBegin(event);
|
||||
somethingClicked = true;
|
||||
somethingClicked = 'selectionBox';
|
||||
break;
|
||||
default:
|
||||
if (wantDebug) {
|
||||
|
@ -4169,7 +4222,7 @@ SelectionDisplay = (function() {
|
|||
}
|
||||
|
||||
if (somethingClicked) {
|
||||
pickRay = Camera.computePickRay(event.x, event.y);
|
||||
pickRay = generalComputePickRay(event.x, event.y);
|
||||
if (wantDebug) {
|
||||
print("mousePressEvent()...... " + overlayNames[result.overlayID]);
|
||||
}
|
||||
|
@ -4201,7 +4254,7 @@ SelectionDisplay = (function() {
|
|||
}
|
||||
|
||||
// if no tool is active, then just look for handles to highlight...
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
var pickRay = generalComputePickRay(event.x, event.y);
|
||||
var result = Overlays.findRayIntersection(pickRay);
|
||||
var pickedColor;
|
||||
var pickedAlpha;
|
||||
|
@ -4320,7 +4373,7 @@ SelectionDisplay = (function() {
|
|||
that.updateHandleSizes = function() {
|
||||
if (selectionManager.hasSelection()) {
|
||||
var diff = Vec3.subtract(selectionManager.worldPosition, Camera.getPosition());
|
||||
var grabberSize = Vec3.length(diff) * GRABBER_DISTANCE_TO_SIZE_RATIO * 2;
|
||||
var grabberSize = Vec3.length(diff) * GRABBER_DISTANCE_TO_SIZE_RATIO * 5;
|
||||
var dimensions = SelectionManager.worldDimensions;
|
||||
var avgDimension = (dimensions.x + dimensions.y + dimensions.z) / 3;
|
||||
grabberSize = Math.min(grabberSize, avgDimension / 10);
|
||||
|
|
18
tests/render-perf/CMakeLists.txt
Normal file
18
tests/render-perf/CMakeLists.txt
Normal file
|
@ -0,0 +1,18 @@
|
|||
|
||||
set(TARGET_NAME render-perf-test)
|
||||
|
||||
if (WIN32)
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4049 /ignore:4217")
|
||||
endif()
|
||||
|
||||
# This is not a testcase -- just set it up as a regular hifi project
|
||||
setup_hifi_project(Quick Gui OpenGL)
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(shared octree gl gpu gpu-gl render model model-networking networking render-utils fbx entities entities-renderer animation audio avatars script-engine physics)
|
||||
|
||||
package_libraries_for_deployment()
|
||||
|
||||
|
||||
target_bullet()
|
651
tests/render-perf/src/main.cpp
Normal file
651
tests/render-perf/src/main.cpp
Normal file
|
@ -0,0 +1,651 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/07/01
|
||||
// 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 <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QElapsedTimer>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QThread>
|
||||
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QResizeEvent>
|
||||
#include <QtGui/QWindow>
|
||||
|
||||
#include <QtWidgets/QFileDialog>
|
||||
#include <QtWidgets/QInputDialog>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtWidgets/QApplication>
|
||||
|
||||
#include <shared/RateCounter.h>
|
||||
|
||||
#include <gl/GLHelpers.h>
|
||||
#include <gl/QOpenGLContextWrapper.h>
|
||||
#include <gl/QOpenGLDebugLoggerWrapper.h>
|
||||
|
||||
#include <gpu/gl/GLBackend.h>
|
||||
#include <gpu/gl/GLFramebuffer.h>
|
||||
|
||||
#include <render/Engine.h>
|
||||
#include <Model.h>
|
||||
#include <model/Stage.h>
|
||||
#include <TextureCache.h>
|
||||
#include <FramebufferCache.h>
|
||||
#include <model-networking/ModelCache.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <DeferredLightingEffect.h>
|
||||
#include <RenderShadowTask.h>
|
||||
#include <RenderDeferredTask.h>
|
||||
#include <OctreeConstants.h>
|
||||
|
||||
#include <EntityTreeRenderer.h>
|
||||
#include <AbstractViewStateInterface.h>
|
||||
#include <AddressManager.h>
|
||||
#include <SceneScriptingInterface.h>
|
||||
|
||||
static const QString LAST_SCENE_KEY = "lastSceneFile";
|
||||
|
||||
class ParentFinder : public SpatialParentFinder {
|
||||
public:
|
||||
EntityTreePointer _tree;
|
||||
ParentFinder(EntityTreePointer tree) : _tree(tree) {}
|
||||
|
||||
SpatiallyNestableWeakPointer find(QUuid parentID, bool& success, SpatialParentTree* entityTree = nullptr) const override {
|
||||
SpatiallyNestableWeakPointer parent;
|
||||
|
||||
if (parentID.isNull()) {
|
||||
success = true;
|
||||
return parent;
|
||||
}
|
||||
|
||||
// search entities
|
||||
if (entityTree) {
|
||||
parent = entityTree->findByID(parentID);
|
||||
} else {
|
||||
parent = _tree ? _tree->findEntityByEntityItemID(parentID) : nullptr;
|
||||
}
|
||||
|
||||
if (!parent.expired()) {
|
||||
success = true;
|
||||
return parent;
|
||||
}
|
||||
|
||||
success = false;
|
||||
return parent;
|
||||
}
|
||||
};
|
||||
|
||||
class Camera {
|
||||
protected:
|
||||
float fov { 60.0f };
|
||||
float znear { 0.1f }, zfar { 512.0f };
|
||||
float aspect { 1.0f };
|
||||
|
||||
void updateViewMatrix() {
|
||||
matrices.view = glm::inverse(glm::translate(glm::mat4(), position) * glm::mat4_cast(getOrientation()));
|
||||
}
|
||||
|
||||
glm::quat getOrientation() const {
|
||||
return glm::angleAxis(yaw, Vectors::UP);
|
||||
}
|
||||
public:
|
||||
float yaw { 0 };
|
||||
glm::vec3 position;
|
||||
|
||||
float rotationSpeed { 1.0f };
|
||||
float movementSpeed { 1.0f };
|
||||
|
||||
struct Matrices {
|
||||
glm::mat4 perspective;
|
||||
glm::mat4 view;
|
||||
} matrices;
|
||||
enum Key {
|
||||
RIGHT,
|
||||
LEFT,
|
||||
UP,
|
||||
DOWN,
|
||||
BACK,
|
||||
FORWARD,
|
||||
KEYS_SIZE,
|
||||
INVALID = -1,
|
||||
};
|
||||
|
||||
std::bitset<KEYS_SIZE> keys;
|
||||
|
||||
Camera() {
|
||||
matrices.perspective = glm::perspective(glm::radians(fov), aspect, znear, zfar);
|
||||
}
|
||||
|
||||
bool moving() {
|
||||
return keys.any();
|
||||
}
|
||||
|
||||
void setFieldOfView(float fov) {
|
||||
this->fov = fov;
|
||||
matrices.perspective = glm::perspective(glm::radians(fov), aspect, znear, zfar);
|
||||
}
|
||||
|
||||
void setAspectRatio(const glm::vec2& size) {
|
||||
setAspectRatio(size.x / size.y);
|
||||
}
|
||||
|
||||
void setAspectRatio(float aspect) {
|
||||
this->aspect = aspect;
|
||||
matrices.perspective = glm::perspective(glm::radians(fov), aspect, znear, zfar);
|
||||
}
|
||||
|
||||
void setPerspective(float fov, const glm::vec2& size, float znear = 0.1f, float zfar = 512.0f) {
|
||||
setPerspective(fov, size.x / size.y, znear, zfar);
|
||||
}
|
||||
|
||||
void setPerspective(float fov, float aspect, float znear = 0.1f, float zfar = 512.0f) {
|
||||
this->aspect = aspect;
|
||||
this->fov = fov;
|
||||
this->znear = znear;
|
||||
this->zfar = zfar;
|
||||
matrices.perspective = glm::perspective(glm::radians(fov), aspect, znear, zfar);
|
||||
};
|
||||
|
||||
void rotate(const float delta) {
|
||||
yaw += delta;
|
||||
updateViewMatrix();
|
||||
}
|
||||
|
||||
void setPosition(const glm::vec3& position) {
|
||||
this->position = position;
|
||||
updateViewMatrix();
|
||||
}
|
||||
|
||||
// Translate in the Z axis of the camera
|
||||
void dolly(float delta) {
|
||||
auto direction = glm::vec3(0, 0, delta);
|
||||
translate(direction);
|
||||
}
|
||||
|
||||
// Translate in the XY plane of the camera
|
||||
void translate(const glm::vec2& delta) {
|
||||
auto move = glm::vec3(delta.x, delta.y, 0);
|
||||
translate(move);
|
||||
}
|
||||
|
||||
void translate(const glm::vec3& delta) {
|
||||
position += getOrientation() * delta;
|
||||
updateViewMatrix();
|
||||
}
|
||||
|
||||
void update(float deltaTime) {
|
||||
if (moving()) {
|
||||
glm::vec3 camFront = getOrientation() * Vectors::FRONT;
|
||||
glm::vec3 camRight = getOrientation() * Vectors::RIGHT;
|
||||
glm::vec3 camUp = getOrientation() * Vectors::UP;
|
||||
float moveSpeed = deltaTime * movementSpeed;
|
||||
|
||||
if (keys[FORWARD]) {
|
||||
position += camFront * moveSpeed;
|
||||
}
|
||||
if (keys[BACK]) {
|
||||
position -= camFront * moveSpeed;
|
||||
}
|
||||
if (keys[LEFT]) {
|
||||
position -= camRight * moveSpeed;
|
||||
}
|
||||
if (keys[RIGHT]) {
|
||||
position += camRight * moveSpeed;
|
||||
}
|
||||
if (keys[UP]) {
|
||||
position += camUp * moveSpeed;
|
||||
}
|
||||
if (keys[DOWN]) {
|
||||
position -= camUp * moveSpeed;
|
||||
}
|
||||
updateViewMatrix();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class QWindowCamera : public Camera {
|
||||
Key forKey(int key) {
|
||||
switch (key) {
|
||||
case Qt::Key_W: return FORWARD;
|
||||
case Qt::Key_S: return BACK;
|
||||
case Qt::Key_A: return LEFT;
|
||||
case Qt::Key_D: return RIGHT;
|
||||
case Qt::Key_E: return UP;
|
||||
case Qt::Key_C: return DOWN;
|
||||
default: break;
|
||||
}
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
vec2 _lastMouse;
|
||||
public:
|
||||
void onKeyPress(QKeyEvent* event) {
|
||||
Key k = forKey(event->key());
|
||||
if (k == INVALID) {
|
||||
return;
|
||||
}
|
||||
keys.set(k);
|
||||
}
|
||||
|
||||
void onKeyRelease(QKeyEvent* event) {
|
||||
Key k = forKey(event->key());
|
||||
if (k == INVALID) {
|
||||
return;
|
||||
}
|
||||
keys.reset(k);
|
||||
}
|
||||
|
||||
void onMouseMove(QMouseEvent* event) {
|
||||
vec2 mouse = toGlm(event->localPos());
|
||||
vec2 delta = mouse - _lastMouse;
|
||||
auto buttons = event->buttons();
|
||||
if (buttons & Qt::RightButton) {
|
||||
dolly(delta.y * 0.01f);
|
||||
} else if (buttons & Qt::LeftButton) {
|
||||
rotate(delta.x * -0.01f);
|
||||
} else if (buttons & Qt::MiddleButton) {
|
||||
delta.y *= -1.0f;
|
||||
translate(delta * -0.01f);
|
||||
}
|
||||
|
||||
_lastMouse = mouse;
|
||||
}
|
||||
};
|
||||
|
||||
// Create a simple OpenGL window that renders text in various ways
|
||||
class QTestWindow : public QWindow, public AbstractViewStateInterface {
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
void copyCurrentViewFrustum(ViewFrustum& viewOut) const override {
|
||||
viewOut = _viewFrustum;
|
||||
}
|
||||
|
||||
void copyShadowViewFrustum(ViewFrustum& viewOut) const override {
|
||||
viewOut = _shadowViewFrustum;
|
||||
}
|
||||
|
||||
QThread* getMainThread() override {
|
||||
return QThread::currentThread();
|
||||
}
|
||||
|
||||
PickRay computePickRay(float x, float y) const override {
|
||||
return PickRay();
|
||||
}
|
||||
|
||||
glm::vec3 getAvatarPosition() const override {
|
||||
return vec3();
|
||||
}
|
||||
|
||||
void postLambdaEvent(std::function<void()> f) override {}
|
||||
qreal getDevicePixelRatio() override {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
render::ScenePointer getMain3DScene() override {
|
||||
return _main3DScene;
|
||||
}
|
||||
render::EnginePointer getRenderEngine() override {
|
||||
return _renderEngine;
|
||||
}
|
||||
|
||||
void pushPostUpdateLambda(void* key, std::function<void()> func) override {}
|
||||
|
||||
public:
|
||||
//"/-17.2049,-8.08629,-19.4153/0,0.881994,0,-0.47126"
|
||||
static void setup() {
|
||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
DependencyManager::registerInheritance<SpatialParentFinder, ParentFinder>();
|
||||
DependencyManager::set<AddressManager>();
|
||||
DependencyManager::set<NodeList>(NodeType::Agent, 0);
|
||||
DependencyManager::set<DeferredLightingEffect>();
|
||||
DependencyManager::set<ResourceCacheSharedItems>();
|
||||
DependencyManager::set<TextureCache>();
|
||||
DependencyManager::set<FramebufferCache>();
|
||||
DependencyManager::set<GeometryCache>();
|
||||
DependencyManager::set<ModelCache>();
|
||||
DependencyManager::set<AnimationCache>();
|
||||
DependencyManager::set<ModelBlender>();
|
||||
DependencyManager::set<PathUtils>();
|
||||
DependencyManager::set<SceneScriptingInterface>();
|
||||
}
|
||||
|
||||
QTestWindow() {
|
||||
QThread::currentThread()->setPriority(QThread::HighestPriority);
|
||||
AbstractViewStateInterface::setInstance(this);
|
||||
_octree = DependencyManager::set<EntityTreeRenderer>(false, this, nullptr);
|
||||
_octree->init();
|
||||
DependencyManager::set<ParentFinder>(_octree->getTree());
|
||||
getEntities()->setViewFrustum(_viewFrustum);
|
||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||
NodePermissions permissions;
|
||||
permissions.setAll(true);
|
||||
nodeList->setPermissions(permissions);
|
||||
|
||||
ResourceManager::init();
|
||||
setSurfaceType(QSurface::OpenGLSurface);
|
||||
auto format = getDefaultOpenGLSurfaceFormat();
|
||||
format.setOption(QSurfaceFormat::DebugContext);
|
||||
setFormat(format);
|
||||
|
||||
_context.setFormat(format);
|
||||
_context.create();
|
||||
|
||||
show();
|
||||
makeCurrent();
|
||||
glewInit();
|
||||
glGetError();
|
||||
#ifdef Q_OS_WIN
|
||||
wglSwapIntervalEXT(0);
|
||||
#endif
|
||||
_camera.movementSpeed = 3.0f;
|
||||
|
||||
setupDebugLogger(this);
|
||||
qDebug() << (const char*)glGetString(GL_VERSION);
|
||||
|
||||
// GPU library init
|
||||
{
|
||||
gpu::Context::init<gpu::gl::GLBackend>();
|
||||
_gpuContext = std::make_shared<gpu::Context>();
|
||||
}
|
||||
|
||||
// Render engine library init
|
||||
{
|
||||
makeCurrent();
|
||||
DependencyManager::get<DeferredLightingEffect>()->init();
|
||||
_renderEngine->addJob<RenderShadowTask>("RenderShadowTask", _cullFunctor);
|
||||
_renderEngine->addJob<RenderDeferredTask>("RenderDeferredTask", _cullFunctor);
|
||||
_renderEngine->load();
|
||||
_renderEngine->registerScene(_main3DScene);
|
||||
}
|
||||
|
||||
QVariant lastScene = _settings.value(LAST_SCENE_KEY);
|
||||
if (lastScene.isValid()) {
|
||||
auto result = QMessageBox::question(nullptr, "Question", "Load last scene " + lastScene.toString());
|
||||
if (result != QMessageBox::No) {
|
||||
importScene(lastScene.toString());
|
||||
}
|
||||
}
|
||||
|
||||
resize(QSize(800, 600));
|
||||
_elapsed.start();
|
||||
|
||||
QTimer* timer = new QTimer(this);
|
||||
timer->setInterval(0);
|
||||
connect(timer, &QTimer::timeout, this, [this] {
|
||||
draw();
|
||||
});
|
||||
timer->start();
|
||||
}
|
||||
|
||||
virtual ~QTestWindow() {
|
||||
ResourceManager::cleanup();
|
||||
}
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent* event) override {
|
||||
switch (event->key()) {
|
||||
case Qt::Key_F1:
|
||||
importScene();
|
||||
return;
|
||||
|
||||
case Qt::Key_F2:
|
||||
goTo();
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
_camera.onKeyPress(event);
|
||||
}
|
||||
|
||||
void keyReleaseEvent(QKeyEvent* event) override {
|
||||
_camera.onKeyRelease(event);
|
||||
}
|
||||
|
||||
void mouseMoveEvent(QMouseEvent* event) override {
|
||||
_camera.onMouseMove(event);
|
||||
}
|
||||
|
||||
void resizeEvent(QResizeEvent* ev) override {
|
||||
resizeWindow(ev->size());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static bool cull(const RenderArgs* renderArgs, const AABox& box) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void update() {
|
||||
auto now = usecTimestampNow();
|
||||
static auto last = now;
|
||||
|
||||
float delta = now - last;
|
||||
// Update the camera
|
||||
_camera.update(delta / USECS_PER_SECOND);
|
||||
|
||||
|
||||
// load the view frustum
|
||||
{
|
||||
_viewFrustum.setProjection(_camera.matrices.perspective);
|
||||
auto view = glm::inverse(_camera.matrices.view);
|
||||
_viewFrustum.setPosition(glm::vec3(view[3]));
|
||||
_viewFrustum.setOrientation(glm::quat_cast(view));
|
||||
}
|
||||
last = now;
|
||||
}
|
||||
|
||||
void draw() {
|
||||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
update();
|
||||
|
||||
makeCurrent();
|
||||
#define RENDER_SCENE 1
|
||||
|
||||
#if RENDER_SCENE
|
||||
RenderArgs renderArgs(_gpuContext, _octree.data(), DEFAULT_OCTREE_SIZE_SCALE,
|
||||
0, RenderArgs::DEFAULT_RENDER_MODE,
|
||||
RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
|
||||
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
QSize windowSize = size();
|
||||
framebufferCache->setFrameBufferSize(windowSize);
|
||||
// Viewport is assigned to the size of the framebuffer
|
||||
renderArgs._viewport = ivec4(0, 0, windowSize.width(), windowSize.height());
|
||||
|
||||
renderArgs.setViewFrustum(_viewFrustum);
|
||||
|
||||
// Final framebuffer that will be handled to the display-plugin
|
||||
{
|
||||
auto finalFramebuffer = framebufferCache->getFramebuffer();
|
||||
renderArgs._blitFramebuffer = finalFramebuffer;
|
||||
}
|
||||
|
||||
render(&renderArgs);
|
||||
|
||||
{
|
||||
gpu::gl::GLFramebuffer* framebuffer = gpu::Backend::getGPUObject<gpu::gl::GLFramebuffer>(*renderArgs._blitFramebuffer);
|
||||
auto fbo = framebuffer->_id;
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
const auto& vp = renderArgs._viewport;
|
||||
glBlitFramebuffer(vp.x, vp.y, vp.z, vp.w, vp.x, vp.y, vp.z, vp.w, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
}
|
||||
#else
|
||||
glClearColor(0.0f, 0.5f, 0.8f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
#endif
|
||||
|
||||
_context.swapBuffers(this);
|
||||
|
||||
#if RENDER_SCENE
|
||||
framebufferCache->releaseFramebuffer(renderArgs._blitFramebuffer);
|
||||
renderArgs._blitFramebuffer.reset();
|
||||
gpu::doInBatch(renderArgs._context, [&](gpu::Batch& batch) {
|
||||
batch.resetStages();
|
||||
});
|
||||
#endif
|
||||
fps.increment();
|
||||
static size_t _frameCount { 0 };
|
||||
++_frameCount;
|
||||
if (_elapsed.elapsed() >= 4000) {
|
||||
qDebug() << "FPS " << fps.rate();
|
||||
_frameCount = 0;
|
||||
_elapsed.restart();
|
||||
}
|
||||
|
||||
if (0 == ++_frameCount % 100) {
|
||||
}
|
||||
}
|
||||
|
||||
void render(RenderArgs* renderArgs) {
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
PerformanceTimer perfTimer("draw");
|
||||
// The pending changes collecting the changes here
|
||||
render::PendingChanges pendingChanges;
|
||||
// Setup the current Zone Entity lighting
|
||||
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(_sunSkyStage.getSunLight());
|
||||
{
|
||||
PerformanceTimer perfTimer("SceneProcessPendingChanges");
|
||||
_main3DScene->enqueuePendingChanges(pendingChanges);
|
||||
_main3DScene->processPendingChangesQueue();
|
||||
}
|
||||
|
||||
// For now every frame pass the renderContext
|
||||
{
|
||||
PerformanceTimer perfTimer("EngineRun");
|
||||
_renderEngine->getRenderContext()->args = renderArgs;
|
||||
// Before the deferred pass, let's try to use the render engine
|
||||
_renderEngine->run();
|
||||
}
|
||||
}
|
||||
|
||||
void makeCurrent() {
|
||||
_context.makeCurrent(this);
|
||||
}
|
||||
|
||||
void resizeWindow(const QSize& size) {
|
||||
_size = size;
|
||||
_camera.setAspectRatio((float)_size.width() / (float)_size.height());
|
||||
}
|
||||
|
||||
void parsePath(const QString& viewpointString) {
|
||||
static const QString FLOAT_REGEX_STRING = "([-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?)";
|
||||
static const QString SPACED_COMMA_REGEX_STRING = "\\s*,\\s*";
|
||||
static const QString POSITION_REGEX_STRING = QString("\\/") + FLOAT_REGEX_STRING + SPACED_COMMA_REGEX_STRING +
|
||||
FLOAT_REGEX_STRING + SPACED_COMMA_REGEX_STRING + FLOAT_REGEX_STRING + "\\s*(?:$|\\/)";
|
||||
static const QString QUAT_REGEX_STRING = QString("\\/") + FLOAT_REGEX_STRING + SPACED_COMMA_REGEX_STRING +
|
||||
FLOAT_REGEX_STRING + SPACED_COMMA_REGEX_STRING + FLOAT_REGEX_STRING + SPACED_COMMA_REGEX_STRING +
|
||||
FLOAT_REGEX_STRING + "\\s*$";
|
||||
|
||||
static QRegExp orientationRegex(QUAT_REGEX_STRING);
|
||||
static QRegExp positionRegex(POSITION_REGEX_STRING);
|
||||
|
||||
if (positionRegex.indexIn(viewpointString) != -1) {
|
||||
// we have at least a position, so emit our signal to say we need to change position
|
||||
glm::vec3 newPosition(positionRegex.cap(1).toFloat(),
|
||||
positionRegex.cap(2).toFloat(),
|
||||
positionRegex.cap(3).toFloat());
|
||||
_camera.setPosition(newPosition);
|
||||
|
||||
if (!glm::any(glm::isnan(newPosition))) {
|
||||
// we may also have an orientation
|
||||
if (viewpointString[positionRegex.matchedLength() - 1] == QChar('/')
|
||||
&& orientationRegex.indexIn(viewpointString, positionRegex.matchedLength() - 1) != -1) {
|
||||
//glm::vec4 v = glm::vec4(
|
||||
// orientationRegex.cap(1).toFloat(),
|
||||
// orientationRegex.cap(2).toFloat(),
|
||||
// orientationRegex.cap(3).toFloat(),
|
||||
// orientationRegex.cap(4).toFloat());
|
||||
//if (!glm::any(glm::isnan(v))) {
|
||||
// _camera.setRotation(glm::normalize(glm::quat(v.w, v.x, v.y, v.z)));
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void importScene(const QString& fileName) {
|
||||
_settings.setValue(LAST_SCENE_KEY, fileName);
|
||||
_octree->clear();
|
||||
_octree->getTree()->readFromURL(fileName);
|
||||
}
|
||||
|
||||
void importScene() {
|
||||
QString fileName = QFileDialog::getOpenFileName(nullptr, tr("Open File"), "/home", tr("Hifi Exports (*.json *.svo)"));
|
||||
if (fileName.isNull()) {
|
||||
return;
|
||||
}
|
||||
importScene(fileName);
|
||||
}
|
||||
|
||||
void goTo() {
|
||||
QString destination = QInputDialog::getText(nullptr, tr("Go To Location"), "Enter path");
|
||||
if (destination.isNull()) {
|
||||
return;
|
||||
}
|
||||
parsePath(destination);
|
||||
}
|
||||
|
||||
private:
|
||||
render::CullFunctor _cullFunctor { cull };
|
||||
gpu::ContextPointer _gpuContext; // initialized during window creation
|
||||
render::EnginePointer _renderEngine { new render::Engine() };
|
||||
render::ScenePointer _main3DScene { new render::Scene(glm::vec3(-0.5f * (float)TREE_SCALE), (float)TREE_SCALE) };
|
||||
QOpenGLContextWrapper _context;
|
||||
QSize _size;
|
||||
RateCounter<> fps;
|
||||
QSettings _settings;
|
||||
|
||||
QWindowCamera _camera;
|
||||
ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc.
|
||||
ViewFrustum _shadowViewFrustum; // current state of view frustum, perspective, orientation, etc.
|
||||
model::SunSkyStage _sunSkyStage;
|
||||
model::LightPointer _globalLight { std::make_shared<model::Light>() };
|
||||
QElapsedTimer _elapsed;
|
||||
QSharedPointer<EntityTreeRenderer> _octree;
|
||||
QSharedPointer<EntityTreeRenderer> getEntities() {
|
||||
return _octree;
|
||||
}
|
||||
};
|
||||
|
||||
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
||||
if (!message.isEmpty()) {
|
||||
#ifdef Q_OS_WIN
|
||||
OutputDebugStringA(message.toLocal8Bit().constData());
|
||||
OutputDebugStringA("\n");
|
||||
#endif
|
||||
std::cout << message.toLocal8Bit().constData() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
const char * LOG_FILTER_RULES = R"V0G0N(
|
||||
hifi.gpu=true
|
||||
)V0G0N";
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
QApplication app(argc, argv);
|
||||
QCoreApplication::setApplicationName("RenderPerf");
|
||||
QCoreApplication::setOrganizationName("High Fidelity");
|
||||
QCoreApplication::setOrganizationDomain("highfidelity.com");
|
||||
|
||||
qInstallMessageHandler(messageHandler);
|
||||
QLoggingCategory::setFilterRules(LOG_FILTER_RULES);
|
||||
QTestWindow::setup();
|
||||
QTestWindow window;
|
||||
app.exec();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "main.moc"
|
Loading…
Reference in a new issue