Merge branch 'master' of github.com:highfidelity/hifi into luanch-crash-fix

This commit is contained in:
Dante Ruiz 2017-07-10 17:49:20 +01:00
commit cc86cda737
69 changed files with 1248 additions and 728 deletions

View file

@ -1101,9 +1101,9 @@ Rectangle {
case 'nearbyUsers':
var data = message.params;
var index = -1;
iAmAdmin = Users.canKick;
index = findNearbySessionIndex('', data);
if (index !== -1) {
iAmAdmin = Users.canKick;
myData = data[index];
data.splice(index, 1);
} else {

View file

@ -166,7 +166,7 @@ Rectangle {
ListView {
anchors { left: parent.left; right: parent.right; leftMargin: 70 }
height: 125;
height: Math.min(250, contentHeight);
spacing: 0;
snapMode: ListView.SnapToItem;
clip: true;

View file

@ -112,10 +112,7 @@
#include <plugins/InputConfiguration.h>
#include <RecordingScriptingInterface.h>
#include <RenderableWebEntityItem.h>
#include <RenderShadowTask.h>
#include <render/RenderFetchCullSortTask.h>
#include <RenderDeferredTask.h>
#include <RenderForwardTask.h>
#include <UpdateSceneTask.h>
#include <RenderViewTask.h>
#include <SecondaryCamera.h>
#include <ResourceCache.h>
@ -1973,6 +1970,7 @@ void Application::initializeGL() {
render::CullFunctor cullFunctor = LODManager::shouldRender;
static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD";
bool isDeferred = !QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD);
_renderEngine->addJob<UpdateSceneTask>("UpdateScene");
_renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraFrame", cullFunctor);
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, isDeferred);
_renderEngine->load();
@ -2729,56 +2727,43 @@ bool Application::importSVOFromURL(const QString& urlString) {
return true;
}
bool _renderRequested { false };
bool Application::event(QEvent* event) {
if (!Menu::getInstance()) {
return false;
}
// Presentation/painting logic
// TODO: Decouple presentation and painting loops
static bool isPaintingThrottled = false;
if ((int)event->type() == (int)Present) {
if (isPaintingThrottled) {
// If painting (triggered by presentation) is hogging the main thread,
// repost as low priority to avoid hanging the GUI.
// This has the effect of allowing presentation to exceed the paint budget by X times and
// only dropping every (1/X) frames, instead of every ceil(X) frames
// (e.g. at a 60FPS target, painting for 17us would fall to 58.82FPS instead of 30FPS).
removePostedEvents(this, Present);
postEvent(this, new QEvent(static_cast<QEvent::Type>(Present)), Qt::LowEventPriority);
isPaintingThrottled = false;
int type = event->type();
switch (type) {
case Event::Lambda:
static_cast<LambdaEvent*>(event)->call();
return true;
}
float nsecsElapsed = (float)_lastTimeUpdated.nsecsElapsed();
if (shouldPaint(nsecsElapsed)) {
_lastTimeUpdated.start();
idle(nsecsElapsed);
postEvent(this, new QEvent(static_cast<QEvent::Type>(Paint)), Qt::HighEventPriority);
}
isPaintingThrottled = true;
case Event::Present:
if (!_renderRequested) {
float nsecsElapsed = (float)_lastTimeUpdated.nsecsElapsed();
if (shouldPaint(nsecsElapsed)) {
_renderRequested = true;
_lastTimeUpdated.start();
idle(nsecsElapsed);
postEvent(this, new QEvent(static_cast<QEvent::Type>(Paint)), Qt::HighEventPriority);
}
}
return true;
return true;
} else if ((int)event->type() == (int)Paint) {
// NOTE: This must be updated as close to painting as possible,
// or AvatarInputs will mysteriously move to the bottom-right
AvatarInputs::getInstance()->update();
case Event::Paint:
// NOTE: This must be updated as close to painting as possible,
// or AvatarInputs will mysteriously move to the bottom-right
AvatarInputs::getInstance()->update();
paintGL();
// wait for the next present event before starting idle / paint again
removePostedEvents(this, Present);
_renderRequested = false;
return true;
paintGL();
isPaintingThrottled = false;
return true;
} else if ((int)event->type() == (int)Idle) {
float nsecsElapsed = (float)_lastTimeUpdated.nsecsElapsed();
idle(nsecsElapsed);
return true;
}
if ((int)event->type() == (int)Lambda) {
static_cast<LambdaEvent*>(event)->call();
return true;
default:
break;
}
{
@ -3166,59 +3151,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
break;
#endif
case Qt::Key_H: {
// whenever switching to/from full screen mirror from the keyboard, remember
// the state you were in before full screen mirror, and return to that.
auto previousMode = _myCamera.getMode();
if (previousMode != CAMERA_MODE_MIRROR) {
switch (previousMode) {
case CAMERA_MODE_FIRST_PERSON:
_returnFromFullScreenMirrorTo = MenuOption::FirstPerson;
break;
case CAMERA_MODE_THIRD_PERSON:
_returnFromFullScreenMirrorTo = MenuOption::ThirdPerson;
break;
// FIXME - it's not clear that these modes make sense to return to...
case CAMERA_MODE_INDEPENDENT:
_returnFromFullScreenMirrorTo = MenuOption::IndependentMode;
break;
case CAMERA_MODE_ENTITY:
_returnFromFullScreenMirrorTo = MenuOption::CameraEntityMode;
break;
default:
_returnFromFullScreenMirrorTo = MenuOption::ThirdPerson;
break;
}
}
bool isMirrorChecked = Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror);
Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, !isMirrorChecked);
if (isMirrorChecked) {
// if we got here without coming in from a non-Full Screen mirror case, then our
// _returnFromFullScreenMirrorTo is unknown. In that case we'll go to the old
// behavior of returning to ThirdPerson
if (_returnFromFullScreenMirrorTo.isEmpty()) {
_returnFromFullScreenMirrorTo = MenuOption::ThirdPerson;
}
Menu::getInstance()->setIsOptionChecked(_returnFromFullScreenMirrorTo, true);
}
cameraMenuChanged();
break;
}
case Qt::Key_P: {
if (!(isShifted || isMeta || isOption)) {
bool isFirstPersonChecked = Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson);
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, !isFirstPersonChecked);
Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, isFirstPersonChecked);
cameraMenuChanged();
}
break;
}
case Qt::Key_Slash:
Menu::getInstance()->triggerOption(MenuOption::Stats);
break;
@ -5378,7 +5310,7 @@ namespace render {
auto& batch = *args->_batch;
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch);
renderWorldBox(batch);
renderWorldBox(args, batch);
}
}
}
@ -5441,10 +5373,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
}
{
PerformanceTimer perfTimer("SceneProcessTransaction");
_main3DScene->enqueueTransaction(transaction);
_main3DScene->processTransactionQueue();
}
// For now every frame pass the renderContext
@ -7135,6 +7064,12 @@ void Application::updateDisplayMode() {
// reset the avatar, to set head and hand palms back to a reasonable default pose.
getMyAvatar()->reset(false);
// switch to first person if entering hmd and setting is checked
if (isHmd && menu->isOptionChecked(MenuOption::FirstPersonHMD)) {
menu->setIsOptionChecked(MenuOption::FirstPerson, true);
cameraMenuChanged();
}
Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin");
}

View file

@ -223,7 +223,7 @@ Menu::Menu() {
// View > First Person
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu,
MenuOption::FirstPerson, 0, // QML Qt:: Key_P
MenuOption::FirstPerson, 0,
true, qApp, SLOT(cameraMenuChanged())));
// View > Third Person
@ -233,7 +233,7 @@ Menu::Menu() {
// View > Mirror
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(viewMenu,
MenuOption::FullscreenMirror, 0, // QML Qt::Key_H,
MenuOption::FullscreenMirror, 0,
false, qApp, SLOT(cameraMenuChanged())));
// View > Independent [advanced]
@ -258,6 +258,9 @@ Menu::Menu() {
// View > Overlays
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Overlays, 0, true);
// View > Enter First Person Mode in HMD
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPersonHMD, 0, true);
// Navigate menu ----------------------------------
MenuWrapper* navigateMenu = addMenu("Navigate");

View file

@ -105,6 +105,7 @@ namespace MenuOption {
const QString ExpandPhysicsSimulationTiming = "Expand /physics";
const QString ExpandUpdateTiming = "Expand /update";
const QString FirstPerson = "First Person";
const QString FirstPersonHMD = "Enter First Person Mode in HMD";
const QString FivePointCalibration = "5 Point Calibration";
const QString FixGaze = "Fix Gaze (no saccade)";
const QString Forward = "Forward";

View file

@ -34,7 +34,7 @@
using namespace std;
void renderWorldBox(gpu::Batch& batch) {
void renderWorldBox(RenderArgs* args, gpu::Batch& batch) {
auto geometryCache = DependencyManager::get<GeometryCache>();
// Show center of world
@ -115,7 +115,7 @@ void renderWorldBox(gpu::Batch& batch) {
geometryIds[17]);
geometryCache->renderWireCubeInstance(batch, GREY4);
geometryCache->renderWireCubeInstance(args, batch, GREY4);
// Draw meter markers along the 3 axis to help with measuring things
const float MARKER_DISTANCE = 1.0f;
@ -123,23 +123,23 @@ void renderWorldBox(gpu::Batch& batch) {
transform = Transform().setScale(MARKER_RADIUS);
batch.setModelTransform(transform);
geometryCache->renderSolidSphereInstance(batch, RED);
geometryCache->renderSolidSphereInstance(args, batch, RED);
transform = Transform().setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, 0.0f)).setScale(MARKER_RADIUS);
batch.setModelTransform(transform);
geometryCache->renderSolidSphereInstance(batch, RED);
geometryCache->renderSolidSphereInstance(args, batch, RED);
transform = Transform().setTranslation(glm::vec3(0.0f, MARKER_DISTANCE, 0.0f)).setScale(MARKER_RADIUS);
batch.setModelTransform(transform);
geometryCache->renderSolidSphereInstance(batch, GREEN);
geometryCache->renderSolidSphereInstance(args, batch, GREEN);
transform = Transform().setTranslation(glm::vec3(0.0f, 0.0f, MARKER_DISTANCE)).setScale(MARKER_RADIUS);
batch.setModelTransform(transform);
geometryCache->renderSolidSphereInstance(batch, BLUE);
geometryCache->renderSolidSphereInstance(args, batch, BLUE);
transform = Transform().setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, MARKER_DISTANCE)).setScale(MARKER_RADIUS);
batch.setModelTransform(transform);
geometryCache->renderSolidSphereInstance(batch, GREY);
geometryCache->renderSolidSphereInstance(args, batch, GREY);
}
// Do some basic timing tests and report the results

View file

@ -16,8 +16,9 @@
#include <glm/gtc/quaternion.hpp>
#include <gpu/Batch.h>
#include <render/Forward.h>
void renderWorldBox(gpu::Batch& batch);
void renderWorldBox(RenderArgs* args, gpu::Batch& batch);
void runTimingTests();
void runUnitTests();

View file

@ -80,8 +80,8 @@ void Circle3DOverlay::render(RenderArgs* args) {
Q_ASSERT(args->_batch);
auto& batch = *args->_batch;
if (args->_pipeline) {
batch.setPipeline(args->_pipeline->pipeline);
if (args->_shapePipeline) {
batch.setPipeline(args->_shapePipeline->pipeline);
}
// FIXME: THe line width of _lineWidth is not supported anymore, we ll need a workaround

View file

@ -65,15 +65,15 @@ void Cube3DOverlay::render(RenderArgs* args) {
transform.setTranslation(position);
transform.setRotation(rotation);
auto geometryCache = DependencyManager::get<GeometryCache>();
auto pipeline = args->_pipeline;
if (!pipeline) {
pipeline = _isSolid ? geometryCache->getOpaqueShapePipeline() : geometryCache->getWireShapePipeline();
auto shapePipeline = args->_shapePipeline;
if (!shapePipeline) {
shapePipeline = _isSolid ? geometryCache->getOpaqueShapePipeline() : geometryCache->getWireShapePipeline();
}
if (_isSolid) {
transform.setScale(dimensions);
batch->setModelTransform(transform);
geometryCache->renderSolidCubeInstance(*batch, cubeColor, pipeline);
geometryCache->renderSolidCubeInstance(args, *batch, cubeColor, shapePipeline);
} else {
geometryCache->bindSimpleProgram(*batch, false, false, false, true, true);
if (getIsDashedLine()) {
@ -109,7 +109,7 @@ void Cube3DOverlay::render(RenderArgs* args) {
} else {
transform.setScale(dimensions);
batch->setModelTransform(transform);
geometryCache->renderWireCubeInstance(*batch, cubeColor, pipeline);
geometryCache->renderWireCubeInstance(args, *batch, cubeColor, shapePipeline);
}
}
}

View file

@ -152,6 +152,7 @@ Overlay::Pointer Overlays::getOverlay(OverlayID id) const {
OverlayID Overlays::addOverlay(const QString& type, const QVariant& properties) {
if (QThread::currentThread() != thread()) {
OverlayID result;
PROFILE_RANGE(script, __FUNCTION__);
BLOCKING_INVOKE_METHOD(this, "addOverlay", Q_RETURN_ARG(OverlayID, result), Q_ARG(QString, type), Q_ARG(QVariant, properties));
return result;
}
@ -220,6 +221,7 @@ OverlayID Overlays::addOverlay(const Overlay::Pointer& overlay) {
OverlayID Overlays::cloneOverlay(OverlayID id) {
if (QThread::currentThread() != thread()) {
OverlayID result;
PROFILE_RANGE(script, __FUNCTION__);
BLOCKING_INVOKE_METHOD(this, "cloneOverlay", Q_RETURN_ARG(OverlayID, result), Q_ARG(OverlayID, id));
return result;
}
@ -315,6 +317,7 @@ void Overlays::deleteOverlay(OverlayID id) {
QString Overlays::getOverlayType(OverlayID overlayId) {
if (QThread::currentThread() != thread()) {
QString result;
PROFILE_RANGE(script, __FUNCTION__);
BLOCKING_INVOKE_METHOD(this, "getOverlayType", Q_RETURN_ARG(QString, result), Q_ARG(OverlayID, overlayId));
return result;
}
@ -329,6 +332,7 @@ QString Overlays::getOverlayType(OverlayID overlayId) {
QObject* Overlays::getOverlayObject(OverlayID id) {
if (QThread::currentThread() != thread()) {
QObject* result;
PROFILE_RANGE(script, __FUNCTION__);
BLOCKING_INVOKE_METHOD(this, "getOverlayObject", Q_RETURN_ARG(QObject*, result), Q_ARG(OverlayID, id));
return result;
}
@ -384,12 +388,6 @@ void Overlays::setParentPanel(OverlayID childId, OverlayID panelId) {
#endif
OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) {
if (QThread::currentThread() != thread()) {
OverlayID result;
BLOCKING_INVOKE_METHOD(this, "getOverlayAtPoint", Q_RETURN_ARG(OverlayID, result), Q_ARG(glm::vec2, point));
return result;
}
if (!_enabled) {
return UNKNOWN_OVERLAY_ID;
}
@ -414,20 +412,47 @@ OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) {
}
OverlayPropertyResult Overlays::getProperty(OverlayID id, const QString& property) {
if (QThread::currentThread() != thread()) {
OverlayPropertyResult result;
BLOCKING_INVOKE_METHOD(this, "getProperty", Q_RETURN_ARG(OverlayPropertyResult, result), Q_ARG(OverlayID, id), Q_ARG(QString, property));
return result;
}
OverlayPropertyResult result;
Overlay::Pointer thisOverlay = getOverlay(id);
OverlayPropertyResult result;
if (thisOverlay && thisOverlay->supportsGetProperty()) {
result.value = thisOverlay->getProperty(property);
}
return result;
}
OverlayPropertyResult Overlays::getProperties(const OverlayID& id, const QStringList& properties) {
Overlay::Pointer thisOverlay = getOverlay(id);
OverlayPropertyResult result;
if (thisOverlay && thisOverlay->supportsGetProperty()) {
QVariantMap mapResult;
for (const auto& property : properties) {
mapResult.insert(property, thisOverlay->getProperty(property));
}
result.value = mapResult;
}
return result;
}
OverlayPropertyResult Overlays::getOverlaysProperties(const QVariant& propertiesById) {
QVariantMap map = propertiesById.toMap();
OverlayPropertyResult result;
QVariantMap resultMap;
for (const auto& key : map.keys()) {
OverlayID id = OverlayID(key);
QVariantMap overlayResult;
Overlay::Pointer thisOverlay = getOverlay(id);
if (thisOverlay && thisOverlay->supportsGetProperty()) {
QStringList propertiesToFetch = map[key].toStringList();
for (const auto& property : propertiesToFetch) {
overlayResult[property] = thisOverlay->getProperty(property);
}
}
resultMap[key] = overlayResult;
}
result.value = resultMap;
return result;
}
OverlayPropertyResult::OverlayPropertyResult() {
}
@ -459,18 +484,6 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionInternal(const PickR
const QVector<OverlayID>& overlaysToInclude,
const QVector<OverlayID>& overlaysToDiscard,
bool visibleOnly, bool collidableOnly) {
if (QThread::currentThread() != thread()) {
RayToOverlayIntersectionResult result;
BLOCKING_INVOKE_METHOD(this, "findRayIntersectionInternal", Q_RETURN_ARG(RayToOverlayIntersectionResult, result),
Q_ARG(PickRay, ray),
Q_ARG(bool, precisionPicking),
Q_ARG(QVector<OverlayID>, overlaysToInclude),
Q_ARG(QVector<OverlayID>, overlaysToDiscard),
Q_ARG(bool, visibleOnly),
Q_ARG(bool, collidableOnly));
return result;
}
float bestDistance = std::numeric_limits<float>::max();
bool bestIsFront = false;
@ -589,6 +602,7 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& objectVar
bool Overlays::isLoaded(OverlayID id) {
if (QThread::currentThread() != thread()) {
bool result;
PROFILE_RANGE(script, __FUNCTION__);
BLOCKING_INVOKE_METHOD(this, "isLoaded", Q_RETURN_ARG(bool, result), Q_ARG(OverlayID, id));
return result;
}
@ -603,6 +617,7 @@ bool Overlays::isLoaded(OverlayID id) {
QSizeF Overlays::textSize(OverlayID id, const QString& text) {
if (QThread::currentThread() != thread()) {
QSizeF result;
PROFILE_RANGE(script, __FUNCTION__);
BLOCKING_INVOKE_METHOD(this, "textSize", Q_RETURN_ARG(QSizeF, result), Q_ARG(OverlayID, id), Q_ARG(QString, text));
return result;
}
@ -681,6 +696,7 @@ void Overlays::deletePanel(OverlayID panelId) {
bool Overlays::isAddedOverlay(OverlayID id) {
if (QThread::currentThread() != thread()) {
bool result;
PROFILE_RANGE(script, __FUNCTION__);
BLOCKING_INVOKE_METHOD(this, "isAddedOverlay", Q_RETURN_ARG(bool, result), Q_ARG(OverlayID, id));
return result;
}
@ -716,6 +732,7 @@ void Overlays::sendHoverLeaveOverlay(OverlayID id, PointerEvent event) {
OverlayID Overlays::getKeyboardFocusOverlay() {
if (QThread::currentThread() != thread()) {
OverlayID result;
PROFILE_RANGE(script, __FUNCTION__);
BLOCKING_INVOKE_METHOD(this, "getKeyboardFocusOverlay", Q_RETURN_ARG(OverlayID, result));
return result;
}
@ -735,6 +752,7 @@ void Overlays::setKeyboardFocusOverlay(OverlayID id) {
float Overlays::width() {
if (QThread::currentThread() != thread()) {
float result;
PROFILE_RANGE(script, __FUNCTION__);
BLOCKING_INVOKE_METHOD(this, "width", Q_RETURN_ARG(float, result));
return result;
}
@ -746,6 +764,7 @@ float Overlays::width() {
float Overlays::height() {
if (QThread::currentThread() != thread()) {
float result;
PROFILE_RANGE(script, __FUNCTION__);
BLOCKING_INVOKE_METHOD(this, "height", Q_RETURN_ARG(float, result));
return result;
}
@ -955,10 +974,11 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) {
QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
QVector<QUuid> result;
if (QThread::currentThread() != thread()) {
BLOCKING_INVOKE_METHOD(this, "findOverlays", Q_RETURN_ARG(QVector<QUuid>, result), Q_ARG(glm::vec3, center), Q_ARG(float, radius));
return result;
}
//if (QThread::currentThread() != thread()) {
// PROFILE_RANGE(script, __FUNCTION__);
// BLOCKING_INVOKE_METHOD(this, "findOverlays", Q_RETURN_ARG(QVector<QUuid>, result), Q_ARG(glm::vec3, center), Q_ARG(float, radius));
// return result;
//}
QMutexLocker locker(&_mutex);
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysWorld);

View file

@ -190,6 +190,10 @@ public slots:
*/
OverlayPropertyResult getProperty(OverlayID id, const QString& property);
OverlayPropertyResult getProperties(const OverlayID& id, const QStringList& properties);
OverlayPropertyResult getOverlaysProperties(const QVariant& overlaysProperties);
/*jsdoc
* Find the closest 3D overlay hit by a pick ray.
*

View file

@ -45,17 +45,17 @@ void Shape3DOverlay::render(RenderArgs* args) {
transform.setTranslation(position);
transform.setRotation(rotation);
auto geometryCache = DependencyManager::get<GeometryCache>();
auto pipeline = args->_pipeline;
if (!pipeline) {
pipeline = _isSolid ? geometryCache->getOpaqueShapePipeline() : geometryCache->getWireShapePipeline();
auto shapePipeline = args->_shapePipeline;
if (!shapePipeline) {
shapePipeline = _isSolid ? geometryCache->getOpaqueShapePipeline() : geometryCache->getWireShapePipeline();
}
transform.setScale(dimensions);
batch->setModelTransform(transform);
if (_isSolid) {
geometryCache->renderSolidShapeInstance(*batch, _shape, cubeColor, pipeline);
geometryCache->renderSolidShapeInstance(args, *batch, _shape, cubeColor, shapePipeline);
} else {
geometryCache->renderWireShapeInstance(*batch, _shape, cubeColor, pipeline);
geometryCache->renderWireShapeInstance(args, *batch, _shape, cubeColor, shapePipeline);
}
}
}

View file

@ -44,15 +44,15 @@ void Sphere3DOverlay::render(RenderArgs* args) {
batch->setModelTransform(transform);
auto geometryCache = DependencyManager::get<GeometryCache>();
auto pipeline = args->_pipeline;
if (!pipeline) {
pipeline = _isSolid ? geometryCache->getOpaqueShapePipeline() : geometryCache->getWireShapePipeline();
auto shapePipeline = args->_shapePipeline;
if (!shapePipeline) {
shapePipeline = _isSolid ? geometryCache->getOpaqueShapePipeline() : geometryCache->getWireShapePipeline();
}
if (_isSolid) {
geometryCache->renderSolidSphereInstance(*batch, sphereColor, pipeline);
geometryCache->renderSolidSphereInstance(args, *batch, sphereColor, shapePipeline);
} else {
geometryCache->renderWireSphereInstance(*batch, sphereColor, pipeline);
geometryCache->renderWireSphereInstance(args, *batch, sphereColor, shapePipeline);
}
}
}

View file

@ -137,8 +137,8 @@ void Text3DOverlay::render(RenderArgs* args) {
// Text renderer sets its own pipeline,
_textRenderer->draw(batch, 0, 0, getText(), textColor, glm::vec2(-1.0f), getDrawInFront());
// so before we continue, we must reset the pipeline
batch.setPipeline(args->_pipeline->pipeline);
args->_pipeline->prepare(batch);
batch.setPipeline(args->_shapePipeline->pipeline);
args->_shapePipeline->prepare(batch, args);
}
const render::ShapeKey Text3DOverlay::getShapeKey() {

View file

@ -404,8 +404,18 @@ void Rig::setJointRotation(int index, bool valid, const glm::quat& rotation, flo
}
bool Rig::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position, glm::vec3 translation, glm::quat rotation) const {
if (isIndexValid(jointIndex)) {
position = (rotation * _internalPoseSet._absolutePoses[jointIndex].trans()) + translation;
if (QThread::currentThread() == thread()) {
if (isIndexValid(jointIndex)) {
position = (rotation * _internalPoseSet._absolutePoses[jointIndex].trans()) + translation;
return true;
} else {
return false;
}
}
QReadLocker readLock(&_externalPoseSetLock);
if (jointIndex >= 0 && jointIndex < (int)_externalPoseSet._absolutePoses.size()) {
position = (rotation * _externalPoseSet._absolutePoses[jointIndex].trans()) + translation;
return true;
} else {
return false;
@ -413,17 +423,31 @@ bool Rig::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position, glm:
}
bool Rig::getJointPosition(int jointIndex, glm::vec3& position) const {
if (isIndexValid(jointIndex)) {
position = _internalPoseSet._absolutePoses[jointIndex].trans();
return true;
if (QThread::currentThread() == thread()) {
if (isIndexValid(jointIndex)) {
position = _internalPoseSet._absolutePoses[jointIndex].trans();
return true;
} else {
return false;
}
} else {
return false;
return getAbsoluteJointTranslationInRigFrame(jointIndex, position);
}
}
bool Rig::getJointRotationInWorldFrame(int jointIndex, glm::quat& result, const glm::quat& rotation) const {
if (isIndexValid(jointIndex)) {
result = rotation * _internalPoseSet._absolutePoses[jointIndex].rot();
if (QThread::currentThread() == thread()) {
if (isIndexValid(jointIndex)) {
result = rotation * _internalPoseSet._absolutePoses[jointIndex].rot();
return true;
} else {
return false;
}
}
QReadLocker readLock(&_externalPoseSetLock);
if (jointIndex >= 0 && jointIndex < (int)_externalPoseSet._absolutePoses.size()) {
result = rotation * _externalPoseSet._absolutePoses[jointIndex].rot();
return true;
} else {
return false;
@ -431,6 +455,15 @@ bool Rig::getJointRotationInWorldFrame(int jointIndex, glm::quat& result, const
}
bool Rig::getJointRotation(int jointIndex, glm::quat& rotation) const {
if (QThread::currentThread() == thread()) {
if (isIndexValid(jointIndex)) {
rotation = _internalPoseSet._relativePoses[jointIndex].rot();
return true;
} else {
return false;
}
}
QReadLocker readLock(&_externalPoseSetLock);
if (jointIndex >= 0 && jointIndex < (int)_externalPoseSet._relativePoses.size()) {
rotation = _externalPoseSet._relativePoses[jointIndex].rot();

View file

@ -610,7 +610,7 @@ void Avatar::render(RenderArgs* renderArgs) {
if (showCollisionShapes && shouldRenderHead(renderArgs) && _skeletonModel->isRenderable()) {
PROFILE_RANGE_BATCH(batch, __FUNCTION__":skeletonBoundingCollisionShapes");
const float BOUNDING_SHAPE_ALPHA = 0.7f;
_skeletonModel->renderBoundingCollisionShapes(*renderArgs->_batch, getUniformScale(), BOUNDING_SHAPE_ALPHA);
_skeletonModel->renderBoundingCollisionShapes(renderArgs, *renderArgs->_batch, getUniformScale(), BOUNDING_SHAPE_ALPHA);
}
if (showReceiveStats || showNamesAboveHeads) {
@ -1008,49 +1008,60 @@ glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
}
}
int Avatar::getJointIndex(const QString& name) const {
if (QThread::currentThread() != thread()) {
int result;
BLOCKING_INVOKE_METHOD(const_cast<Avatar*>(this), "getJointIndex",
Q_RETURN_ARG(int, result), Q_ARG(const QString&, name));
return result;
void Avatar::invalidateJointIndicesCache() const {
QWriteLocker writeLock(&_modelJointIndicesCacheLock);
_modelJointsCached = false;
}
void Avatar::withValidJointIndicesCache(std::function<void()> const& worker) const {
QReadLocker readLock(&_modelJointIndicesCacheLock);
if (_modelJointsCached) {
worker();
} else {
readLock.unlock();
{
QWriteLocker writeLock(&_modelJointIndicesCacheLock);
if (!_modelJointsCached) {
_modelJointIndicesCache.clear();
if (_skeletonModel && _skeletonModel->isActive()) {
_modelJointIndicesCache = _skeletonModel->getFBXGeometry().jointIndices;
_modelJointsCached = true;
}
}
worker();
}
}
}
int Avatar::getJointIndex(const QString& name) const {
int result = getFauxJointIndex(name);
if (result != -1) {
return result;
}
return _skeletonModel->isActive() ? _skeletonModel->getFBXGeometry().getJointIndex(name) : -1;
withValidJointIndicesCache([&]() {
if (_modelJointIndicesCache.contains(name)) {
result = _modelJointIndicesCache[name] - 1;
}
});
return result;
}
QStringList Avatar::getJointNames() const {
if (QThread::currentThread() != thread()) {
QStringList result;
BLOCKING_INVOKE_METHOD(const_cast<Avatar*>(this), "getJointNames",
Q_RETURN_ARG(QStringList, result));
return result;
}
return _skeletonModel->isActive() ? _skeletonModel->getFBXGeometry().getJointNames() : QStringList();
QStringList result;
withValidJointIndicesCache([&]() {
result = _modelJointIndicesCache.keys();
});
return result;
}
glm::vec3 Avatar::getJointPosition(int index) const {
if (QThread::currentThread() != thread()) {
glm::vec3 position;
BLOCKING_INVOKE_METHOD(const_cast<Avatar*>(this), "getJointPosition",
Q_RETURN_ARG(glm::vec3, position), Q_ARG(const int, index));
return position;
}
glm::vec3 position;
_skeletonModel->getJointPositionInWorldFrame(index, position);
return position;
}
glm::vec3 Avatar::getJointPosition(const QString& name) const {
if (QThread::currentThread() != thread()) {
glm::vec3 position;
BLOCKING_INVOKE_METHOD(const_cast<Avatar*>(this), "getJointPosition",
Q_RETURN_ARG(glm::vec3, position), Q_ARG(const QString&, name));
return position;
}
glm::vec3 position;
_skeletonModel->getJointPositionInWorldFrame(getJointIndex(name), position);
return position;
@ -1071,6 +1082,8 @@ void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
}
void Avatar::setModelURLFinished(bool success) {
invalidateJointIndicesCache();
if (!success && _skeletonModelURL != AvatarData::defaultFullAvatarModelUrl()) {
const int MAX_SKELETON_DOWNLOAD_ATTEMPTS = 4; // NOTE: we don't want to be as generous as ResourceCache is, we only want 4 attempts
if (_skeletonModel->getResourceDownloadAttemptsRemaining() <= 0 ||

View file

@ -267,6 +267,13 @@ protected:
virtual void maybeUpdateSessionDisplayNameFromTransport(const QString& sessionDisplayName) override { _sessionDisplayName = sessionDisplayName; } // don't use no-op setter!
SkeletonModelPointer _skeletonModel;
void invalidateJointIndicesCache() const;
void withValidJointIndicesCache(std::function<void()> const& worker) const;
mutable QHash<QString, int> _modelJointIndicesCache;
mutable QReadWriteLock _modelJointIndicesCacheLock;
mutable bool _modelJointsCached { false };
glm::vec3 _skeletonOffset;
std::vector<std::shared_ptr<Model>> _attachmentModels;
std::vector<std::shared_ptr<Model>> _attachmentsToRemove;

View file

@ -322,20 +322,20 @@ void SkeletonModel::computeBoundingShape() {
_boundingCapsuleLocalOffset = invScale * offset;
}
void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float scale, float alpha) {
void SkeletonModel::renderBoundingCollisionShapes(RenderArgs* args, gpu::Batch& batch, float scale, float alpha) {
auto geometryCache = DependencyManager::get<GeometryCache>();
// draw a blue sphere at the capsule top point
glm::vec3 topPoint = _translation + getRotation() * (scale * (_boundingCapsuleLocalOffset + (0.5f * _boundingCapsuleHeight) * Vectors::UNIT_Y));
batch.setModelTransform(Transform().setTranslation(topPoint).postScale(scale * _boundingCapsuleRadius));
geometryCache->renderSolidSphereInstance(batch, glm::vec4(0.6f, 0.6f, 0.8f, alpha));
geometryCache->renderSolidSphereInstance(args, batch, glm::vec4(0.6f, 0.6f, 0.8f, alpha));
// draw a yellow sphere at the capsule bottom point
glm::vec3 bottomPoint = topPoint - glm::vec3(0.0f, scale * _boundingCapsuleHeight, 0.0f);
glm::vec3 axis = topPoint - bottomPoint;
batch.setModelTransform(Transform().setTranslation(bottomPoint).postScale(scale * _boundingCapsuleRadius));
geometryCache->renderSolidSphereInstance(batch, glm::vec4(0.8f, 0.8f, 0.6f, alpha));
geometryCache->renderSolidSphereInstance(args, batch, glm::vec4(0.8f, 0.8f, 0.6f, alpha));
// draw a green cylinder between the two points
glm::vec3 origin(0.0f);

View file

@ -96,7 +96,7 @@ public:
/// \return whether or not the head was found.
glm::vec3 getDefaultEyeModelPosition() const;
void renderBoundingCollisionShapes(gpu::Batch& batch, float scale, float alpha);
void renderBoundingCollisionShapes(RenderArgs* args, gpu::Batch& batch, float scale, float alpha);
float getBoundingCapsuleRadius() const { return _boundingCapsuleRadius; }
float getBoundingCapsuleHeight() const { return _boundingCapsuleHeight; }
const glm::vec3 getBoundingCapsuleOffset() const { return _boundingCapsuleLocalOffset; }

View file

@ -1462,12 +1462,12 @@ int AvatarData::getJointIndex(const QString& name) const {
return result;
}
QReadLocker readLock(&_jointDataLock);
return _jointIndices.value(name) - 1;
return _fstJointIndices.value(name) - 1;
}
QStringList AvatarData::getJointNames() const {
QReadLocker readLock(&_jointDataLock);
return _jointNames;
return _fstJointNames;
}
glm::quat AvatarData::getOrientationOutbound() const {
@ -1720,14 +1720,14 @@ void AvatarData::setJointMappingsFromNetworkReply() {
bool ok;
int jointIndex = line.mid(secondSeparatorIndex + 1).trimmed().toInt(&ok);
if (ok) {
while (_jointNames.size() < jointIndex + 1) {
_jointNames.append(QString());
while (_fstJointNames.size() < jointIndex + 1) {
_fstJointNames.append(QString());
}
_jointNames[jointIndex] = jointName;
_fstJointNames[jointIndex] = jointName;
}
}
for (int i = 0; i < _jointNames.size(); i++) {
_jointIndices.insert(_jointNames.at(i), i + 1);
for (int i = 0; i < _fstJointNames.size(); i++) {
_fstJointIndices.insert(_fstJointNames.at(i), i + 1);
}
}
@ -1781,8 +1781,8 @@ void AvatarData::sendIdentityPacket() {
void AvatarData::updateJointMappings() {
{
QWriteLocker writeLock(&_jointDataLock);
_jointIndices.clear();
_jointNames.clear();
_fstJointIndices.clear();
_fstJointNames.clear();
_jointData.clear();
}

View file

@ -704,8 +704,8 @@ protected:
QString _displayName;
QString _sessionDisplayName { };
QHash<QString, int> _jointIndices; ///< 1-based, since zero is returned for missing keys
QStringList _jointNames; ///< in order of depth-first traversal
QHash<QString, int> _fstJointIndices; ///< 1-based, since zero is returned for missing keys
QStringList _fstJointNames; ///< in order of depth-first traversal
quint64 _errorLogExpiry; ///< time in future when to log an error

View file

@ -378,7 +378,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
auto shapeTransform = getTransformToCenter(success);
if (success) {
batch.setModelTransform(shapeTransform); // we want to include the scale as well
DependencyManager::get<GeometryCache>()->renderWireCubeInstance(batch, greenColor);
DependencyManager::get<GeometryCache>()->renderWireCubeInstance(args, batch, greenColor);
}
return;
}

View file

@ -128,9 +128,9 @@ void RenderableShapeEntityItem::render(RenderArgs* args) {
auto pipeline = color.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline();
if (render::ShapeKey(args->_globalShapeKey).isWireframe()) {
geometryCache->renderWireShapeInstance(batch, MAPPING[_shape], color, pipeline);
geometryCache->renderWireShapeInstance(args, batch, MAPPING[_shape], color, pipeline);
} else {
geometryCache->renderSolidShapeInstance(batch, MAPPING[_shape], color, pipeline);
geometryCache->renderSolidShapeInstance(args, batch, MAPPING[_shape], color, pipeline);
}
}

View file

@ -221,10 +221,10 @@ void RenderableZoneEntityItem::render(RenderArgs* args) {
if (getShapeType() == SHAPE_TYPE_SPHERE) {
shapeTransform.postScale(SPHERE_ENTITY_SCALE);
batch.setModelTransform(shapeTransform);
geometryCache->renderWireSphereInstance(batch, DEFAULT_COLOR);
geometryCache->renderWireSphereInstance(args, batch, DEFAULT_COLOR);
} else {
batch.setModelTransform(shapeTransform);
geometryCache->renderWireCubeInstance(batch, DEFAULT_COLOR);
geometryCache->renderWireCubeInstance(args, batch, DEFAULT_COLOR);
}
break;
}
@ -554,11 +554,13 @@ void RenderableZoneEntityItemMeta::setProceduralUserData(QString userData) {
void RenderableZoneEntityItemMeta::render(RenderArgs* args) {
if (!_stage) {
_stage = DependencyManager::get<DeferredLightingEffect>()->getLightStage();
_stage = args->_scene->getStage<LightStage>();
assert(_stage);
}
if (!_backgroundStage) {
_backgroundStage = DependencyManager::get<DeferredLightingEffect>()->getBackgroundStage();
_backgroundStage = args->_scene->getStage<BackgroundStage>();
assert(_backgroundStage);
}
{ // Sun

View file

@ -32,13 +32,6 @@ const btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
if (info.getType() == SHAPE_TYPE_NONE) {
return nullptr;
}
const float MIN_SHAPE_DIAGONAL_SQUARED = 3.0e-4f; // 1 cm cube
if (4.0f * glm::length2(info.getHalfExtents()) < MIN_SHAPE_DIAGONAL_SQUARED) {
// tiny shapes are not supported
// qCDebug(physics) << "ShapeManager::getShape -- not making shape due to size" << diagonal;
return nullptr;
}
DoubleHashKey key = info.getHash();
ShapeReference* shapeRef = _shapeMap.find(key);
if (shapeRef) {

View file

@ -13,6 +13,8 @@
#include <gpu/Context.h>
std::string BackgroundStage::_stageName { "BACKGROUND_STAGE"};
BackgroundStage::Index BackgroundStage::findBackground(const BackgroundPointer& background) const {
auto found = _backgroundMap.find(background);
if (found != _backgroundMap.end()) {
@ -52,15 +54,15 @@ BackgroundStage::BackgroundPointer BackgroundStage::removeBackground(Index index
void DrawBackgroundStage::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) {
const auto& lightingModel = inputs;
if (!lightingModel->isBackgroundEnabled()) {
return;
}
// Background rendering decision
auto backgroundStage = DependencyManager::get<DeferredLightingEffect>()->getBackgroundStage();
auto backgroundStage = renderContext->_scene->getStage<BackgroundStage>();
assert(backgroundStage);
model::SunSkyStagePointer background;
model::SkyboxPointer skybox;
if (backgroundStage->_currentFrame._backgrounds.size()) {
@ -68,11 +70,8 @@ void DrawBackgroundStage::run(const render::RenderContextPointer& renderContext,
auto background = backgroundStage->getBackground(backgroundId);
if (background) {
skybox = background->getSkybox();
}
} else {
skybox = DependencyManager::get<DeferredLightingEffect>()->getDefaultSkybox();
}
}
/* auto backgroundMode = skyStage->getBackgroundMode();
switch (backgroundMode) {
@ -137,4 +136,15 @@ void DrawBackgroundStage::run(const render::RenderContextPointer& renderContext,
}
*/
}
}
BackgroundStageSetup::BackgroundStageSetup() {
}
void BackgroundStageSetup::run(const render::RenderContextPointer& renderContext) {
auto stage = renderContext->_scene->getStage(BackgroundStage::getName());
if (!stage) {
renderContext->_scene->resetStage(BackgroundStage::getName(), std::make_shared<BackgroundStage>());
}
}

View file

@ -15,13 +15,17 @@
#include <set>
#include <unordered_map>
#include <render/IndexedContainer.h>
#include <render/Stage.h>
#include "LightingModel.h"
// Background stage to set up background-related rendering tasks
class BackgroundStage {
class BackgroundStage : public render::Stage {
public:
static std::string _stageName;
static const std::string& getName() { return _stageName; }
using Index = render::indexed_container::Index;
static const Index INVALID_INDEX { render::indexed_container::INVALID_INDEX };
static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; }
@ -66,6 +70,15 @@ public:
};
using BackgroundStagePointer = std::shared_ptr<BackgroundStage>;
class BackgroundStageSetup {
public:
using JobModel = render::Job::Model<BackgroundStageSetup>;
BackgroundStageSetup();
void run(const render::RenderContextPointer& renderContext);
protected:
};
class DrawBackgroundStage {
public:

View file

@ -432,9 +432,10 @@ void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const I
batch.setResourceTexture(Lighting, deferredFramebuffer->getLightingTexture());
}
auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
assert(deferredLightingEffect->getLightStage()->getNumLights() > 0);
auto lightAndShadow = deferredLightingEffect->getLightStage()->getLightAndShadow(0);
auto lightStage = renderContext->_scene->getStage<LightStage>();
assert(lightStage);
assert(lightStage->getNumLights() > 0);
auto lightAndShadow = lightStage->getLightAndShadow(0);
const auto& globalShadow = lightAndShadow.second;
if (globalShadow) {
batch.setResourceTexture(Shadow, globalShadow->map);

View file

@ -99,75 +99,35 @@ void DeferredLightingEffect::init() {
loadLightProgram(deferred_light_vert, local_lights_shading_frag, true, _localLight, _localLightLocations);
loadLightProgram(deferred_light_vert, local_lights_drawOutline_frag, true, _localLightOutline, _localLightOutlineLocations);
// Light Stage and clusters
_lightStage = std::make_shared<LightStage>();
// Allocate a global light representing the Global Directional light casting shadow (the sun) and the ambient light
_allocatedLights.push_back(std::make_shared<model::Light>());
model::LightPointer lp = _allocatedLights[0];
lp->setType(model::Light::SUN);
lp->setDirection(glm::vec3(-1.0f));
lp->setColor(glm::vec3(1.0f));
lp->setIntensity(1.0f);
lp->setType(model::Light::SUN);
lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset::OLD_TOWN_SQUARE);
// Add the global light to the light stage (for later shadow rendering)
_globalLights.push_back(_lightStage->addLight(lp));
_lightStage->addShadow(_globalLights[0]);
_backgroundStage = std::make_shared<BackgroundStage>();
auto textureCache = DependencyManager::get<TextureCache>();
{
PROFILE_RANGE(render, "Process Default Skybox");
auto textureCache = DependencyManager::get<TextureCache>();
auto skyboxUrl = PathUtils::resourcesPath().toStdString() + "images/Default-Sky-9-cubemap.ktx";
_defaultSkyboxTexture = gpu::Texture::unserialize(skyboxUrl);
_defaultSkyboxAmbientTexture = _defaultSkyboxTexture;
_defaultSkybox->setCubemap(_defaultSkyboxTexture);
}
lp->setAmbientIntensity(0.5f);
lp->setAmbientMap(_defaultSkyboxAmbientTexture);
auto irradianceSH = _defaultSkyboxAmbientTexture->getIrradiance();
if (irradianceSH) {
lp->setAmbientSphere((*irradianceSH));
}
}
void DeferredLightingEffect::setupKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit) {
void DeferredLightingEffect::setupKeyLightBatch(const RenderArgs* args, gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit) {
PerformanceTimer perfTimer("DLE->setupBatch()");
model::LightPointer keySunLight;
if (_lightStage && _lightStage->_currentFrame._sunLights.size()) {
keySunLight = _lightStage->getLight(_lightStage->_currentFrame._sunLights.front());
} else {
keySunLight = _allocatedLights[_globalLights.front()];
auto lightStage = args->_scene->getStage<LightStage>();
if (lightStage && lightStage->_currentFrame._sunLights.size()) {
keySunLight = lightStage->getLight(lightStage->_currentFrame._sunLights.front());
}
model::LightPointer keyAmbiLight;
if (_lightStage && _lightStage->_currentFrame._ambientLights.size()) {
keyAmbiLight = _lightStage->getLight(_lightStage->_currentFrame._ambientLights.front());
} else {
keyAmbiLight = _allocatedLights[_globalLights.front()];
if (lightStage && lightStage->_currentFrame._ambientLights.size()) {
keyAmbiLight = lightStage->getLight(lightStage->_currentFrame._ambientLights.front());
}
if (lightBufferUnit >= 0) {
batch.setUniformBuffer(lightBufferUnit, keySunLight->getLightSchemaBuffer());
}
if (ambientBufferUnit >= 0) {
batch.setUniformBuffer(ambientBufferUnit, keyAmbiLight->getAmbientSchemaBuffer());
if (keySunLight) {
if (lightBufferUnit >= 0) {
batch.setUniformBuffer(lightBufferUnit, keySunLight->getLightSchemaBuffer());
}
}
if (keyAmbiLight->getAmbientMap() && (skyboxCubemapUnit >= 0)) {
batch.setResourceTexture(skyboxCubemapUnit, keyAmbiLight->getAmbientMap());
if (keyAmbiLight) {
if (ambientBufferUnit >= 0) {
batch.setUniformBuffer(ambientBufferUnit, keyAmbiLight->getAmbientSchemaBuffer());
}
if (keyAmbiLight->getAmbientMap() && (skyboxCubemapUnit >= 0)) {
batch.setResourceTexture(skyboxCubemapUnit, keyAmbiLight->getAmbientMap());
}
}
}
@ -266,21 +226,6 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo
}
void DeferredLightingEffect::setGlobalLight(const model::LightPointer& light) {
/* auto globalLight = _allocatedLights.front();
globalLight->setDirection(light->getDirection());
globalLight->setColor(light->getColor());
globalLight->setIntensity(light->getIntensity());
globalLight->setAmbientIntensity(light->getAmbientIntensity());
globalLight->setAmbientSphere(light->getAmbientSphere());
globalLight->setAmbientMap(light->getAmbientMap());*/
}
const model::LightPointer& DeferredLightingEffect::getGlobalLight() const {
return _allocatedLights.front();
}
#include <shared/Shapes.h>
model::MeshPointer DeferredLightingEffect::getPointLightMesh() {
@ -483,8 +428,9 @@ void PrepareDeferred::run(const RenderContextPointer& renderContext, const Input
// Prepare a fresh Light Frame
auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
deferredLightingEffect->getLightStage()->_currentFrame.clear();
auto lightStage = renderContext->_scene->getStage<LightStage>();
assert(lightStage);
lightStage->_currentFrame.clear();
}
@ -547,8 +493,10 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext,
// Global directional light and ambient pass
assert(deferredLightingEffect->getLightStage()->getNumLights() > 0);
auto lightAndShadow = deferredLightingEffect->getLightStage()->getLightAndShadow(0);
auto lightStage = renderContext->_scene->getStage<LightStage>();
assert(lightStage);
assert(lightStage->getNumLights() > 0);
auto lightAndShadow = lightStage->getLightAndShadow(0);
const auto& globalShadow = lightAndShadow.second;
// Bind the shadow buffer
@ -558,7 +506,8 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext,
auto& program = deferredLightingEffect->_directionalSkyboxLight;
LightLocationsPtr locations = deferredLightingEffect->_directionalSkyboxLightLocations;
const auto& keyLight = deferredLightingEffect->_allocatedLights[deferredLightingEffect->_globalLights.front()];
auto keyLight = lightStage->getLight(0);
// Setup the global directional pass pipeline
{
@ -597,7 +546,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext,
batch._glUniform4fv(locations->texcoordFrameTransform, 1, reinterpret_cast< const float* >(&textureFrameTransform));
// Setup the global lighting
deferredLightingEffect->setupKeyLightBatch(batch, locations->lightBufferUnit, locations->ambientBufferUnit, SKYBOX_MAP_UNIT);
deferredLightingEffect->setupKeyLightBatch(args, batch, locations->lightBufferUnit, locations->ambientBufferUnit, SKYBOX_MAP_UNIT);
batch.draw(gpu::TRIANGLE_STRIP, 4);
@ -749,3 +698,66 @@ void RenderDeferred::run(const RenderContextPointer& renderContext, const Inputs
auto config = std::static_pointer_cast<Config>(renderContext->jobConfig);
config->setGPUBatchRunTime(_gpuTimer->getGPUAverage(), _gpuTimer->getBatchAverage());
}
void DefaultLightingSetup::run(const RenderContextPointer& renderContext) {
if (!_defaultLight || !_defaultBackground) {
if (!_defaultSkyboxTexture) {
auto textureCache = DependencyManager::get<TextureCache>();
{
PROFILE_RANGE(render, "Process Default Skybox");
auto textureCache = DependencyManager::get<TextureCache>();
auto skyboxUrl = PathUtils::resourcesPath().toStdString() + "images/Default-Sky-9-cubemap.ktx";
_defaultSkyboxTexture = gpu::Texture::unserialize(skyboxUrl);
_defaultSkyboxAmbientTexture = _defaultSkyboxTexture;
_defaultSkybox->setCubemap(_defaultSkyboxTexture);
}
}
auto lightStage = renderContext->_scene->getStage<LightStage>();
if (lightStage) {
// Allocate a default global light directional and ambient
auto lp = std::make_shared<model::Light>();
lp->setType(model::Light::SUN);
lp->setDirection(glm::vec3(-1.0f));
lp->setColor(glm::vec3(1.0f));
lp->setIntensity(1.0f);
lp->setType(model::Light::SUN);
lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset::OLD_TOWN_SQUARE);
lp->setAmbientIntensity(0.5f);
lp->setAmbientMap(_defaultSkyboxAmbientTexture);
auto irradianceSH = _defaultSkyboxAmbientTexture->getIrradiance();
if (irradianceSH) {
lp->setAmbientSphere((*irradianceSH));
}
// capture default light
_defaultLight = lp;
// Add the global light to the light stage (for later shadow rendering)
_defaultLightID = lightStage->addLight(lp);
lightStage->addShadow(_defaultLightID);
}
auto backgroundStage = renderContext->_scene->getStage<BackgroundStage>();
if (backgroundStage) {
auto background = std::make_shared<model::SunSkyStage>();
background->setSkybox(_defaultSkybox);
// capture deault background
_defaultBackground = background;
// Add the global light to the light stage (for later shadow rendering)
_defaultBackgroundID = backgroundStage->addBackground(_defaultBackground);
}
}
}

View file

@ -47,30 +47,16 @@ class DeferredLightingEffect : public Dependency {
public:
void init();
void setupKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit);
void setupKeyLightBatch(const RenderArgs* args, gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit);
void unsetKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit);
// update global lighting
void setGlobalLight(const model::LightPointer& light);
const model::LightPointer& getGlobalLight() const;
const LightStagePointer& getLightStage() { return _lightStage; }
const BackgroundStagePointer& getBackgroundStage() { return _backgroundStage; }
void setShadowMapEnabled(bool enable) { _shadowMapEnabled = enable; };
void setAmbientOcclusionEnabled(bool enable) { _ambientOcclusionEnabled = enable; }
bool isAmbientOcclusionEnabled() const { return _ambientOcclusionEnabled; }
model::SkyboxPointer getDefaultSkybox() const { return _defaultSkybox; }
gpu::TexturePointer getDefaultSkyboxTexture() const { return _defaultSkyboxTexture; }
gpu::TexturePointer getDefaultSkyboxAmbientTexture() const { return _defaultSkyboxAmbientTexture; }
private:
DeferredLightingEffect() = default;
LightStagePointer _lightStage;
BackgroundStagePointer _backgroundStage;
bool _shadowMapEnabled{ false };
bool _ambientOcclusionEnabled{ false };
@ -97,15 +83,6 @@ private:
LightLocationsPtr _localLightLocations;
LightLocationsPtr _localLightOutlineLocations;
using Lights = std::vector<model::LightPointer>;
Lights _allocatedLights;
std::vector<int> _globalLights;
model::SkyboxPointer _defaultSkybox { new ProceduralSkybox() };
gpu::TexturePointer _defaultSkyboxTexture;
gpu::TexturePointer _defaultSkyboxAmbientTexture;
friend class LightClusteringPass;
friend class RenderDeferredSetup;
friend class RenderDeferredLocals;
@ -195,6 +172,20 @@ protected:
gpu::RangeTimerPointer _gpuTimer;
};
class DefaultLightingSetup {
public:
using JobModel = render::Job::Model<DefaultLightingSetup>;
void run(const render::RenderContextPointer& renderContext);
protected:
model::LightPointer _defaultLight;
LightStage::Index _defaultLightID{ LightStage::INVALID_INDEX };
model::SunSkyStagePointer _defaultBackground;
BackgroundStage::Index _defaultBackgroundID{ BackgroundStage::INVALID_INDEX };
model::SkyboxPointer _defaultSkybox { new ProceduralSkybox() };
gpu::TexturePointer _defaultSkyboxTexture;
gpu::TexturePointer _defaultSkyboxAmbientTexture;
};
#endif // hifi_DeferredLightingEffect_h

View file

@ -455,7 +455,7 @@ _nextID(0) {
buildShapes();
GeometryCache::_simpleOpaquePipeline =
std::make_shared<render::ShapePipeline>(getSimplePipeline(false, false, true, false), nullptr,
[](const render::ShapePipeline&, gpu::Batch& batch) {
[](const render::ShapePipeline&, gpu::Batch& batch, RenderArgs* args) {
// Set the defaults needed for a simple program
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO,
DependencyManager::get<TextureCache>()->getWhiteTexture());
@ -463,7 +463,7 @@ _nextID(0) {
);
GeometryCache::_simpleTransparentPipeline =
std::make_shared<render::ShapePipeline>(getSimplePipeline(false, true, true, false), nullptr,
[](const render::ShapePipeline&, gpu::Batch& batch) {
[](const render::ShapePipeline&, gpu::Batch& batch, RenderArgs* args) {
// Set the defaults needed for a simple program
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO,
DependencyManager::get<TextureCache>()->getWhiteTexture());
@ -471,7 +471,7 @@ _nextID(0) {
);
GeometryCache::_simpleWirePipeline =
std::make_shared<render::ShapePipeline>(getSimplePipeline(false, false, true, true), nullptr,
[](const render::ShapePipeline&, gpu::Batch& batch) {});
[](const render::ShapePipeline&, gpu::Batch& batch, RenderArgs* args) {});
}
GeometryCache::~GeometryCache() {
@ -1938,7 +1938,7 @@ uint32_t toCompactColor(const glm::vec4& color) {
static const size_t INSTANCE_COLOR_BUFFER = 0;
void renderInstances(gpu::Batch& batch, const glm::vec4& color, bool isWire,
void renderInstances(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color, bool isWire,
const render::ShapePipelinePointer& pipeline, GeometryCache::Shape shape) {
// Add pipeline to name
std::string instanceName = (isWire ? "wire_shapes_" : "solid_shapes_") + std::to_string(shape) + "_" + std::to_string(std::hash<render::ShapePipelinePointer>()(pipeline));
@ -1951,9 +1951,9 @@ void renderInstances(gpu::Batch& batch, const glm::vec4& color, bool isWire,
}
// Add call to named buffer
batch.setupNamedCalls(instanceName, [isWire, pipeline, shape](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {
batch.setupNamedCalls(instanceName, [args, isWire, pipeline, shape](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {
batch.setPipeline(pipeline->pipeline);
pipeline->prepare(batch);
pipeline->prepare(batch, args);
if (isWire) {
DependencyManager::get<GeometryCache>()->renderWireShapeInstances(batch, shape, data.count(), data.buffers[INSTANCE_COLOR_BUFFER]);
@ -1963,28 +1963,28 @@ void renderInstances(gpu::Batch& batch, const glm::vec4& color, bool isWire,
});
}
void GeometryCache::renderSolidShapeInstance(gpu::Batch& batch, GeometryCache::Shape shape, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
renderInstances(batch, color, false, pipeline, shape);
void GeometryCache::renderSolidShapeInstance(RenderArgs* args, gpu::Batch& batch, GeometryCache::Shape shape, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
renderInstances(args, batch, color, false, pipeline, shape);
}
void GeometryCache::renderWireShapeInstance(gpu::Batch& batch, GeometryCache::Shape shape, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
renderInstances(batch, color, true, pipeline, shape);
void GeometryCache::renderWireShapeInstance(RenderArgs* args, gpu::Batch& batch, GeometryCache::Shape shape, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
renderInstances(args, batch, color, true, pipeline, shape);
}
void GeometryCache::renderSolidSphereInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
renderInstances(batch, color, false, pipeline, GeometryCache::Sphere);
void GeometryCache::renderSolidSphereInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
renderInstances(args, batch, color, false, pipeline, GeometryCache::Sphere);
}
void GeometryCache::renderWireSphereInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
renderInstances(batch, color, true, pipeline, GeometryCache::Sphere);
void GeometryCache::renderWireSphereInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
renderInstances(args, batch, color, true, pipeline, GeometryCache::Sphere);
}
// Enable this in a debug build to cause 'box' entities to iterate through all the
// available shape types, both solid and wireframes
//#define DEBUG_SHAPES
void GeometryCache::renderSolidCubeInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
void GeometryCache::renderSolidCubeInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
#ifdef DEBUG_SHAPES
static auto startTime = usecTimestampNow();
renderInstances(INSTANCE_NAME, batch, color, pipeline, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {
@ -2018,11 +2018,11 @@ void GeometryCache::renderSolidCubeInstance(gpu::Batch& batch, const glm::vec4&
}
});
#else
renderInstances(batch, color, false, pipeline, GeometryCache::Cube);
renderInstances(args, batch, color, false, pipeline, GeometryCache::Cube);
#endif
}
void GeometryCache::renderWireCubeInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
void GeometryCache::renderWireCubeInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
static const std::string INSTANCE_NAME = __FUNCTION__;
renderInstances(batch, color, true, pipeline, GeometryCache::Cube);
renderInstances(args, batch, color, true, pipeline, GeometryCache::Cube);
}

View file

@ -172,46 +172,46 @@ public:
void renderShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer);
void renderWireShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer);
void renderSolidShapeInstance(gpu::Batch& batch, Shape shape, const glm::vec4& color = glm::vec4(1),
void renderSolidShapeInstance(RenderArgs* args, gpu::Batch& batch, Shape shape, const glm::vec4& color = glm::vec4(1),
const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline);
void renderSolidShapeInstance(gpu::Batch& batch, Shape shape, const glm::vec3& color,
void renderSolidShapeInstance(RenderArgs* args, gpu::Batch& batch, Shape shape, const glm::vec3& color,
const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline) {
renderSolidShapeInstance(batch, shape, glm::vec4(color, 1.0f), pipeline);
renderSolidShapeInstance(args, batch, shape, glm::vec4(color, 1.0f), pipeline);
}
void renderWireShapeInstance(gpu::Batch& batch, Shape shape, const glm::vec4& color = glm::vec4(1),
void renderWireShapeInstance(RenderArgs* args, gpu::Batch& batch, Shape shape, const glm::vec4& color = glm::vec4(1),
const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline);
void renderWireShapeInstance(gpu::Batch& batch, Shape shape, const glm::vec3& color,
void renderWireShapeInstance(RenderArgs* args, gpu::Batch& batch, Shape shape, const glm::vec3& color,
const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline) {
renderWireShapeInstance(batch, shape, glm::vec4(color, 1.0f), pipeline);
renderWireShapeInstance(args, batch, shape, glm::vec4(color, 1.0f), pipeline);
}
void renderSolidSphereInstance(gpu::Batch& batch, const glm::vec4& color,
void renderSolidSphereInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color,
const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline);
void renderSolidSphereInstance(gpu::Batch& batch, const glm::vec3& color,
void renderSolidSphereInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec3& color,
const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline) {
renderSolidSphereInstance(batch, glm::vec4(color, 1.0f), pipeline);
renderSolidSphereInstance(args, batch, glm::vec4(color, 1.0f), pipeline);
}
void renderWireSphereInstance(gpu::Batch& batch, const glm::vec4& color,
void renderWireSphereInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color,
const render::ShapePipelinePointer& pipeline = _simpleWirePipeline);
void renderWireSphereInstance(gpu::Batch& batch, const glm::vec3& color,
void renderWireSphereInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec3& color,
const render::ShapePipelinePointer& pipeline = _simpleWirePipeline) {
renderWireSphereInstance(batch, glm::vec4(color, 1.0f), pipeline);
renderWireSphereInstance(args, batch, glm::vec4(color, 1.0f), pipeline);
}
void renderSolidCubeInstance(gpu::Batch& batch, const glm::vec4& color,
void renderSolidCubeInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color,
const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline);
void renderSolidCubeInstance(gpu::Batch& batch, const glm::vec3& color,
void renderSolidCubeInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec3& color,
const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline) {
renderSolidCubeInstance(batch, glm::vec4(color, 1.0f), pipeline);
renderSolidCubeInstance(args, batch, glm::vec4(color, 1.0f), pipeline);
}
void renderWireCubeInstance(gpu::Batch& batch, const glm::vec4& color,
void renderWireCubeInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color,
const render::ShapePipelinePointer& pipeline = _simpleWirePipeline);
void renderWireCubeInstance(gpu::Batch& batch, const glm::vec3& color,
void renderWireCubeInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec3& color,
const render::ShapePipelinePointer& pipeline = _simpleWirePipeline) {
renderWireCubeInstance(batch, glm::vec4(color, 1.0f), pipeline);
renderWireCubeInstance(args, batch, glm::vec4(color, 1.0f), pipeline);
}
// Dynamic geometry

View file

@ -574,8 +574,8 @@ void LightClusteringPass::run(const render::RenderContextPointer& renderContext,
}
// From the LightStage and the current frame, update the light cluster Grid
auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
auto lightStage = deferredLightingEffect->getLightStage();
auto lightStage = renderContext->_scene->getStage<LightStage>();
assert(lightStage);
_lightClusters->updateLightStage(lightStage);
_lightClusters->updateLightFrame(lightStage->_currentFrame, lightingModel->isPointLightEnabled(), lightingModel->isSpotLightEnabled());

View file

@ -55,7 +55,8 @@ LightPayload::~LightPayload() {
void LightPayload::render(RenderArgs* args) {
if (!_stage) {
_stage = DependencyManager::get<DeferredLightingEffect>()->getLightStage();
_stage = args->_scene->getStage<LightStage>();
assert(_stage);
}
// Do we need to allocate the light in the stage ?
if (LightStage::isIndexInvalid(_index)) {
@ -123,7 +124,8 @@ KeyLightPayload::~KeyLightPayload() {
void KeyLightPayload::render(RenderArgs* args) {
if (!_stage) {
_stage = DependencyManager::get<DeferredLightingEffect>()->getLightStage();
_stage = args->_scene->getStage<LightStage>();
assert(_stage);
}
// Do we need to allocate the light in the stage ?
if (LightStage::isIndexInvalid(_index)) {

View file

@ -13,6 +13,11 @@
#include "LightStage.h"
std::string LightStage::_stageName { "LIGHT_STAGE"};
LightStage::LightStage() {
}
LightStage::Shadow::Shadow(model::LightPointer light) : _light{ light}, _frustum{ std::make_shared<ViewFrustum>() } {
framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(MAP_SIZE));
map = framebuffer->getDepthStencilBuffer();
@ -165,3 +170,14 @@ void LightStage::updateLightArrayBuffer(Index lightId) {
}
}
LightStageSetup::LightStageSetup() {
}
void LightStageSetup::run(const render::RenderContextPointer& renderContext) {
auto stage = renderContext->_scene->getStage(LightStage::getName());
if (!stage) {
stage = std::make_shared<LightStage>();
renderContext->_scene->resetStage(LightStage::getName(), stage);
}
}

View file

@ -14,17 +14,23 @@
#include <set>
#include <unordered_map>
#include <gpu/Framebuffer.h>
#include <model/Light.h>
#include <render/IndexedContainer.h>
#include "gpu/Framebuffer.h"
#include "model/Light.h"
#include <render/Stage.h>
#include <render/Engine.h>
class ViewFrustum;
// Light stage to set up light-related rendering tasks
class LightStage {
class LightStage : public render::Stage {
public:
static std::string _stageName;
static const std::string& getName() { return _stageName; }
using Index = render::indexed_container::Index;
static const Index INVALID_INDEX { render::indexed_container::INVALID_INDEX };
static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; }
@ -93,6 +99,7 @@ public:
LightPointer getLight(Index lightId) const {
return _lights.get(lightId);
}
Index getShadowId(Index lightId) const {
if (checkLightId(lightId)) {
return _descs[lightId].shadowId;
@ -109,6 +116,7 @@ public:
return LightAndShadow(getLight(lightId), getShadow(lightId));
}
LightStage();
Lights _lights;
LightMap _lightMap;
Descs _descs;
@ -149,5 +157,15 @@ using LightStagePointer = std::shared_ptr<LightStage>;
class LightStageSetup {
public:
using JobModel = render::Job::Model<LightStageSetup>;
LightStageSetup();
void run(const render::RenderContextPointer& renderContext);
protected:
};
#endif

View file

@ -259,7 +259,7 @@ void MeshPartPayload::render(RenderArgs* args) {
gpu::Batch& batch = *(args->_batch);
auto locations = args->_pipeline->locations;
auto locations = args->_shapePipeline->locations;
assert(locations);
// Bind the model transform and the skinCLusterMatrices if needed
@ -583,7 +583,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
}
gpu::Batch& batch = *(args->_batch);
auto locations = args->_pipeline->locations;
auto locations = args->_shapePipeline->locations;
assert(locations);
bindTransform(batch, locations, args->_renderMode);

View file

@ -76,8 +76,8 @@ void initForwardPipelines(ShapePlumber& plumber);
void addPlumberPipeline(ShapePlumber& plumber,
const ShapeKey& key, const gpu::ShaderPointer& vertex, const gpu::ShaderPointer& pixel);
void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch);
void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch);
void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch, RenderArgs* args);
void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch, RenderArgs* args);
void initOverlay3DPipelines(ShapePlumber& plumber) {
auto vertex = gpu::Shader::createVertex(std::string(overlay3D_vert));
@ -359,7 +359,7 @@ void addPlumberPipeline(ShapePlumber& plumber,
}
}
void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) {
void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch, RenderArgs* args) {
// Set a default albedo map
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO,
DependencyManager::get<TextureCache>()->getWhiteTexture());
@ -382,13 +382,13 @@ void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) {
}
}
void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) {
void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch, RenderArgs* args) {
// Set the batch
batchSetter(pipeline, batch);
batchSetter(pipeline, batch, args);
// Set the light
if (pipeline.locations->lightBufferUnit >= 0) {
DependencyManager::get<DeferredLightingEffect>()->setupKeyLightBatch(batch,
DependencyManager::get<DeferredLightingEffect>()->setupKeyLightBatch(args, batch,
pipeline.locations->lightBufferUnit,
pipeline.locations->lightAmbientBufferUnit,
pipeline.locations->lightAmbientMapUnit);

View file

@ -35,8 +35,8 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext,
assert(renderContext->args);
assert(renderContext->args->hasViewFrustum());
auto lightStage = DependencyManager::get<DeferredLightingEffect>()->getLightStage();
auto lightStage = renderContext->_scene->getStage<LightStage>();
assert(lightStage);
LightStage::Index globalLightIndex { 0 };
const auto globalLight = lightStage->getLight(globalLightIndex);
@ -68,7 +68,7 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext,
std::vector<ShapeKey> skinnedShapeKeys{};
// Iterate through all inShapes and render the unskinned
args->_pipeline = shadowPipeline;
args->_shapePipeline = shadowPipeline;
batch.setPipeline(shadowPipeline->pipeline);
for (auto items : inShapes) {
if (items.first.isSkinned()) {
@ -79,13 +79,13 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext,
}
// Reiterate to render the skinned
args->_pipeline = shadowSkinnedPipeline;
args->_shapePipeline = shadowSkinnedPipeline;
batch.setPipeline(shadowSkinnedPipeline->pipeline);
for (const auto& key : skinnedShapeKeys) {
renderItems(renderContext, inShapes.at(key));
}
args->_pipeline = nullptr;
args->_shapePipeline = nullptr;
args->_batch = nullptr;
});
}
@ -140,7 +140,8 @@ void RenderShadowTask::configure(const Config& configuration) {
}
void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, Output& output) {
auto lightStage = DependencyManager::get<DeferredLightingEffect>()->getLightStage();
auto lightStage = renderContext->_scene->getStage<LightStage>();
assert(lightStage);
const auto globalShadow = lightStage->getShadow(0);
// Cache old render args

View file

@ -532,9 +532,11 @@ void DebugSubsurfaceScattering::run(const render::RenderContextPointer& renderCo
const auto light = DependencyManager::get<DeferredLightingEffect>()->getLightStage()->getLight(0);
auto lightStage = renderContext->_scene->getStage<LightStage>();
assert(lightStage);
// const auto light = DependencyManager::get<DeferredLightingEffect>()->getLightStage()->getLight(0);
const auto light = lightStage->getLight(0);
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
batch.enableStereo(false);

View file

@ -0,0 +1,26 @@
//
// UpdateSceneTask.cpp
// render-utils/src/
//
// Created by Sam Gateau on 6/21/2017.
// Copyright 2017 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 "UpdateSceneTask.h"
#include <render/SceneTask.h>
#include "LightStage.h"
#include "BackgroundStage.h"
#include "DeferredLightingEffect.h"
void UpdateSceneTask::build(JobModel& task, const render::Varying& input, render::Varying& output) {
task.addJob<LightStageSetup>("LightStageSetup");
task.addJob<BackgroundStageSetup>("BackgroundStageSetup");
task.addJob<DefaultLightingSetup>("DefaultLightingSetup");
task.addJob<render::PerformSceneTransaction>("PerformSceneTransaction");
}

View file

@ -0,0 +1,30 @@
//
// UpdateSceneTask.h
// render-utils/src/
//
// Created by Sam Gateau on 6/21/2017.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#pragma once
#ifndef hifi_UpdateSceneTask_h
#define hifi_UpdateSceneTask_h
#include <render/Engine.h>
#include <render/RenderFetchCullSortTask.h>
class UpdateSceneTask {
public:
using JobModel = render::Task::Model<UpdateSceneTask>;
UpdateSceneTask() {}
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs);
};
#endif // hifi_UpdateSceneTask_h

View file

@ -52,13 +52,21 @@ void ZoneRendererTask::build(JobModel& task, const Varying& input, Varying& oupu
}
void SetupZones::run(const RenderContextPointer& context, const Inputs& inputs) {
auto backgroundStage = DependencyManager::get<DeferredLightingEffect>()->getBackgroundStage();
auto backgroundStage = context->_scene->getStage<BackgroundStage>();
assert(backgroundStage);
backgroundStage->_currentFrame.clear();
// call render in the correct order first...
render::renderItems(context, inputs);
// Finally add the default lights and background:
auto lightStage = context->_scene->getStage<LightStage>();
assert(lightStage);
lightStage->_currentFrame.pushSunLight(0);
lightStage->_currentFrame.pushAmbientLight(0);
backgroundStage->_currentFrame.pushBackground(0);
}
const gpu::PipelinePointer& DebugZoneLighting::getKeyLightPipeline() {
@ -130,14 +138,13 @@ void DebugZoneLighting::run(const render::RenderContextPointer& context, const I
auto deferredTransform = inputs;
auto lightStage = DependencyManager::get<DeferredLightingEffect>()->getLightStage();
auto lightStage = context->_scene->getStage<LightStage>(LightStage::getName());
std::vector<model::LightPointer> keyLightStack;
if (lightStage && lightStage->_currentFrame._sunLights.size()) {
for (auto index : lightStage->_currentFrame._sunLights) {
keyLightStack.push_back(lightStage->getLight(index));
}
}
keyLightStack.push_back(DependencyManager::get<DeferredLightingEffect>()->getGlobalLight());
std::vector<model::LightPointer> ambientLightStack;
if (lightStage && lightStage->_currentFrame._ambientLights.size()) {
@ -145,10 +152,8 @@ void DebugZoneLighting::run(const render::RenderContextPointer& context, const I
ambientLightStack.push_back(lightStage->getLight(index));
}
}
ambientLightStack.push_back(DependencyManager::get<DeferredLightingEffect>()->getGlobalLight());
auto backgroundStage = DependencyManager::get<DeferredLightingEffect>()->getBackgroundStage();
auto backgroundStage = context->_scene->getStage<BackgroundStage>(BackgroundStage::getName());
std::vector<model::SkyboxPointer> skyboxStack;
if (backgroundStage && backgroundStage->_currentFrame._backgrounds.size()) {
for (auto index : backgroundStage->_currentFrame._backgrounds) {
@ -157,8 +162,7 @@ void DebugZoneLighting::run(const render::RenderContextPointer& context, const I
skyboxStack.push_back(background->getSkybox());
}
}
}
skyboxStack.push_back(DependencyManager::get<DeferredLightingEffect>()->getDefaultSkybox());
}
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {

View file

@ -103,7 +103,7 @@ namespace render {
std::shared_ptr<gpu::Context> _context;
std::shared_ptr<gpu::Framebuffer> _blitFramebuffer;
std::shared_ptr<render::ShapePipeline> _pipeline;
std::shared_ptr<render::ShapePipeline> _shapePipeline;
QSharedPointer<QObject> _renderData;
std::stack<ViewFrustum> _viewFrustums;
glm::ivec4 _viewport { 0.0f, 0.0f, 1.0f, 1.0f };

View file

@ -43,11 +43,11 @@ void renderShape(RenderArgs* args, const ShapePlumberPointer& shapeContext, cons
assert(item.getKey().isShape());
auto key = item.getShapeKey() | globalKey;
if (key.isValid() && !key.hasOwnPipeline()) {
args->_pipeline = shapeContext->pickPipeline(args, key);
if (args->_pipeline) {
args->_shapePipeline = shapeContext->pickPipeline(args, key);
if (args->_shapePipeline) {
item.render(args);
}
args->_pipeline = nullptr;
args->_shapePipeline = nullptr;
} else if (key.hasOwnPipeline()) {
item.render(args);
} else {
@ -109,15 +109,15 @@ void render::renderStateSortShapes(const RenderContextPointer& renderContext,
// Then render
for (auto& pipelineKey : sortedPipelines) {
auto& bucket = sortedShapes[pipelineKey];
args->_pipeline = shapeContext->pickPipeline(args, pipelineKey);
if (!args->_pipeline) {
args->_shapePipeline = shapeContext->pickPipeline(args, pipelineKey);
if (!args->_shapePipeline) {
continue;
}
for (auto& item : bucket) {
item.render(args);
}
}
args->_pipeline = nullptr;
args->_shapePipeline = nullptr;
for (auto& item : ownPipelineBucket) {
item.render(args);
}

View file

@ -18,6 +18,8 @@
#include <gpu/Context.h>
#include "EngineStats.h"
#include "SceneTask.h"
#include "Logging.h"
using namespace render;

View file

@ -237,3 +237,26 @@ void Scene::resetSelections(const Selections& selections) {
}
}
}
// Access a particular Stage (empty if doesn't exist)
// Thread safe
StagePointer Scene::getStage(const Stage::Name& name) const {
std::unique_lock<std::mutex> lock(_stagesMutex);
auto found = _stages.find(name);
if (found == _stages.end()) {
return StagePointer();
} else {
return (*found).second;
}
}
void Scene::resetStage(const Stage::Name& name, const StagePointer& stage) {
std::unique_lock<std::mutex> lock(_stagesMutex);
auto found = _stages.find(name);
if (found == _stages.end()) {
_stages.insert(StageMap::value_type(name, stage));
} else {
(*found).second = stage;
}
}

View file

@ -14,6 +14,7 @@
#include "Item.h"
#include "SpatialTree.h"
#include "Stage.h"
#include "Selection.h"
namespace render {
@ -110,6 +111,19 @@ public:
// Access non-spatialized items (overlays, backgrounds)
const ItemIDSet& getNonspatialSet() const { return _masterNonspatialSet; }
// Access a particular Stage (empty if doesn't exist)
// Thread safe
StagePointer getStage(const Stage::Name& name) const;
template <class T>
std::shared_ptr<T> getStage(const Stage::Name& name = T::getName()) const {
auto stage = getStage(name);
return (stage ? std::static_pointer_cast<T>(stage) : std::shared_ptr<T>());
}
void resetStage(const Stage::Name& name, const StagePointer& stage);
protected:
// Thread safe elements that can be accessed from anywhere
std::atomic<unsigned int> _IDAllocator{ 1 }; // first valid itemID will be One
@ -128,7 +142,6 @@ protected:
void removeItems(const ItemIDs& ids);
void updateItems(const ItemIDs& ids, UpdateFunctors& functors);
// The Selection map
mutable std::mutex _selectionsMutex; // mutable so it can be used in the thread safe getSelection const method
SelectionMap _selections;
@ -139,6 +152,11 @@ protected:
// void appendToSelection(const Selection& selection);
// void mergeWithSelection(const Selection& selection);
// The Stage map
mutable std::mutex _stagesMutex; // mutable so it can be used in the thread safe getStage const method
StageMap _stages;
friend class Engine;
};

View file

@ -0,0 +1,21 @@
//
// SceneTask.cpp
// render/src/render
//
// Created by Sam Gateau on 6/14/2017.
// Copyright 2017 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 "SceneTask.h"
using namespace render;
void PerformSceneTransaction::configure(const Config& config) {
}
void PerformSceneTransaction::run(const RenderContextPointer& renderContext) {
renderContext->_scene->processTransactionQueue();
}

View file

@ -0,0 +1,41 @@
//
// SceneTask.h
// render/src/render
//
// Created by Sam Gateau on 6/14/2017.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_render_SceneTask_h
#define hifi_render_SceneTask_h
#include "Engine.h"
namespace render {
class PerformSceneTransactionConfig : public Job::Config {
Q_OBJECT
public:
signals:
void dirty();
protected:
};
class PerformSceneTransaction {
public:
using Config = PerformSceneTransactionConfig;
using JobModel = Job::Model<PerformSceneTransaction, Config>;
void configure(const Config& config);
void run(const RenderContextPointer& renderContext);
protected:
};
}
#endif // hifi_render_SceneTask_h

View file

@ -17,9 +17,9 @@
using namespace render;
void ShapePipeline::prepare(gpu::Batch& batch) {
void ShapePipeline::prepare(gpu::Batch& batch, RenderArgs* args) {
if (batchSetter) {
batchSetter(*this, batch);
batchSetter(*this, batch, args);
}
}
@ -119,7 +119,7 @@ const ShapePipelinePointer ShapePlumber::pickPipeline(RenderArgs* args, const Ke
// Run the pipeline's BatchSetter on the passed in batch
if (shapePipeline->batchSetter) {
shapePipeline->batchSetter(*shapePipeline, *batch);
shapePipeline->batchSetter(*shapePipeline, *batch, args);
}
return shapePipeline;

View file

@ -240,14 +240,14 @@ public:
};
using LocationsPointer = std::shared_ptr<Locations>;
using BatchSetter = std::function<void(const ShapePipeline&, gpu::Batch&)>;
using BatchSetter = std::function<void(const ShapePipeline&, gpu::Batch&, RenderArgs* args)>;
ShapePipeline(gpu::PipelinePointer pipeline, LocationsPointer locations, BatchSetter batchSetter) :
pipeline(pipeline), locations(locations), batchSetter(batchSetter) {}
// Normally, a pipeline is accessed thorugh pickPipeline. If it needs to be set manually,
// after calling setPipeline this method should be called to prepare the pipeline with default buffers.
void prepare(gpu::Batch& batch);
void prepare(gpu::Batch& batch, RenderArgs* args);
gpu::PipelinePointer pipeline;
std::shared_ptr<Locations> locations;

View file

@ -0,0 +1,26 @@
//
// Stage.cpp
// render/src/render
//
// Created by Sam Gateau on 6/14/2017.
// Copyright 2017 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 "Stage.h"
using namespace render;
Stage::~Stage() {
}
Stage::Stage() :
_name()
{
}

View file

@ -0,0 +1,38 @@
//
// Stage.h
// render/src/render
//
// Created by Sam Gateau on 6/14/2017.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_render_Stage_h
#define hifi_render_Stage_h
#include <memory>
#include <map>
#include <string>
namespace render {
class Stage {
public:
using Name = std::string;
Stage();
virtual ~Stage();
protected:
Name _name;
};
using StagePointer = std::shared_ptr<Stage>;
using StageMap = std::map<const Stage::Name, StagePointer>;
}
#endif // hifi_render_Stage_h

View file

@ -15,6 +15,9 @@
#include "NumericalConstants.h" // for MILLIMETERS_PER_METER
// Bullet doesn't support arbitrarily small shapes
const float MIN_HALF_EXTENT = 0.005f; // 0.5 cm
void ShapeInfo::clear() {
_url.clear();
_pointCollection.clear();
@ -26,14 +29,20 @@ void ShapeInfo::clear() {
}
void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString url) {
_url = "";
_type = type;
_halfExtents = halfExtents;
setHalfExtents(halfExtents);
switch(type) {
case SHAPE_TYPE_NONE:
_halfExtents = glm::vec3(0.0f);
break;
case SHAPE_TYPE_BOX:
case SHAPE_TYPE_SPHERE:
break;
case SHAPE_TYPE_SPHERE: {
float radius = glm::length(halfExtents) / SQUARE_ROOT_OF_3;
radius = glm::max(radius, MIN_HALF_EXTENT);
_halfExtents = glm::vec3(radius);
}
break;
case SHAPE_TYPE_COMPOUND:
case SHAPE_TYPE_STATIC_MESH:
@ -48,14 +57,15 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString
void ShapeInfo::setBox(const glm::vec3& halfExtents) {
_url = "";
_type = SHAPE_TYPE_BOX;
_halfExtents = halfExtents;
setHalfExtents(halfExtents);
_doubleHashKey.clear();
}
void ShapeInfo::setSphere(float radius) {
_url = "";
_type = SHAPE_TYPE_SPHERE;
_halfExtents = glm::vec3(radius, radius, radius);
radius = glm::max(radius, MIN_HALF_EXTENT);
_halfExtents = glm::vec3(radius);
_doubleHashKey.clear();
}
@ -68,6 +78,8 @@ void ShapeInfo::setPointCollection(const ShapeInfo::PointCollection& pointCollec
void ShapeInfo::setCapsuleY(float radius, float halfHeight) {
_url = "";
_type = SHAPE_TYPE_CAPSULE_Y;
radius = glm::max(radius, MIN_HALF_EXTENT);
halfHeight = glm::max(halfHeight, 0.0f);
_halfExtents = glm::vec3(radius, halfHeight, radius);
_doubleHashKey.clear();
}
@ -239,3 +251,7 @@ const DoubleHashKey& ShapeInfo::getHash() const {
}
return _doubleHashKey;
}
void ShapeInfo::setHalfExtents(const glm::vec3& halfExtents) {
_halfExtents = glm::max(halfExtents, glm::vec3(MIN_HALF_EXTENT));
}

View file

@ -89,6 +89,8 @@ public:
const DoubleHashKey& getHash() const;
protected:
void setHalfExtents(const glm::vec3& halfExtents);
QUrl _url; // url for model of convex collision hulls
PointCollection _pointCollection;
TriangleIndices _triangleIndices;

View file

@ -1010,7 +1010,6 @@ function setupModelMenus() {
Menu.addMenuItem({
menuName: "Edit",
menuItemName: "Entity List...",
shortcutKey: "CTRL+META+L",
afterItem: "Entities",
grouping: "Advanced"
});
@ -1041,7 +1040,6 @@ function setupModelMenus() {
Menu.addMenuItem({
menuName: "Edit",
menuItemName: "Allow Selecting of Large Models",
shortcutKey: "CTRL+META+L",
afterItem: GRABBABLE_ENTITIES_MENU_ITEM,
isCheckable: true,
isChecked: true,
@ -1050,7 +1048,6 @@ function setupModelMenus() {
Menu.addMenuItem({
menuName: "Edit",
menuItemName: "Allow Selecting of Small Models",
shortcutKey: "CTRL+META+S",
afterItem: "Allow Selecting of Large Models",
isCheckable: true,
isChecked: true,
@ -1059,7 +1056,6 @@ function setupModelMenus() {
Menu.addMenuItem({
menuName: "Edit",
menuItemName: "Allow Selecting of Lights",
shortcutKey: "CTRL+SHIFT+META+L",
afterItem: "Allow Selecting of Small Models",
isCheckable: true,
grouping: "Advanced"
@ -1067,14 +1063,12 @@ function setupModelMenus() {
Menu.addMenuItem({
menuName: "Edit",
menuItemName: "Select All Entities In Box",
shortcutKey: "CTRL+SHIFT+META+A",
afterItem: "Allow Selecting of Lights",
grouping: "Advanced"
});
Menu.addMenuItem({
menuName: "Edit",
menuItemName: "Select All Entities Touching Box",
shortcutKey: "CTRL+SHIFT+META+T",
afterItem: "Select All Entities In Box",
grouping: "Advanced"
});
@ -1082,21 +1076,18 @@ function setupModelMenus() {
Menu.addMenuItem({
menuName: "Edit",
menuItemName: "Export Entities",
shortcutKey: "CTRL+META+E",
afterItem: "Entities",
grouping: "Advanced"
});
Menu.addMenuItem({
menuName: "Edit",
menuItemName: "Import Entities",
shortcutKey: "CTRL+META+I",
afterItem: "Export Entities",
grouping: "Advanced"
});
Menu.addMenuItem({
menuName: "Edit",
menuItemName: "Import Entities from URL",
shortcutKey: "CTRL+META+U",
afterItem: "Import Entities",
grouping: "Advanced"
});

View file

@ -862,6 +862,9 @@ function avatarDisconnected(nodeID) {
function clearLocalQMLDataAndClosePAL() {
sendToQml({ method: 'clearLocalQMLData' });
if (onPalScreen) {
tablet.gotoHomeScreen();
}
}
function avatarAdded(avatarID) {

View file

@ -77,7 +77,6 @@ void TestWindow::initGl() {
#ifdef DEFERRED_LIGHTING
auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
deferredLightingEffect->init();
deferredLightingEffect->setGlobalLight(_light);
initDeferredPipelines(*_shapePlumber);
#endif
}

View file

@ -889,11 +889,6 @@ private:
BackgroundRenderData::_item = _main3DScene->allocateID();
transaction.resetItem(BackgroundRenderData::_item, backgroundRenderPayload);
}
// Setup the current Zone Entity lighting
{
auto stage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(stage->getSunLight());
}
{
PerformanceTimer perfTimer("SceneProcessTransaction");
@ -914,8 +909,6 @@ private:
PerformanceTimer perfTimer("draw");
// The pending changes collecting the changes here
render::Transaction transaction;
// Setup the current Zone Entity lighting
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(_sunSkyStage.getSunLight());
{
PerformanceTimer perfTimer("SceneProcessTransaction");
_main3DScene->enqueueTransaction(transaction);

View file

@ -17,8 +17,8 @@ set_target_properties(ac-client PROPERTIES FOLDER "Tools")
add_subdirectory(skeleton-dump)
set_target_properties(skeleton-dump PROPERTIES FOLDER "Tools")
add_subdirectory(atp-get)
set_target_properties(atp-get PROPERTIES FOLDER "Tools")
add_subdirectory(atp-client)
set_target_properties(atp-client PROPERTIES FOLDER "Tools")
add_subdirectory(oven)
set_target_properties(oven PROPERTIES FOLDER "Tools")

View file

@ -14,6 +14,7 @@
#include <QLoggingCategory>
#include <QCommandLineParser>
#include <NetworkLogging.h>
#include <NetworkingConstants.h>
#include <SharedLogging.h>
#include <AddressManager.h>
#include <DependencyManager.h>
@ -33,6 +34,9 @@ ACClientApp::ACClientApp(int argc, char* argv[]) :
const QCommandLineOption verboseOutput("v", "verbose output");
parser.addOption(verboseOutput);
const QCommandLineOption authOption("u", "set usename and pass", "username:password");
parser.addOption(authOption);
const QCommandLineOption domainAddressOption("d", "domain-server address", "127.0.0.1");
parser.addOption(domainAddressOption);
@ -81,6 +85,18 @@ ACClientApp::ACClientApp(int argc, char* argv[]) :
listenPort = parser.value(listenPortOption).toInt();
}
if (parser.isSet(authOption)) {
QStringList pieces = parser.value(authOption).split(":");
if (pieces.size() != 2) {
qDebug() << "-u should be followed by username:password";
parser.showHelp();
Q_UNREACHABLE();
}
_username = pieces[0];
_password = pieces[1];
}
Setting::init();
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
@ -88,6 +104,9 @@ ACClientApp::ACClientApp(int argc, char* argv[]) :
DependencyManager::set<AddressManager>();
DependencyManager::set<NodeList>(NodeType::Agent, listenPort);
auto accountManager = DependencyManager::get<AccountManager>();
accountManager->setIsAgent(true);
accountManager->setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL);
auto nodeList = DependencyManager::get<NodeList>();
@ -96,27 +115,45 @@ ACClientApp::ACClientApp(int argc, char* argv[]) :
connect(domainCheckInTimer, &QTimer::timeout, nodeList.data(), &NodeList::sendDomainServerCheckIn);
domainCheckInTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS);
// start the nodeThread so its event loop is running
// start the nodeThread so its event loop is running
// (must happen after the checkin timer is created with the nodelist as it's parent)
nodeList->startThread();
const DomainHandler& domainHandler = nodeList->getDomainHandler();
connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&)));
// connect(&domainHandler, SIGNAL(resetting()), SLOT(resettingDomain()));
// connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails()));
connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &ACClientApp::domainConnectionRefused);
connect(nodeList.data(), &NodeList::nodeAdded, this, &ACClientApp::nodeAdded);
connect(nodeList.data(), &NodeList::nodeKilled, this, &ACClientApp::nodeKilled);
connect(nodeList.data(), &NodeList::nodeActivated, this, &ACClientApp::nodeActivated);
// connect(nodeList.data(), &NodeList::uuidChanged, getMyAvatar(), &MyAvatar::setSessionUUID);
// connect(nodeList.data(), &NodeList::uuidChanged, this, &ACClientApp::setSessionUUID);
connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &ACClientApp::notifyPacketVersionMismatch);
nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer
<< NodeType::EntityServer << NodeType::AssetServer << NodeType::MessagesMixer);
if (_verbose) {
QString username = accountManager->getAccountInfo().getUsername();
qDebug() << "cached username is" << username << ", isLoggedIn =" << accountManager->isLoggedIn();
}
if (!_username.isEmpty()) {
connect(accountManager.data(), &AccountManager::newKeypair, this, [&](){
if (_verbose) {
qDebug() << "new keypair has been created.";
}
});
connect(accountManager.data(), &AccountManager::loginComplete, this, [&](){
if (_verbose) {
qDebug() << "login successful";
}
});
connect(accountManager.data(), &AccountManager::loginFailed, this, [&](){
qDebug() << "login failed.";
});
accountManager->requestAccessToken(_username, _password);
}
DependencyManager::get<AddressManager>()->handleLookupString(domainServerAddress, false);
QTimer* doTimer = new QTimer(this);

View file

@ -47,6 +47,9 @@ private:
bool _sawAvatarMixer { false };
bool _sawAssetServer { false };
bool _sawMessagesMixer { false };
QString _username;
QString _password;
};
#endif //hifi_ACClientApp_h

View file

@ -1,4 +1,4 @@
set(TARGET_NAME atp-get)
set(TARGET_NAME atp-client)
setup_hifi_project(Core Widgets)
setup_memory_debugger()
link_hifi_libraries(shared networking)

View file

@ -0,0 +1,406 @@
//
// ATPClientApp.cpp
// tools/atp-client/src
//
// Created by Seth Alves on 2017-3-15
// Copyright 2017 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 <QDataStream>
#include <QTextStream>
#include <QThread>
#include <QFile>
#include <QLoggingCategory>
#include <QCommandLineParser>
#include <NetworkLogging.h>
#include <NetworkingConstants.h>
#include <SharedLogging.h>
#include <AddressManager.h>
#include <DependencyManager.h>
#include <SettingHandle.h>
#include <AssetUpload.h>
#include "ATPClientApp.h"
#define HIGH_FIDELITY_ATP_CLIENT_USER_AGENT "Mozilla/5.0 (HighFidelityATPClient)"
#define TIMEOUT_MILLISECONDS 8000
ATPClientApp::ATPClientApp(int argc, char* argv[]) :
QCoreApplication(argc, argv)
{
// parse command-line
QCommandLineParser parser;
parser.setApplicationDescription("High Fidelity ATP-Client");
const QCommandLineOption helpOption = parser.addHelpOption();
const QCommandLineOption verboseOutput("v", "verbose output");
parser.addOption(verboseOutput);
const QCommandLineOption uploadOption("T", "upload local file", "local-file-to-send");
parser.addOption(uploadOption);
const QCommandLineOption authOption("u", "set usename and pass", "username:password");
parser.addOption(authOption);
const QCommandLineOption outputFilenameOption("o", "output filename", "output-file-name");
parser.addOption(outputFilenameOption);
const QCommandLineOption domainAddressOption("d", "domain-server address", "127.0.0.1");
parser.addOption(domainAddressOption);
const QCommandLineOption listenPortOption("listenPort", "listen port", QString::number(INVALID_PORT));
parser.addOption(listenPortOption);
if (!parser.parse(QCoreApplication::arguments())) {
qCritical() << parser.errorText() << endl;
parser.showHelp();
Q_UNREACHABLE();
}
if (parser.isSet(helpOption)) {
parser.showHelp();
Q_UNREACHABLE();
}
_verbose = parser.isSet(verboseOutput);
if (!_verbose) {
QLoggingCategory::setFilterRules("qt.network.ssl.warning=false");
const_cast<QLoggingCategory*>(&networking())->setEnabled(QtDebugMsg, false);
const_cast<QLoggingCategory*>(&networking())->setEnabled(QtInfoMsg, false);
const_cast<QLoggingCategory*>(&networking())->setEnabled(QtWarningMsg, false);
const_cast<QLoggingCategory*>(&shared())->setEnabled(QtDebugMsg, false);
const_cast<QLoggingCategory*>(&shared())->setEnabled(QtInfoMsg, false);
const_cast<QLoggingCategory*>(&shared())->setEnabled(QtWarningMsg, false);
}
QStringList posArgs = parser.positionalArguments();
if (posArgs.size() != 1) {
qDebug() << "give remote url argument";
parser.showHelp();
Q_UNREACHABLE();
}
_url = QUrl(posArgs[0]);
if (_url.scheme() != "atp") {
qDebug() << "url should start with atp:";
parser.showHelp();
Q_UNREACHABLE();
}
int domainPort = 40103;
if (_url.port() != -1) {
domainPort = _url.port();
}
if (parser.isSet(outputFilenameOption)) {
_localOutputFile = parser.value(outputFilenameOption);
}
if (parser.isSet(uploadOption)) {
_localUploadFile = parser.value(uploadOption);
}
if (parser.isSet(authOption)) {
QStringList pieces = parser.value(authOption).split(":");
if (pieces.size() != 2) {
qDebug() << "-u should be followed by username:password";
parser.showHelp();
Q_UNREACHABLE();
}
_username = pieces[0];
_password = pieces[1];
_waitingForLogin = true;
}
if (parser.isSet(listenPortOption)) {
_listenPort = parser.value(listenPortOption).toInt();
}
_domainServerAddress = QString("127.0.0.1") + ":" + QString::number(domainPort);
if (parser.isSet(domainAddressOption)) {
_domainServerAddress = parser.value(domainAddressOption);
} else if (!_url.host().isEmpty()) {
QUrl domainURL;
domainURL.setScheme("hifi");
domainURL.setHost(_url.host());
_domainServerAddress = domainURL.toString();
}
Setting::init();
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
DependencyManager::set<AccountManager>([&]{ return QString(HIGH_FIDELITY_ATP_CLIENT_USER_AGENT); });
DependencyManager::set<AddressManager>();
DependencyManager::set<NodeList>(NodeType::Agent, _listenPort);
auto accountManager = DependencyManager::get<AccountManager>();
accountManager->setIsAgent(true);
accountManager->setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL);
auto nodeList = DependencyManager::get<NodeList>();
// setup a timer for domain-server check ins
_domainCheckInTimer = new QTimer(nodeList.data());
connect(_domainCheckInTimer, &QTimer::timeout, nodeList.data(), &NodeList::sendDomainServerCheckIn);
_domainCheckInTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS);
// start the nodeThread so its event loop is running
// (must happen after the checkin timer is created with the nodelist as it's parent)
nodeList->startThread();
const DomainHandler& domainHandler = nodeList->getDomainHandler();
connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&)));
connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &ATPClientApp::domainConnectionRefused);
connect(nodeList.data(), &NodeList::nodeAdded, this, &ATPClientApp::nodeAdded);
connect(nodeList.data(), &NodeList::nodeKilled, this, &ATPClientApp::nodeKilled);
connect(nodeList.data(), &NodeList::nodeActivated, this, &ATPClientApp::nodeActivated);
connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &ATPClientApp::notifyPacketVersionMismatch);
nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer
<< NodeType::EntityServer << NodeType::AssetServer << NodeType::MessagesMixer);
if (_verbose) {
QString username = accountManager->getAccountInfo().getUsername();
qDebug() << "cached username is" << username << ", isLoggedIn =" << accountManager->isLoggedIn();
}
if (!_username.isEmpty()) {
connect(accountManager.data(), &AccountManager::newKeypair, this, [&](){
if (_verbose) {
qDebug() << "new keypair has been created.";
}
});
connect(accountManager.data(), &AccountManager::loginComplete, this, [&](){
if (_verbose) {
qDebug() << "login successful";
}
_waitingForLogin = false;
go();
});
connect(accountManager.data(), &AccountManager::loginFailed, this, [&](){
qDebug() << "login failed.";
_waitingForLogin = false;
go();
});
accountManager->requestAccessToken(_username, _password);
}
auto assetClient = DependencyManager::set<AssetClient>();
assetClient->init();
if (_verbose) {
qDebug() << "domain-server address is" << _domainServerAddress;
}
DependencyManager::get<AddressManager>()->handleLookupString(_domainServerAddress, false);
QTimer* _timeoutTimer = new QTimer(this);
_timeoutTimer->setSingleShot(true);
connect(_timeoutTimer, &QTimer::timeout, this, &ATPClientApp::timedOut);
_timeoutTimer->start(TIMEOUT_MILLISECONDS);
}
ATPClientApp::~ATPClientApp() {
if (_domainCheckInTimer) {
QMetaObject::invokeMethod(_domainCheckInTimer, "deleteLater", Qt::QueuedConnection);
}
if (_timeoutTimer) {
QMetaObject::invokeMethod(_timeoutTimer, "deleteLater", Qt::QueuedConnection);
}
}
void ATPClientApp::domainConnectionRefused(const QString& reasonMessage, int reasonCodeInt, const QString& extraInfo) {
// this is non-fatal if we are trying to get an authenticated connection -- it will be retried.
if (_verbose) {
qDebug() << "domainConnectionRefused";
}
}
void ATPClientApp::domainChanged(const QString& domainHostname) {
if (_verbose) {
qDebug() << "domainChanged";
}
}
void ATPClientApp::nodeAdded(SharedNodePointer node) {
if (_verbose) {
qDebug() << "node added: " << node->getType();
}
}
void ATPClientApp::nodeActivated(SharedNodePointer node) {
if (!_waitingForLogin && node->getType() == NodeType::AssetServer) {
_waitingForNode = false;
go();
}
}
void ATPClientApp::go() {
if (_waitingForLogin || _waitingForNode) {
return;
}
auto path = _url.path();
if (_verbose) {
qDebug() << "path is " << path;
}
if (!_localUploadFile.isEmpty()) {
uploadAsset();
} else if (path == "/") {
listAssets();
} else {
lookupAsset();
}
}
void ATPClientApp::nodeKilled(SharedNodePointer node) {
if (_verbose) {
qDebug() << "nodeKilled" << node->getType();
}
}
void ATPClientApp::timedOut() {
finish(1);
}
void ATPClientApp::notifyPacketVersionMismatch() {
if (_verbose) {
qDebug() << "packet version mismatch";
}
finish(1);
}
void ATPClientApp::uploadAsset() {
auto path = _url.path();
if (path == "/") {
qDebug() << "cannot upload to path of /";
QCoreApplication::exit(1);
}
auto upload = DependencyManager::get<AssetClient>()->createUpload(_localUploadFile);
QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable {
if (upload->getError() != AssetUpload::NoError) {
qDebug() << "upload failed: " << upload->getErrorString();
} else {
setMapping(hash);
}
upload->deleteLater();
});
upload->start();
}
void ATPClientApp::setMapping(QString hash) {
auto path = _url.path();
auto assetClient = DependencyManager::get<AssetClient>();
auto request = assetClient->createSetMappingRequest(path, hash);
connect(request, &SetMappingRequest::finished, this, [=](SetMappingRequest* request) mutable {
if (request->getError() != SetMappingRequest::NoError) {
qDebug() << "upload succeeded, but couldn't set mapping: " << request->getErrorString();
} else if (_verbose) {
qDebug() << "mapping set.";
}
request->deleteLater();
finish(0);
});
request->start();
}
void ATPClientApp::listAssets() {
auto request = DependencyManager::get<AssetClient>()->createGetAllMappingsRequest();
QObject::connect(request, &GetAllMappingsRequest::finished, this, [=](GetAllMappingsRequest* request) mutable {
auto result = request->getError();
if (result == GetAllMappingsRequest::NotFound) {
qDebug() << "not found: " << request->getErrorString();
} else if (result == GetAllMappingsRequest::NoError) {
auto mappings = request->getMappings();
for (auto& kv : mappings ) {
qDebug() << kv.first << kv.second;
}
} else {
qDebug() << "error -- " << request->getError() << " -- " << request->getErrorString();
}
request->deleteLater();
finish(0);
});
request->start();
}
void ATPClientApp::lookupAsset() {
auto path = _url.path();
auto request = DependencyManager::get<AssetClient>()->createGetMappingRequest(path);
QObject::connect(request, &GetMappingRequest::finished, this, [=](GetMappingRequest* request) mutable {
auto result = request->getError();
if (result == GetMappingRequest::NotFound) {
qDebug() << "not found: " << request->getErrorString();
} else if (result == GetMappingRequest::NoError) {
qDebug() << "found, hash is " << request->getHash();
download(request->getHash());
} else {
qDebug() << "error -- " << request->getError() << " -- " << request->getErrorString();
}
request->deleteLater();
});
request->start();
}
void ATPClientApp::download(AssetHash hash) {
auto assetClient = DependencyManager::get<AssetClient>();
auto assetRequest = new AssetRequest(hash);
connect(assetRequest, &AssetRequest::finished, this, [this](AssetRequest* request) mutable {
Q_ASSERT(request->getState() == AssetRequest::Finished);
if (request->getError() == AssetRequest::Error::NoError) {
QString data = QString::fromUtf8(request->getData());
if (_localOutputFile == "" || _localOutputFile == "-") {
QTextStream cout(stdout);
cout << data;
} else {
QFile outputHandle(_localOutputFile);
if (outputHandle.open(QIODevice::ReadWrite)) {
QTextStream stream( &outputHandle );
stream << data;
} else {
qDebug() << "couldn't open output file:" << _localOutputFile;
}
}
}
request->deleteLater();
finish(0);
});
assetRequest->start();
}
void ATPClientApp::finish(int exitCode) {
auto nodeList = DependencyManager::get<NodeList>();
// send the domain a disconnect packet, force stoppage of domain-server check-ins
nodeList->getDomainHandler().disconnect();
nodeList->setIsShuttingDown(true);
// tell the packet receiver we're shutting down, so it can drop packets
nodeList->getPacketReceiver().setShouldDropPackets(true);
// remove the NodeList from the DependencyManager
DependencyManager::destroy<NodeList>();
QCoreApplication::exit(exitCode);
}

View file

@ -1,6 +1,6 @@
//
// ATPGetApp.h
// tools/atp-get/src
// ATPClientApp.h
// tools/atp-client/src
//
// Created by Seth Alves on 2017-3-15
// Copyright 2017 High Fidelity, Inc.
@ -10,8 +10,8 @@
//
#ifndef hifi_ATPGetApp_h
#define hifi_ATPGetApp_h
#ifndef hifi_ATPClientApp_h
#define hifi_ATPClientApp_h
#include <QApplication>
#include <udt/Constants.h>
@ -23,11 +23,11 @@
#include <MappingRequest.h>
class ATPGetApp : public QCoreApplication {
class ATPClientApp : public QCoreApplication {
Q_OBJECT
public:
ATPGetApp(int argc, char* argv[]);
~ATPGetApp();
ATPClientApp(int argc, char* argv[]);
~ATPClientApp();
private slots:
void domainConnectionRefused(const QString& reasonMessage, int reasonCodeInt, const QString& extraInfo);
@ -38,15 +38,33 @@ private slots:
void notifyPacketVersionMismatch();
private:
void go();
NodeList* _nodeList;
void timedOut();
void lookup();
void uploadAsset();
void setMapping(QString hash);
void lookupAsset();
void listAssets();
void download(AssetHash hash);
void finish(int exitCode);
bool _verbose;
QUrl _url;
QString _localOutputFile;
QString _localUploadFile;
int _listenPort { INVALID_PORT };
QString _domainServerAddress;
QString _username;
QString _password;
bool _waitingForLogin { false };
bool _waitingForNode { true };
QTimer* _domainCheckInTimer { nullptr };
QTimer* _timeoutTimer { nullptr };
};
#endif // hifi_ATPGetApp_h
#endif // hifi_ATPClientApp_h

View file

@ -1,6 +1,6 @@
//
// main.cpp
// tools/atp-get/src
// tools/atp-client/src
//
// Created by Seth Alves on 2017-3-15
// Copyright 2017 High Fidelity, Inc.
@ -15,7 +15,7 @@
#include <BuildInfo.h>
#include "ATPGetApp.h"
#include "ATPClientApp.h"
using namespace std;
@ -25,7 +25,7 @@ int main(int argc, char * argv[]) {
QCoreApplication::setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN);
QCoreApplication::setApplicationVersion(BuildInfo::VERSION);
ATPGetApp app(argc, argv);
ATPClientApp app(argc, argv);
return app.exec();
}

View file

@ -1,255 +0,0 @@
//
// ATPGetApp.cpp
// tools/atp-get/src
//
// Created by Seth Alves on 2017-3-15
// Copyright 2017 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 <QDataStream>
#include <QTextStream>
#include <QThread>
#include <QFile>
#include <QLoggingCategory>
#include <QCommandLineParser>
#include <NetworkLogging.h>
#include <SharedLogging.h>
#include <AddressManager.h>
#include <DependencyManager.h>
#include <SettingHandle.h>
#include "ATPGetApp.h"
ATPGetApp::ATPGetApp(int argc, char* argv[]) :
QCoreApplication(argc, argv)
{
// parse command-line
QCommandLineParser parser;
parser.setApplicationDescription("High Fidelity ATP-Get");
const QCommandLineOption helpOption = parser.addHelpOption();
const QCommandLineOption verboseOutput("v", "verbose output");
parser.addOption(verboseOutput);
const QCommandLineOption domainAddressOption("d", "domain-server address", "127.0.0.1");
parser.addOption(domainAddressOption);
const QCommandLineOption cacheSTUNOption("s", "cache stun-server response");
parser.addOption(cacheSTUNOption);
const QCommandLineOption listenPortOption("listenPort", "listen port", QString::number(INVALID_PORT));
parser.addOption(listenPortOption);
if (!parser.parse(QCoreApplication::arguments())) {
qCritical() << parser.errorText() << endl;
parser.showHelp();
Q_UNREACHABLE();
}
if (parser.isSet(helpOption)) {
parser.showHelp();
Q_UNREACHABLE();
}
_verbose = parser.isSet(verboseOutput);
if (!_verbose) {
QLoggingCategory::setFilterRules("qt.network.ssl.warning=false");
const_cast<QLoggingCategory*>(&networking())->setEnabled(QtDebugMsg, false);
const_cast<QLoggingCategory*>(&networking())->setEnabled(QtInfoMsg, false);
const_cast<QLoggingCategory*>(&networking())->setEnabled(QtWarningMsg, false);
const_cast<QLoggingCategory*>(&shared())->setEnabled(QtDebugMsg, false);
const_cast<QLoggingCategory*>(&shared())->setEnabled(QtInfoMsg, false);
const_cast<QLoggingCategory*>(&shared())->setEnabled(QtWarningMsg, false);
}
QStringList filenames = parser.positionalArguments();
if (filenames.empty() || filenames.size() > 2) {
qDebug() << "give remote url and optional local filename as arguments";
parser.showHelp();
Q_UNREACHABLE();
}
_url = QUrl(filenames[0]);
if (_url.scheme() != "atp") {
qDebug() << "url should start with atp:";
parser.showHelp();
Q_UNREACHABLE();
}
if (filenames.size() == 2) {
_localOutputFile = filenames[1];
}
QString domainServerAddress = "127.0.0.1:40103";
if (parser.isSet(domainAddressOption)) {
domainServerAddress = parser.value(domainAddressOption);
}
if (_verbose) {
qDebug() << "domain-server address is" << domainServerAddress;
}
int listenPort = INVALID_PORT;
if (parser.isSet(listenPortOption)) {
listenPort = parser.value(listenPortOption).toInt();
}
Setting::init();
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
DependencyManager::set<AccountManager>([&]{ return QString("Mozilla/5.0 (HighFidelityATPGet)"); });
DependencyManager::set<AddressManager>();
DependencyManager::set<NodeList>(NodeType::Agent, listenPort);
auto nodeList = DependencyManager::get<NodeList>();
nodeList->startThread();
// setup a timer for domain-server check ins
QTimer* domainCheckInTimer = new QTimer(nodeList.data());
connect(domainCheckInTimer, &QTimer::timeout, nodeList.data(), &NodeList::sendDomainServerCheckIn);
domainCheckInTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS);
const DomainHandler& domainHandler = nodeList->getDomainHandler();
connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&)));
// connect(&domainHandler, SIGNAL(resetting()), SLOT(resettingDomain()));
// connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails()));
connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &ATPGetApp::domainConnectionRefused);
connect(nodeList.data(), &NodeList::nodeAdded, this, &ATPGetApp::nodeAdded);
connect(nodeList.data(), &NodeList::nodeKilled, this, &ATPGetApp::nodeKilled);
connect(nodeList.data(), &NodeList::nodeActivated, this, &ATPGetApp::nodeActivated);
// connect(nodeList.data(), &NodeList::uuidChanged, getMyAvatar(), &MyAvatar::setSessionUUID);
// connect(nodeList.data(), &NodeList::uuidChanged, this, &ATPGetApp::setSessionUUID);
connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &ATPGetApp::notifyPacketVersionMismatch);
nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer
<< NodeType::EntityServer << NodeType::AssetServer << NodeType::MessagesMixer);
DependencyManager::get<AddressManager>()->handleLookupString(domainServerAddress, false);
auto assetClient = DependencyManager::set<AssetClient>();
assetClient->init();
QTimer* doTimer = new QTimer(this);
doTimer->setSingleShot(true);
connect(doTimer, &QTimer::timeout, this, &ATPGetApp::timedOut);
doTimer->start(4000);
}
ATPGetApp::~ATPGetApp() {
}
void ATPGetApp::domainConnectionRefused(const QString& reasonMessage, int reasonCodeInt, const QString& extraInfo) {
qDebug() << "domainConnectionRefused";
}
void ATPGetApp::domainChanged(const QString& domainHostname) {
if (_verbose) {
qDebug() << "domainChanged";
}
}
void ATPGetApp::nodeAdded(SharedNodePointer node) {
if (_verbose) {
qDebug() << "node added: " << node->getType();
}
}
void ATPGetApp::nodeActivated(SharedNodePointer node) {
if (node->getType() == NodeType::AssetServer) {
lookup();
}
}
void ATPGetApp::nodeKilled(SharedNodePointer node) {
qDebug() << "nodeKilled";
}
void ATPGetApp::timedOut() {
finish(1);
}
void ATPGetApp::notifyPacketVersionMismatch() {
if (_verbose) {
qDebug() << "packet version mismatch";
}
finish(1);
}
void ATPGetApp::lookup() {
auto path = _url.path();
qDebug() << "path is " << path;
auto request = DependencyManager::get<AssetClient>()->createGetMappingRequest(path);
QObject::connect(request, &GetMappingRequest::finished, this, [=](GetMappingRequest* request) mutable {
auto result = request->getError();
if (result == GetMappingRequest::NotFound) {
qDebug() << "not found";
} else if (result == GetMappingRequest::NoError) {
qDebug() << "found, hash is " << request->getHash();
download(request->getHash());
} else {
qDebug() << "error -- " << request->getError() << " -- " << request->getErrorString();
}
request->deleteLater();
});
request->start();
}
void ATPGetApp::download(AssetHash hash) {
auto assetClient = DependencyManager::get<AssetClient>();
auto assetRequest = new AssetRequest(hash);
connect(assetRequest, &AssetRequest::finished, this, [this](AssetRequest* request) mutable {
Q_ASSERT(request->getState() == AssetRequest::Finished);
if (request->getError() == AssetRequest::Error::NoError) {
QString data = QString::fromUtf8(request->getData());
if (_localOutputFile == "") {
QTextStream cout(stdout);
cout << data;
} else {
QFile outputHandle(_localOutputFile);
if (outputHandle.open(QIODevice::ReadWrite)) {
QTextStream stream( &outputHandle );
stream << data;
} else {
qDebug() << "couldn't open output file:" << _localOutputFile;
}
}
}
request->deleteLater();
finish(0);
});
assetRequest->start();
}
void ATPGetApp::finish(int exitCode) {
auto nodeList = DependencyManager::get<NodeList>();
// send the domain a disconnect packet, force stoppage of domain-server check-ins
nodeList->getDomainHandler().disconnect();
nodeList->setIsShuttingDown(true);
// tell the packet receiver we're shutting down, so it can drop packets
nodeList->getPacketReceiver().setShouldDropPackets(true);
// remove the NodeList from the DependencyManager
DependencyManager::destroy<NodeList>();
QCoreApplication::exit(exitCode);
}

View file

@ -354,8 +354,8 @@ void FBXBaker::rewriteAndBakeSceneTextures() {
FbxFileTexture* fileTexture = property.GetSrcObject<FbxFileTexture>(j);
// use QFileInfo to easily split up the existing texture filename into its components
QString fbxFileName { fileTexture->GetFileName() };
QFileInfo textureFileInfo { fbxFileName.replace("\\", "/") };
QString fbxTextureFileName { fileTexture->GetFileName() };
QFileInfo textureFileInfo { fbxTextureFileName.replace("\\", "/") };
// make sure this texture points to something and isn't one we've already re-mapped
if (!textureFileInfo.filePath().isEmpty()
@ -372,6 +372,9 @@ void FBXBaker::rewriteAndBakeSceneTextures() {
qCDebug(model_baking).noquote() << "Re-mapping" << fileTexture->GetFileName()
<< "to" << bakedTextureFilePath;
// figure out the URL to this texture, embedded or external
auto urlToTexture = getTextureURL(textureFileInfo, fileTexture);
// write the new filename into the FBX scene
fileTexture->SetFileName(bakedTextureFilePath.toLocal8Bit());
@ -379,9 +382,6 @@ void FBXBaker::rewriteAndBakeSceneTextures() {
// be right beside the FBX
fileTexture->SetRelativeFileName(bakedTextureFileName.toLocal8Bit().constData());
// figure out the URL to this texture, embedded or external
auto urlToTexture = getTextureURL(textureFileInfo, fileTexture);
if (!_bakingTextures.contains(urlToTexture)) {
// bake this texture asynchronously
bakeTexture(urlToTexture, textureType, _uniqueOutputPath + BAKED_OUTPUT_SUBFOLDER);