mirror of
https://github.com/overte-org/overte.git
synced 2025-08-12 12:34:11 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into orange
This commit is contained in:
commit
653ce89e08
151 changed files with 1365 additions and 922 deletions
|
@ -23,7 +23,6 @@
|
|||
|
||||
#include <EntityEditPacketSender.h>
|
||||
#include <EntityTree.h>
|
||||
#include <EntityTreeHeadlessViewer.h>
|
||||
#include <ScriptEngine.h>
|
||||
#include <ThreadedAssignment.h>
|
||||
|
||||
|
@ -31,6 +30,7 @@
|
|||
|
||||
#include "AudioGate.h"
|
||||
#include "MixedAudioStream.h"
|
||||
#include "entities/EntityTreeHeadlessViewer.h"
|
||||
#include "avatars/ScriptableAvatar.h"
|
||||
|
||||
class Agent : public ThreadedAssignment {
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
#include <SharedUtil.h>
|
||||
#include <Octree.h>
|
||||
#include <OctreePacketData.h>
|
||||
#include <OctreeHeadlessViewer.h>
|
||||
#include <ViewFrustum.h>
|
||||
|
||||
#include "../octree/OctreeHeadlessViewer.h"
|
||||
#include "EntityTree.h"
|
||||
|
||||
class EntitySimulation;
|
|
@ -9,17 +9,14 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <NodeList.h>
|
||||
|
||||
#include "OctreeLogging.h"
|
||||
#include "OctreeHeadlessViewer.h"
|
||||
|
||||
OctreeHeadlessViewer::OctreeHeadlessViewer() : OctreeRenderer() {
|
||||
_viewFrustum.setProjection(glm::perspective(glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES), DEFAULT_ASPECT_RATIO, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP));
|
||||
}
|
||||
#include <NodeList.h>
|
||||
#include <OctreeLogging.h>
|
||||
|
||||
void OctreeHeadlessViewer::init() {
|
||||
OctreeRenderer::init();
|
||||
|
||||
OctreeHeadlessViewer::OctreeHeadlessViewer() {
|
||||
_viewFrustum.setProjection(glm::perspective(glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES), DEFAULT_ASPECT_RATIO, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP));
|
||||
}
|
||||
|
||||
void OctreeHeadlessViewer::queryOctree() {
|
|
@ -12,28 +12,17 @@
|
|||
#ifndef hifi_OctreeHeadlessViewer_h
|
||||
#define hifi_OctreeHeadlessViewer_h
|
||||
|
||||
#include <udt/PacketHeaders.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <ViewFrustum.h>
|
||||
#include <OctreeProcessor.h>
|
||||
#include <JurisdictionListener.h>
|
||||
#include <OctreeQuery.h>
|
||||
|
||||
#include "JurisdictionListener.h"
|
||||
#include "Octree.h"
|
||||
#include "OctreeConstants.h"
|
||||
#include "OctreeQuery.h"
|
||||
#include "OctreeRenderer.h"
|
||||
#include "OctreeSceneStats.h"
|
||||
#include "Octree.h"
|
||||
|
||||
// Generic client side Octree renderer class.
|
||||
class OctreeHeadlessViewer : public OctreeRenderer {
|
||||
class OctreeHeadlessViewer : public OctreeProcessor {
|
||||
Q_OBJECT
|
||||
public:
|
||||
OctreeHeadlessViewer();
|
||||
virtual ~OctreeHeadlessViewer() {};
|
||||
virtual void renderElement(OctreeElementPointer element, RenderArgs* args) override { /* swallow these */ }
|
||||
|
||||
virtual void init() override ;
|
||||
virtual void render(RenderArgs* renderArgs) override { /* swallow these */ }
|
||||
|
||||
void setJurisdictionListener(JurisdictionListener* jurisdictionListener) { _jurisdictionListener = jurisdictionListener; }
|
||||
|
||||
|
@ -71,6 +60,7 @@ private:
|
|||
JurisdictionListener* _jurisdictionListener = nullptr;
|
||||
OctreeQuery _octreeQuery;
|
||||
|
||||
ViewFrustum _viewFrustum;
|
||||
float _voxelSizeScale { DEFAULT_OCTREE_SIZE_SCALE };
|
||||
int _boundaryLevelAdjust { 0 };
|
||||
int _maxPacketsPerSecond { DEFAULT_MAX_OCTREE_PPS };
|
|
@ -19,10 +19,10 @@
|
|||
#include <QtCore/QUuid>
|
||||
|
||||
#include <EntityEditPacketSender.h>
|
||||
#include <EntityTreeHeadlessViewer.h>
|
||||
#include <plugins/CodecPlugin.h>
|
||||
#include <ScriptEngine.h>
|
||||
#include <ThreadedAssignment.h>
|
||||
#include "../entities/EntityTreeHeadlessViewer.h"
|
||||
|
||||
class EntityScriptServer : public ThreadedAssignment {
|
||||
Q_OBJECT
|
||||
|
|
|
@ -7,16 +7,18 @@
|
|||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
macro(LINK_HIFI_LIBRARIES)
|
||||
function(LINK_HIFI_LIBRARIES)
|
||||
|
||||
file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}")
|
||||
|
||||
set(LIBRARIES_TO_LINK ${ARGN})
|
||||
|
||||
foreach(HIFI_LIBRARY ${LIBRARIES_TO_LINK})
|
||||
foreach(HIFI_LIBRARY ${LIBRARIES_TO_LINK})
|
||||
if (NOT TARGET ${HIFI_LIBRARY})
|
||||
add_subdirectory("${RELATIVE_LIBRARY_DIR_PATH}/${HIFI_LIBRARY}" "${RELATIVE_LIBRARY_DIR_PATH}/${HIFI_LIBRARY}")
|
||||
endif ()
|
||||
endforeach()
|
||||
|
||||
foreach(HIFI_LIBRARY ${LIBRARIES_TO_LINK})
|
||||
|
||||
include_directories("${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src")
|
||||
include_directories("${CMAKE_BINARY_DIR}/libraries/${HIFI_LIBRARY}/shaders")
|
||||
|
@ -29,4 +31,4 @@ macro(LINK_HIFI_LIBRARIES)
|
|||
|
||||
setup_memory_debugger()
|
||||
|
||||
endmacro(LINK_HIFI_LIBRARIES)
|
||||
endfunction()
|
||||
|
|
|
@ -147,6 +147,7 @@
|
|||
{
|
||||
"name": "security",
|
||||
"label": "Security",
|
||||
"restart": false,
|
||||
"settings": [
|
||||
{
|
||||
"name": "http_username",
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</ul>
|
||||
|
||||
<button id="advanced-toggle-button" class="btn btn-info advanced-toggle">Show advanced</button>
|
||||
<button class="btn btn-success save-button">Save and restart</button>
|
||||
<button class="btn btn-success save-button">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -77,7 +77,7 @@
|
|||
</div>
|
||||
|
||||
<div class="col-xs-12 hidden-sm hidden-md hidden-lg">
|
||||
<button class="btn btn-success save-button" id="small-save-button">Save and restart</button>
|
||||
<button class="btn btn-success save-button" id="small-save-button">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1328,6 +1328,18 @@ function makeTableCategoryInput(setting, numVisibleColumns) {
|
|||
return html;
|
||||
}
|
||||
|
||||
function getDescriptionForKey(key) {
|
||||
for (var i in Settings.data.descriptions) {
|
||||
if (Settings.data.descriptions[i].name === key) {
|
||||
return Settings.data.descriptions[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var SAVE_BUTTON_LABEL_SAVE = "Save";
|
||||
var SAVE_BUTTON_LABEL_RESTART = "Save and restart";
|
||||
var reasonsForRestart = [];
|
||||
|
||||
function badgeSidebarForDifferences(changedElement) {
|
||||
// figure out which group this input is in
|
||||
var panelParentID = changedElement.closest('.panel').attr('id');
|
||||
|
@ -1350,13 +1362,24 @@ function badgeSidebarForDifferences(changedElement) {
|
|||
}
|
||||
|
||||
var badgeValue = 0
|
||||
var description = getDescriptionForKey(panelParentID);
|
||||
|
||||
// badge for any settings we have that are not the same or are not present in initialValues
|
||||
for (var setting in panelJSON) {
|
||||
if ((!_.has(initialPanelJSON, setting) && panelJSON[setting] !== "") ||
|
||||
(!_.isEqual(panelJSON[setting], initialPanelJSON[setting])
|
||||
&& (panelJSON[setting] !== "" || _.has(initialPanelJSON, setting)))) {
|
||||
badgeValue += 1
|
||||
badgeValue += 1;
|
||||
|
||||
// add a reason to restart
|
||||
if (description && description.restart != false) {
|
||||
reasonsForRestart.push(setting);
|
||||
}
|
||||
} else {
|
||||
// remove a reason to restart
|
||||
if (description && description.restart != false) {
|
||||
reasonsForRestart = $.grep(reasonsForRestart, function(v) { return v != setting; });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1365,6 +1388,7 @@ function badgeSidebarForDifferences(changedElement) {
|
|||
badgeValue = ""
|
||||
}
|
||||
|
||||
$(".save-button").html(reasonsForRestart.length > 0 ? SAVE_BUTTON_LABEL_RESTART : SAVE_BUTTON_LABEL_SAVE);
|
||||
$("a[href='#" + panelParentID + "'] .badge").html(badgeValue);
|
||||
}
|
||||
|
||||
|
|
|
@ -115,6 +115,7 @@
|
|||
#include <RenderDeferredTask.h>
|
||||
#include <RenderForwardTask.h>
|
||||
#include <RenderViewTask.h>
|
||||
#include <SecondaryCamera.h>
|
||||
#include <ResourceCache.h>
|
||||
#include <ResourceRequest.h>
|
||||
#include <SandboxUtils.h>
|
||||
|
@ -580,7 +581,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
_undoStackScriptingInterface(&_undoStack),
|
||||
_entitySimulation(new PhysicalEntitySimulation()),
|
||||
_physicsEngine(new PhysicsEngine(Vectors::ZERO)),
|
||||
_entityClipboardRenderer(false, this, this),
|
||||
_entityClipboard(new EntityTree()),
|
||||
_lastQueriedTime(usecTimestampNow()),
|
||||
_previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION),
|
||||
|
@ -1874,6 +1874,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<SecondaryCameraRenderTask>("SecondaryCameraFrame", cullFunctor);
|
||||
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, isDeferred);
|
||||
_renderEngine->load();
|
||||
_renderEngine->registerScene(_main3DScene);
|
||||
|
@ -3987,11 +3988,6 @@ void Application::init() {
|
|||
DependencyManager::get<NodeList>()->sendDomainServerCheckIn();
|
||||
|
||||
getEntities()->init();
|
||||
{
|
||||
QMutexLocker viewLocker(&_viewMutex);
|
||||
getEntities()->setViewFrustum(_viewFrustum);
|
||||
}
|
||||
|
||||
getEntities()->setEntityLoadingPriorityFunction([this](const EntityItem& item) {
|
||||
auto dims = item.getDimensions();
|
||||
auto maxSize = glm::compMax(dims);
|
||||
|
@ -4021,13 +4017,6 @@ void Application::init() {
|
|||
// of events related clicking, hovering over, and entering entities
|
||||
getEntities()->connectSignalsToSlots(entityScriptingInterface.data());
|
||||
|
||||
_entityClipboardRenderer.init();
|
||||
{
|
||||
QMutexLocker viewLocker(&_viewMutex);
|
||||
_entityClipboardRenderer.setViewFrustum(_viewFrustum);
|
||||
}
|
||||
_entityClipboardRenderer.setTree(_entityClipboard);
|
||||
|
||||
// Make sure any new sounds are loaded as soon as know about them.
|
||||
connect(tree.get(), &EntityTree::newCollisionSoundURL, this, [this](QUrl newURL, EntityItemID id) {
|
||||
EntityTreePointer tree = getEntities()->getTree();
|
||||
|
@ -5020,9 +5009,6 @@ QRect Application::getDesirableApplicationGeometry() const {
|
|||
return applicationGeometry;
|
||||
}
|
||||
|
||||
// FIXME, preprocessor guard this check to occur only in DEBUG builds
|
||||
static QThread * activeRenderingThread = nullptr;
|
||||
|
||||
PickRay Application::computePickRay(float x, float y) const {
|
||||
vec2 pickPoint { x, y };
|
||||
PickRay result;
|
||||
|
@ -5093,7 +5079,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
|||
auto myAvatar = getMyAvatar();
|
||||
myAvatar->preDisplaySide(renderArgs);
|
||||
|
||||
activeRenderingThread = QThread::currentThread();
|
||||
PROFILE_RANGE(render, __FUNCTION__);
|
||||
PerformanceTimer perfTimer("display");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide()");
|
||||
|
@ -5163,8 +5148,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
|||
// Before the deferred pass, let's try to use the render engine
|
||||
_renderEngine->run();
|
||||
}
|
||||
|
||||
activeRenderingThread = nullptr;
|
||||
}
|
||||
|
||||
void Application::resetSensors(bool andReload) {
|
||||
|
|
|
@ -181,7 +181,6 @@ public:
|
|||
QUndoStack* getUndoStack() { return &_undoStack; }
|
||||
MainWindow* getWindow() const { return _window; }
|
||||
EntityTreePointer getEntityClipboard() const { return _entityClipboard; }
|
||||
EntityTreeRenderer* getEntityClipboardRenderer() { return &_entityClipboardRenderer; }
|
||||
EntityEditPacketSender* getEntityEditPacketSender() { return &_entityEditSender; }
|
||||
|
||||
ivec2 getMouse() const;
|
||||
|
@ -532,7 +531,6 @@ private:
|
|||
PhysicalEntitySimulationPointer _entitySimulation;
|
||||
PhysicsEnginePointer _physicsEngine;
|
||||
|
||||
EntityTreeRenderer _entityClipboardRenderer;
|
||||
EntityTreePointer _entityClipboard;
|
||||
|
||||
mutable QMutex _viewMutex { QMutex::Recursive };
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <OctreeConstants.h>
|
||||
#include <PIDController.h>
|
||||
#include <SimpleMovingAverage.h>
|
||||
#include <render/Args.h>
|
||||
|
||||
const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 20.0;
|
||||
const float DEFAULT_HMD_LOD_DOWN_FPS = 20.0;
|
||||
|
@ -45,7 +46,6 @@ const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE;
|
|||
// This controls how low the auto-adjust LOD will go. We want a minimum vision of ~20:500 or 0.04 of default
|
||||
const float ADJUST_LOD_MIN_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE * 0.04f;
|
||||
|
||||
class RenderArgs;
|
||||
class AABox;
|
||||
|
||||
class LODManager : public QObject, public Dependency {
|
||||
|
|
125
interface/src/SecondaryCamera.cpp
Normal file
125
interface/src/SecondaryCamera.cpp
Normal file
|
@ -0,0 +1,125 @@
|
|||
//
|
||||
// SecondaryCamera.cpp
|
||||
// interface/src
|
||||
//
|
||||
// Created by Samuel Gateau, Howard Stearns, and Zach Fox on 2017-06-08.
|
||||
// Copyright 2013 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 "SecondaryCamera.h"
|
||||
#include <TextureCache.h>
|
||||
#include <gpu/Context.h>
|
||||
|
||||
using RenderArgsPointer = std::shared_ptr<RenderArgs>;
|
||||
|
||||
void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) {
|
||||
|
||||
task.addJob<RenderShadowTask>("RenderShadowTask", cullFunctor);
|
||||
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
|
||||
assert(items.canCast<RenderFetchCullSortTask::Output>());
|
||||
if (!isDeferred) {
|
||||
task.addJob<RenderForwardTask>("Forward", items);
|
||||
} else {
|
||||
task.addJob<RenderDeferredTask>("RenderDeferredTask", items);
|
||||
}
|
||||
}
|
||||
|
||||
void SecondaryCameraRenderTaskConfig::resetSize(int width, int height) { // FIXME: Add an arg here for "destinationFramebuffer"
|
||||
bool wasEnabled = isEnabled();
|
||||
setEnabled(false);
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
textureCache->resetSpectatorCameraFramebuffer(width, height); // FIXME: Call the correct reset function based on the "destinationFramebuffer" arg
|
||||
setEnabled(wasEnabled);
|
||||
}
|
||||
|
||||
void SecondaryCameraRenderTaskConfig::resetSizeSpectatorCamera(int width, int height) { // Carefully adjust the framebuffer / texture.
|
||||
resetSize(width, height);
|
||||
}
|
||||
|
||||
class BeginSecondaryCameraFrame { // Changes renderContext for our framebuffer and and view.
|
||||
glm::vec3 _position{};
|
||||
glm::quat _orientation{};
|
||||
float _vFoV{};
|
||||
float _nearClipPlaneDistance{};
|
||||
float _farClipPlaneDistance{};
|
||||
public:
|
||||
using Config = BeginSecondaryCameraFrameConfig;
|
||||
using JobModel = render::Job::ModelO<BeginSecondaryCameraFrame, RenderArgsPointer, Config>;
|
||||
BeginSecondaryCameraFrame() {
|
||||
_cachedArgsPointer = std::make_shared<RenderArgs>(_cachedArgs);
|
||||
}
|
||||
|
||||
void configure(const Config& config) {
|
||||
if (config.enabled || config.alwaysEnabled) {
|
||||
_position = config.position;
|
||||
_orientation = config.orientation;
|
||||
_vFoV = config.vFoV;
|
||||
_nearClipPlaneDistance = config.nearClipPlaneDistance;
|
||||
_farClipPlaneDistance = config.farClipPlaneDistance;
|
||||
}
|
||||
}
|
||||
|
||||
void run(const render::RenderContextPointer& renderContext, RenderArgsPointer& cachedArgs) {
|
||||
auto args = renderContext->args;
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
gpu::FramebufferPointer destFramebuffer;
|
||||
destFramebuffer = textureCache->getSpectatorCameraFramebuffer(); // FIXME: Change the destination based on some unimplemented config var
|
||||
if (destFramebuffer) {
|
||||
_cachedArgsPointer->_blitFramebuffer = args->_blitFramebuffer;
|
||||
_cachedArgsPointer->_viewport = args->_viewport;
|
||||
_cachedArgsPointer->_displayMode = args->_displayMode;
|
||||
_cachedArgsPointer->_renderMode = args->_renderMode;
|
||||
args->_blitFramebuffer = destFramebuffer;
|
||||
args->_viewport = glm::ivec4(0, 0, destFramebuffer->getWidth(), destFramebuffer->getHeight());
|
||||
args->_displayMode = RenderArgs::MONO;
|
||||
args->_renderMode = RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE;
|
||||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
batch.disableContextStereo();
|
||||
});
|
||||
|
||||
auto srcViewFrustum = args->getViewFrustum();
|
||||
srcViewFrustum.setPosition(_position);
|
||||
srcViewFrustum.setOrientation(_orientation);
|
||||
srcViewFrustum.setProjection(glm::perspective(glm::radians(_vFoV), ((float)args->_viewport.z / (float)args->_viewport.w), _nearClipPlaneDistance, _farClipPlaneDistance));
|
||||
// Without calculating the bound planes, the secondary camera will use the same culling frustum as the main camera,
|
||||
// which is not what we want here.
|
||||
srcViewFrustum.calculate();
|
||||
args->pushViewFrustum(srcViewFrustum);
|
||||
cachedArgs = _cachedArgsPointer;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
RenderArgs _cachedArgs;
|
||||
RenderArgsPointer _cachedArgsPointer;
|
||||
};
|
||||
|
||||
class EndSecondaryCameraFrame { // Restores renderContext.
|
||||
public:
|
||||
using JobModel = render::Job::ModelI<EndSecondaryCameraFrame, RenderArgsPointer>;
|
||||
|
||||
void run(const render::RenderContextPointer& renderContext, const RenderArgsPointer& cachedArgs) {
|
||||
auto args = renderContext->args;
|
||||
args->_blitFramebuffer = cachedArgs->_blitFramebuffer;
|
||||
args->_viewport = cachedArgs->_viewport;
|
||||
args->popViewFrustum();
|
||||
args->_displayMode = cachedArgs->_displayMode;
|
||||
args->_renderMode = cachedArgs->_renderMode;
|
||||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
batch.restoreContextStereo();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
void SecondaryCameraRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor) {
|
||||
const auto cachedArg = task.addJob<BeginSecondaryCameraFrame>("BeginSecondaryCamera");
|
||||
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
|
||||
assert(items.canCast<RenderFetchCullSortTask::Output>());
|
||||
task.addJob<RenderDeferredTask>("RenderDeferredTask", items);
|
||||
task.addJob<EndSecondaryCameraFrame>("EndSecondaryCamera", cachedArg);
|
||||
}
|
70
interface/src/SecondaryCamera.h
Normal file
70
interface/src/SecondaryCamera.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
//
|
||||
// SecondaryCamera.h
|
||||
// interface/src
|
||||
//
|
||||
// Created by Samuel Gateau, Howard Stearns, and Zach Fox on 2017-06-08.
|
||||
// Copyright 2013 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_SecondaryCamera_h
|
||||
#define hifi_SecondaryCamera_h
|
||||
|
||||
#include <RenderShadowTask.h>
|
||||
#include <render/RenderFetchCullSortTask.h>
|
||||
#include <RenderDeferredTask.h>
|
||||
#include <RenderForwardTask.h>
|
||||
|
||||
|
||||
class MainRenderTask {
|
||||
public:
|
||||
using JobModel = render::Task::Model<MainRenderTask>;
|
||||
|
||||
MainRenderTask() {}
|
||||
|
||||
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred = true);
|
||||
};
|
||||
|
||||
class BeginSecondaryCameraFrameConfig : public render::Task::Config { // Exposes secondary camera parameters to JavaScript.
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(glm::vec3 position MEMBER position NOTIFY dirty) // of viewpoint to render from
|
||||
Q_PROPERTY(glm::quat orientation MEMBER orientation NOTIFY dirty) // of viewpoint to render from
|
||||
Q_PROPERTY(float vFoV MEMBER vFoV NOTIFY dirty) // Secondary camera's vertical field of view. In degrees.
|
||||
Q_PROPERTY(float nearClipPlaneDistance MEMBER nearClipPlaneDistance NOTIFY dirty) // Secondary camera's near clip plane distance. In meters.
|
||||
Q_PROPERTY(float farClipPlaneDistance MEMBER farClipPlaneDistance NOTIFY dirty) // Secondary camera's far clip plane distance. In meters.
|
||||
public:
|
||||
glm::vec3 position{};
|
||||
glm::quat orientation{};
|
||||
float vFoV{ 45.0f };
|
||||
float nearClipPlaneDistance{ 0.1f };
|
||||
float farClipPlaneDistance{ 100.0f };
|
||||
BeginSecondaryCameraFrameConfig() : render::Task::Config(false) {}
|
||||
signals:
|
||||
void dirty();
|
||||
};
|
||||
|
||||
class SecondaryCameraRenderTaskConfig : public render::Task::Config {
|
||||
Q_OBJECT
|
||||
public:
|
||||
SecondaryCameraRenderTaskConfig() : render::Task::Config(false) {}
|
||||
private:
|
||||
void resetSize(int width, int height);
|
||||
signals:
|
||||
void dirty();
|
||||
public slots:
|
||||
void resetSizeSpectatorCamera(int width, int height);
|
||||
};
|
||||
|
||||
class SecondaryCameraRenderTask {
|
||||
public:
|
||||
using Config = SecondaryCameraRenderTaskConfig;
|
||||
using JobModel = render::Task::Model<SecondaryCameraRenderTask, Config>;
|
||||
SecondaryCameraRenderTask() {}
|
||||
void configure(const Config& config) {}
|
||||
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
#include <DependencyManager.h>
|
||||
#include <gpu/Batch.h>
|
||||
#include <RenderArgs.h>
|
||||
|
||||
|
||||
class AudioScope : public QObject, public Dependency {
|
||||
|
|
|
@ -1881,15 +1881,14 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) {
|
|||
|
||||
const float RENDER_HEAD_CUTOFF_DISTANCE = 0.3f;
|
||||
|
||||
bool MyAvatar::cameraInsideHead() const {
|
||||
const glm::vec3 cameraPosition = qApp->getCamera().getPosition();
|
||||
bool MyAvatar::cameraInsideHead(const glm::vec3& cameraPosition) const {
|
||||
return glm::length(cameraPosition - getHeadPosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getUniformScale());
|
||||
}
|
||||
|
||||
bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const {
|
||||
bool defaultMode = renderArgs->_renderMode == RenderArgs::DEFAULT_RENDER_MODE;
|
||||
bool firstPerson = qApp->getCamera().getMode() == CAMERA_MODE_FIRST_PERSON;
|
||||
bool insideHead = cameraInsideHead();
|
||||
bool insideHead = cameraInsideHead(renderArgs->getViewFrustum().getPosition());
|
||||
return !defaultMode || !firstPerson || !insideHead;
|
||||
}
|
||||
|
||||
|
|
|
@ -615,7 +615,7 @@ private:
|
|||
float scale = 1.0f, bool isSoft = false,
|
||||
bool allowDuplicates = false, bool useSaved = true) override;
|
||||
|
||||
bool cameraInsideHead() const;
|
||||
bool cameraInsideHead(const glm::vec3& cameraPosition) const;
|
||||
|
||||
void updateEyeContactTarget(float deltaTime);
|
||||
|
||||
|
|
|
@ -152,9 +152,13 @@ void MenuScriptingInterface::closeInfoView(const QString& path) {
|
|||
}
|
||||
|
||||
bool MenuScriptingInterface::isInfoViewVisible(const QString& path) {
|
||||
if (QThread::currentThread() == qApp->thread()) {
|
||||
return Menu::getInstance()->isInfoViewVisible(path);
|
||||
}
|
||||
|
||||
bool result;
|
||||
QMetaObject::invokeMethod(Menu::getInstance(), "isInfoViewVisible", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(bool, result), Q_ARG(const QString&, path));
|
||||
Q_RETURN_ARG(bool, result), Q_ARG(const QString&, path));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -284,6 +284,11 @@ void WindowScriptingInterface::copyToClipboard(const QString& text) {
|
|||
QApplication::clipboard()->setText(text);
|
||||
}
|
||||
|
||||
|
||||
bool WindowScriptingInterface::setDisplayTexture(const QString& name) {
|
||||
return qApp->getActiveDisplayPlugin()->setDisplayTexture(name); // Plugins that don't know how, answer false.
|
||||
}
|
||||
|
||||
void WindowScriptingInterface::takeSnapshot(bool notify, bool includeAnimated, float aspectRatio) {
|
||||
qApp->takeSnapshot(notify, includeAnimated, aspectRatio);
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ public slots:
|
|||
void displayAnnouncement(const QString& message);
|
||||
void shareSnapshot(const QString& path, const QUrl& href = QUrl(""));
|
||||
bool isPhysicsEnabled();
|
||||
bool setDisplayTexture(const QString& name);
|
||||
|
||||
int openMessageBox(QString title, QString text, int buttons, int defaultButton);
|
||||
void updateMessageBox(int id, QString title, QString text, int buttons, int defaultButton);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <glm/gtx/vector_angle.hpp>
|
||||
|
||||
#include <render/Args.h>
|
||||
#include <avatar/AvatarManager.h>
|
||||
#include <Application.h>
|
||||
#include <AudioClient.h>
|
||||
|
@ -33,6 +34,7 @@
|
|||
#include "SequenceNumberStats.h"
|
||||
#include "StatTracker.h"
|
||||
|
||||
|
||||
HIFI_QML_DEF(Stats)
|
||||
|
||||
using namespace std;
|
||||
|
@ -454,7 +456,7 @@ void Stats::updateStats(bool force) {
|
|||
}
|
||||
}
|
||||
|
||||
void Stats::setRenderDetails(const RenderDetails& details) {
|
||||
void Stats::setRenderDetails(const render::RenderDetails& details) {
|
||||
STAT_UPDATE(triangles, details._trianglesRendered);
|
||||
STAT_UPDATE(materialSwitches, details._materialSwitches);
|
||||
if (_expanded) {
|
||||
|
|
|
@ -9,10 +9,11 @@
|
|||
#ifndef hifi_Stats_h
|
||||
#define hifi_Stats_h
|
||||
|
||||
#include <QtGui/QVector3D>
|
||||
|
||||
#include <OffscreenQmlElement.h>
|
||||
#include <RenderArgs.h>
|
||||
#include <QVector3D>
|
||||
#include <AudioIOStats.h>
|
||||
#include <render/Args.h>
|
||||
|
||||
#define STATS_PROPERTY(type, name, initialValue) \
|
||||
Q_PROPERTY(type name READ name NOTIFY name##Changed) \
|
||||
|
@ -138,7 +139,7 @@ public:
|
|||
|
||||
Stats(QQuickItem* parent = nullptr);
|
||||
bool includeTimingRecord(const QString& name);
|
||||
void setRenderDetails(const RenderDetails& details);
|
||||
void setRenderDetails(const render::RenderDetails& details);
|
||||
const QString& monospaceFont() {
|
||||
return _monospaceFont;
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ void Image3DOverlay::render(RenderArgs* args) {
|
|||
_geometryId
|
||||
);
|
||||
|
||||
batch->setResourceTexture(0, args->_whiteTexture); // restore default white color after me
|
||||
batch->setResourceTexture(0, nullptr); // restore default white color after me
|
||||
}
|
||||
|
||||
const render::ShapeKey Image3DOverlay::getShapeKey() {
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
//
|
||||
// LocalModelsOverlay.cpp
|
||||
// interface/src/ui/overlays
|
||||
//
|
||||
// Created by Ryan Huffman on 07/08/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "LocalModelsOverlay.h"
|
||||
|
||||
#include <EntityTreeRenderer.h>
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
|
||||
QString const LocalModelsOverlay::TYPE = "localmodels";
|
||||
|
||||
LocalModelsOverlay::LocalModelsOverlay(EntityTreeRenderer* entityTreeRenderer) :
|
||||
Volume3DOverlay(),
|
||||
_entityTreeRenderer(entityTreeRenderer) {
|
||||
}
|
||||
|
||||
LocalModelsOverlay::LocalModelsOverlay(const LocalModelsOverlay* localModelsOverlay) :
|
||||
Volume3DOverlay(localModelsOverlay),
|
||||
_entityTreeRenderer(localModelsOverlay->_entityTreeRenderer)
|
||||
{
|
||||
}
|
||||
|
||||
void LocalModelsOverlay::update(float deltatime) {
|
||||
_entityTreeRenderer->update();
|
||||
}
|
||||
|
||||
void LocalModelsOverlay::render(RenderArgs* args) {
|
||||
if (_visible) {
|
||||
auto batch = args ->_batch;
|
||||
|
||||
Transform transform = Transform();
|
||||
transform.setTranslation(args->getViewFrustum().getPosition() + getPosition());
|
||||
batch->setViewTransform(transform);
|
||||
_entityTreeRenderer->render(args);
|
||||
transform.setTranslation(args->getViewFrustum().getPosition());
|
||||
batch->setViewTransform(transform);
|
||||
}
|
||||
}
|
||||
|
||||
LocalModelsOverlay* LocalModelsOverlay::createClone() const {
|
||||
return new LocalModelsOverlay(this);
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
//
|
||||
// LocalModelsOverlay.h
|
||||
// interface/src/ui/overlays
|
||||
//
|
||||
// Created by Ryan Huffman on 07/08/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_LocalModelsOverlay_h
|
||||
#define hifi_LocalModelsOverlay_h
|
||||
|
||||
#include "Volume3DOverlay.h"
|
||||
|
||||
class EntityTreeRenderer;
|
||||
|
||||
class LocalModelsOverlay : public Volume3DOverlay {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static QString const TYPE;
|
||||
virtual QString getType() const override { return TYPE; }
|
||||
|
||||
LocalModelsOverlay(EntityTreeRenderer* entityTreeRenderer);
|
||||
LocalModelsOverlay(const LocalModelsOverlay* localModelsOverlay);
|
||||
|
||||
virtual void update(float deltatime) override;
|
||||
virtual void render(RenderArgs* args) override;
|
||||
|
||||
virtual LocalModelsOverlay* createClone() const override;
|
||||
|
||||
private:
|
||||
EntityTreeRenderer* _entityTreeRenderer;
|
||||
};
|
||||
|
||||
#endif // hifi_LocalModelsOverlay_h
|
|
@ -26,7 +26,6 @@
|
|||
#include "Shape3DOverlay.h"
|
||||
#include "ImageOverlay.h"
|
||||
#include "Line3DOverlay.h"
|
||||
#include "LocalModelsOverlay.h"
|
||||
#include "ModelOverlay.h"
|
||||
#include "Rectangle3DOverlay.h"
|
||||
#include "Sphere3DOverlay.h"
|
||||
|
@ -171,8 +170,6 @@ OverlayID Overlays::addOverlay(const QString& type, const QVariant& properties)
|
|||
thisOverlay = std::make_shared<Line3DOverlay>();
|
||||
} else if (type == Grid3DOverlay::TYPE) {
|
||||
thisOverlay = std::make_shared<Grid3DOverlay>();
|
||||
} else if (type == LocalModelsOverlay::TYPE) {
|
||||
thisOverlay = std::make_shared<LocalModelsOverlay>(qApp->getEntityClipboardRenderer());
|
||||
} else if (type == ModelOverlay::TYPE) {
|
||||
thisOverlay = std::make_shared<ModelOverlay>();
|
||||
} else if (type == Web3DOverlay::TYPE) {
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "Cube3DOverlay.h"
|
||||
#include "ImageOverlay.h"
|
||||
#include "Line3DOverlay.h"
|
||||
#include "LocalModelsOverlay.h"
|
||||
#include "ModelOverlay.h"
|
||||
#include "Overlays.h"
|
||||
#include "Rectangle3DOverlay.h"
|
||||
|
|
|
@ -318,7 +318,7 @@ void Web3DOverlay::render(RenderArgs* args) {
|
|||
geometryCache->bindOpaqueWebBrowserProgram(batch, _isAA);
|
||||
}
|
||||
geometryCache->renderQuad(batch, halfSize * -1.0f, halfSize, vec2(0), vec2(1), color, _geometryId);
|
||||
batch.setResourceTexture(0, args->_whiteTexture); // restore default white color after me
|
||||
batch.setResourceTexture(0, nullptr); // restore default white color after me
|
||||
}
|
||||
|
||||
const render::ShapeKey Web3DOverlay::getShapeKey() {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
set(TARGET_NAME animation)
|
||||
setup_hifi_library(Network Script)
|
||||
link_hifi_libraries(shared model fbx)
|
||||
include_hifi_library_headers(networking)
|
||||
include_hifi_library_headers(gpu)
|
||||
|
||||
target_nsight()
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
set(TARGET_NAME audio-client)
|
||||
setup_hifi_library(Network Multimedia)
|
||||
link_hifi_libraries(audio plugins)
|
||||
include_hifi_library_headers(shared)
|
||||
include_hifi_library_headers(networking)
|
||||
|
||||
# append audio includes to our list of includes to bubble
|
||||
target_include_directories(${TARGET_NAME} PUBLIC "${HIFI_LIBRARY_DIR}/audio/src")
|
||||
|
|
|
@ -2,5 +2,17 @@ set(TARGET_NAME avatars-renderer)
|
|||
AUTOSCRIBE_SHADER_LIB(gpu model render render-utils)
|
||||
setup_hifi_library(Widgets Network Script)
|
||||
link_hifi_libraries(shared gpu model animation model-networking script-engine render image render-utils)
|
||||
include_hifi_library_headers(avatars)
|
||||
include_hifi_library_headers(networking)
|
||||
include_hifi_library_headers(fbx)
|
||||
include_hifi_library_headers(recording)
|
||||
include_hifi_library_headers(trackers)
|
||||
include_hifi_library_headers(ktx)
|
||||
include_hifi_library_headers(procedural)
|
||||
include_hifi_library_headers(physics)
|
||||
include_hifi_library_headers(entities-renderer)
|
||||
include_hifi_library_headers(audio)
|
||||
include_hifi_library_headers(entities)
|
||||
include_hifi_library_headers(octree)
|
||||
|
||||
target_bullet()
|
||||
|
|
|
@ -288,6 +288,13 @@ void Avatar::updateAvatarEntities() {
|
|||
properties.setScript(noScript);
|
||||
}
|
||||
|
||||
// When grabbing avatar entities, they are parented to the joint moving them, then when un-grabbed
|
||||
// they go back to the default parent (null uuid). When un-gripped, others saw the entity disappear.
|
||||
// The thinking here is the local position was noticed as changing, but not the parentID (since it is now
|
||||
// back to the default), and the entity flew off somewhere. Marking all changed definitely fixes this,
|
||||
// and seems safe (per Seth).
|
||||
properties.markAllChanged();
|
||||
|
||||
// try to build the entity
|
||||
EntityItemPointer entity = entityTree->findEntityByEntityItemID(EntityItemID(entityID));
|
||||
bool success = true;
|
||||
|
@ -1067,15 +1074,15 @@ void Avatar::setModelURLFinished(bool success) {
|
|||
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 ||
|
||||
_skeletonModel->getResourceDownloadAttempts() > MAX_SKELETON_DOWNLOAD_ATTEMPTS) {
|
||||
qCWarning(avatars_renderer) << "Using default after failing to load Avatar model: " << _skeletonModelURL
|
||||
qCWarning(avatars_renderer) << "Using default after failing to load Avatar model: " << _skeletonModelURL
|
||||
<< "after" << _skeletonModel->getResourceDownloadAttempts() << "attempts.";
|
||||
// call _skeletonModel.setURL, but leave our copy of _skeletonModelURL alone. This is so that
|
||||
// we don't redo this every time we receive an identity packet from the avatar with the bad url.
|
||||
QMetaObject::invokeMethod(_skeletonModel.get(), "setURL",
|
||||
Qt::QueuedConnection, Q_ARG(QUrl, AvatarData::defaultFullAvatarModelUrl()));
|
||||
} else {
|
||||
qCWarning(avatars_renderer) << "Avatar model: " << _skeletonModelURL
|
||||
<< "failed to load... attempts:" << _skeletonModel->getResourceDownloadAttempts()
|
||||
qCWarning(avatars_renderer) << "Avatar model: " << _skeletonModelURL
|
||||
<< "failed to load... attempts:" << _skeletonModel->getResourceDownloadAttempts()
|
||||
<< "out of:" << MAX_SKELETON_DOWNLOAD_ATTEMPTS;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ setup_hifi_library(Script Qml)
|
|||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
link_hifi_libraries(shared)
|
||||
include_hifi_library_headers(networking)
|
||||
|
||||
GroupSources("src/controllers")
|
||||
|
||||
|
|
|
@ -2,6 +2,14 @@ set(TARGET_NAME display-plugins)
|
|||
AUTOSCRIBE_SHADER_LIB(gpu display-plugins)
|
||||
setup_hifi_library(OpenGL)
|
||||
link_hifi_libraries(shared plugins ui-plugins gl gpu-gl ui render-utils)
|
||||
include_hifi_library_headers(gpu)
|
||||
include_hifi_library_headers(model-networking)
|
||||
include_hifi_library_headers(networking)
|
||||
include_hifi_library_headers(model)
|
||||
include_hifi_library_headers(fbx)
|
||||
include_hifi_library_headers(image)
|
||||
include_hifi_library_headers(ktx)
|
||||
include_hifi_library_headers(render)
|
||||
|
||||
target_opengl()
|
||||
|
||||
|
|
|
@ -496,6 +496,17 @@ void OpenGLDisplayPlugin::submitFrame(const gpu::FramePointer& newFrame) {
|
|||
_newFrameQueue.push(newFrame);
|
||||
});
|
||||
}
|
||||
void OpenGLDisplayPlugin::renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer texture, glm::ivec4 viewport, const glm::ivec4 scissor) {
|
||||
batch.enableStereo(false);
|
||||
batch.resetViewTransform();
|
||||
batch.setFramebuffer(gpu::FramebufferPointer());
|
||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, vec4(0));
|
||||
batch.setStateScissorRect(scissor);
|
||||
batch.setViewportTransform(viewport);
|
||||
batch.setResourceTexture(0, texture);
|
||||
batch.setPipeline(_presentPipeline);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::updateFrameData() {
|
||||
PROFILE_RANGE(render, __FUNCTION__)
|
||||
|
@ -605,14 +616,11 @@ void OpenGLDisplayPlugin::compositeLayers() {
|
|||
|
||||
void OpenGLDisplayPlugin::internalPresent() {
|
||||
render([&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.resetViewTransform();
|
||||
batch.setFramebuffer(gpu::FramebufferPointer());
|
||||
batch.setViewportTransform(ivec4(uvec2(0), getSurfacePixels()));
|
||||
batch.setResourceTexture(0, _compositeFramebuffer->getRenderBuffer(0));
|
||||
batch.setPipeline(_presentPipeline);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
// Note: _displayTexture must currently be the same size as the display.
|
||||
uvec2 dims = _displayTexture ? uvec2(_displayTexture->getDimensions()) : getSurfacePixels();
|
||||
auto viewport = ivec4(uvec2(0), dims);
|
||||
renderFromTexture(batch, _displayTexture ? _displayTexture : _compositeFramebuffer->getRenderBuffer(0), viewport, viewport);
|
||||
});
|
||||
swapBuffers();
|
||||
_presentRate.increment();
|
||||
}
|
||||
|
@ -694,6 +702,22 @@ void OpenGLDisplayPlugin::withMainThreadContext(std::function<void()> f) const {
|
|||
_container->makeRenderingContextCurrent();
|
||||
}
|
||||
|
||||
bool OpenGLDisplayPlugin::setDisplayTexture(const QString& name) {
|
||||
// Note: it is the caller's responsibility to keep the network texture in cache.
|
||||
if (name.isEmpty()) {
|
||||
_displayTexture.reset();
|
||||
onDisplayTextureReset();
|
||||
return true;
|
||||
}
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
auto displayNetworkTexture = textureCache->getTexture(name);
|
||||
if (!displayNetworkTexture) {
|
||||
return false;
|
||||
}
|
||||
_displayTexture = displayNetworkTexture->getGPUTexture();
|
||||
return !!_displayTexture;
|
||||
}
|
||||
|
||||
QImage OpenGLDisplayPlugin::getScreenshot(float aspectRatio) const {
|
||||
auto size = _compositeFramebuffer->getSize();
|
||||
if (isHmd()) {
|
||||
|
|
|
@ -57,6 +57,8 @@ public:
|
|||
return getSurfaceSize();
|
||||
}
|
||||
|
||||
virtual bool setDisplayTexture(const QString& name) override;
|
||||
virtual bool onDisplayTextureReset() { return false; };
|
||||
QImage getScreenshot(float aspectRatio = 0.0f) const override;
|
||||
|
||||
float presentRate() const override;
|
||||
|
@ -109,6 +111,7 @@ protected:
|
|||
// Plugin specific functionality to send the composed scene to the output window or device
|
||||
virtual void internalPresent();
|
||||
|
||||
void renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer texture, glm::ivec4 viewport, const glm::ivec4 scissor);
|
||||
virtual void updateFrameData();
|
||||
|
||||
void withMainThreadContext(std::function<void()> f) const;
|
||||
|
@ -134,6 +137,7 @@ protected:
|
|||
gpu::PipelinePointer _simplePipeline;
|
||||
gpu::PipelinePointer _presentPipeline;
|
||||
gpu::PipelinePointer _cursorPipeline;
|
||||
gpu::TexturePointer _displayTexture{};
|
||||
float _compositeOverlayAlpha { 1.0f };
|
||||
|
||||
struct CursorData {
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include <QtCore/QProcessEnvironment>
|
||||
|
||||
#include <ViewFrustum.h>
|
||||
#include <controllers/Pose.h>
|
||||
#include <gpu/Frame.h>
|
||||
|
||||
const QString DebugHmdDisplayPlugin::NAME("HMD Simulator");
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <gpu/StandardShaderLib.h>
|
||||
#include <gpu/gl/GLBackend.h>
|
||||
|
||||
#include <TextureCache.h>
|
||||
#include <PathUtils.h>
|
||||
|
||||
#include "../Logging.h"
|
||||
|
@ -211,7 +212,15 @@ void HmdDisplayPlugin::internalPresent() {
|
|||
// Composite together the scene, overlay and mouse cursor
|
||||
hmdPresent();
|
||||
|
||||
if (!_disablePreview) {
|
||||
if (_displayTexture) {
|
||||
// Note: _displayTexture must currently be the same size as the display.
|
||||
uvec2 dims = uvec2(_displayTexture->getDimensions());
|
||||
auto viewport = ivec4(uvec2(0), dims);
|
||||
render([&](gpu::Batch& batch) {
|
||||
renderFromTexture(batch, _displayTexture, viewport, viewport);
|
||||
});
|
||||
swapBuffers();
|
||||
} else if (!_disablePreview) {
|
||||
// screen preview mirroring
|
||||
auto sourceSize = _renderTargetSize;
|
||||
if (_monoPreview) {
|
||||
|
@ -278,16 +287,7 @@ void HmdDisplayPlugin::internalPresent() {
|
|||
|
||||
viewport.z *= 2;
|
||||
}
|
||||
|
||||
batch.enableStereo(false);
|
||||
batch.resetViewTransform();
|
||||
batch.setFramebuffer(gpu::FramebufferPointer());
|
||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, vec4(0));
|
||||
batch.setStateScissorRect(scissor); // was viewport
|
||||
batch.setViewportTransform(viewport);
|
||||
batch.setResourceTexture(0, _compositeFramebuffer->getRenderBuffer(0));
|
||||
batch.setPipeline(_presentPipeline);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
renderFromTexture(batch, _compositeFramebuffer->getRenderBuffer(0), viewport, scissor);
|
||||
});
|
||||
swapBuffers();
|
||||
} else if (_clearPreviewFlag) {
|
||||
|
@ -316,15 +316,7 @@ void HmdDisplayPlugin::internalPresent() {
|
|||
auto viewport = getViewportForSourceSize(uvec2(_previewTexture->getDimensions()));
|
||||
|
||||
render([&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.resetViewTransform();
|
||||
batch.setFramebuffer(gpu::FramebufferPointer());
|
||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, vec4(0));
|
||||
batch.setStateScissorRect(viewport);
|
||||
batch.setViewportTransform(viewport);
|
||||
batch.setResourceTexture(0, _previewTexture);
|
||||
batch.setPipeline(_presentPipeline);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
renderFromTexture(batch, _previewTexture, viewport, viewport);
|
||||
});
|
||||
_clearPreviewFlag = false;
|
||||
swapBuffers();
|
||||
|
|
|
@ -46,6 +46,8 @@ public:
|
|||
|
||||
float stutterRate() const override;
|
||||
|
||||
virtual bool onDisplayTextureReset() override { _clearPreviewFlag = true; return true; };
|
||||
|
||||
protected:
|
||||
virtual void hmdPresent() = 0;
|
||||
virtual bool isHmdMounted() const = 0;
|
||||
|
|
|
@ -2,6 +2,16 @@ set(TARGET_NAME entities-renderer)
|
|||
AUTOSCRIBE_SHADER_LIB(gpu model procedural render render-utils)
|
||||
setup_hifi_library(Widgets Network Script)
|
||||
link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils image)
|
||||
include_hifi_library_headers(networking)
|
||||
include_hifi_library_headers(gl)
|
||||
include_hifi_library_headers(ktx)
|
||||
include_hifi_library_headers(octree)
|
||||
include_hifi_library_headers(audio)
|
||||
include_hifi_library_headers(physics)
|
||||
include_hifi_library_headers(animation)
|
||||
include_hifi_library_headers(fbx)
|
||||
include_hifi_library_headers(entities)
|
||||
include_hifi_library_headers(avatars)
|
||||
|
||||
target_bullet()
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "EntityTreeRenderer.h"
|
||||
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
#include <QEventLoop>
|
||||
|
@ -24,7 +26,6 @@
|
|||
#include <SceneScriptingInterface.h>
|
||||
#include <ScriptEngine.h>
|
||||
|
||||
#include "EntityTreeRenderer.h"
|
||||
|
||||
#include "RenderableEntityItem.h"
|
||||
|
||||
|
@ -130,7 +131,12 @@ void EntityTreeRenderer::clear() {
|
|||
if (scene) {
|
||||
render::Transaction transaction;
|
||||
foreach(auto entity, _entitiesInScene) {
|
||||
entity->removeFromScene(entity, scene, transaction);
|
||||
auto renderable = entity->getRenderableInterface();
|
||||
if (!renderable) {
|
||||
qCWarning(entitiesrenderer) << "EntityTreeRenderer::deletingEntity(), trying to remove non-renderable entity";
|
||||
continue;
|
||||
}
|
||||
renderable->removeFromScene(entity, scene, transaction);
|
||||
}
|
||||
scene->enqueueTransaction(transaction);
|
||||
} else {
|
||||
|
@ -141,7 +147,7 @@ void EntityTreeRenderer::clear() {
|
|||
// reset the zone to the default (while we load the next scene)
|
||||
_layeredZones.clear();
|
||||
|
||||
OctreeRenderer::clear();
|
||||
OctreeProcessor::clear();
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::reloadEntityScripts() {
|
||||
|
@ -155,7 +161,7 @@ void EntityTreeRenderer::reloadEntityScripts() {
|
|||
}
|
||||
|
||||
void EntityTreeRenderer::init() {
|
||||
OctreeRenderer::init();
|
||||
OctreeProcessor::init();
|
||||
EntityTreePointer entityTree = std::static_pointer_cast<EntityTree>(_tree);
|
||||
entityTree->setFBXService(this);
|
||||
|
||||
|
@ -181,7 +187,7 @@ void EntityTreeRenderer::shutdown() {
|
|||
}
|
||||
|
||||
void EntityTreeRenderer::setTree(OctreePointer newTree) {
|
||||
OctreeRenderer::setTree(newTree);
|
||||
OctreeProcessor::setTree(newTree);
|
||||
std::static_pointer_cast<EntityTree>(_tree)->setFBXService(this);
|
||||
}
|
||||
|
||||
|
@ -791,24 +797,33 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
|
|||
}
|
||||
|
||||
void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
|
||||
if (!_entitiesInScene.contains(entityID)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_tree && !_shuttingDown && _entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->unloadEntityScript(entityID, true);
|
||||
}
|
||||
|
||||
auto scene = _viewState->getMain3DScene();
|
||||
if (!scene) {
|
||||
qCWarning(entitiesrenderer) << "EntityTreeRenderer::deletingEntity(), Unexpected null scene, possibly during application shutdown";
|
||||
return;
|
||||
}
|
||||
|
||||
auto entity = _entitiesInScene.take(entityID);
|
||||
auto renderable = entity->getRenderableInterface();
|
||||
if (!renderable) {
|
||||
qCWarning(entitiesrenderer) << "EntityTreeRenderer::deletingEntity(), trying to remove non-renderable entity";
|
||||
return;
|
||||
}
|
||||
|
||||
forceRecheckEntities(); // reset our state to force checking our inside/outsideness of entities
|
||||
|
||||
// here's where we remove the entity payload from the scene
|
||||
if (_entitiesInScene.contains(entityID)) {
|
||||
auto entity = _entitiesInScene.take(entityID);
|
||||
render::Transaction transaction;
|
||||
auto scene = _viewState->getMain3DScene();
|
||||
if (scene) {
|
||||
entity->removeFromScene(entity, scene, transaction);
|
||||
scene->enqueueTransaction(transaction);
|
||||
} else {
|
||||
qCWarning(entitiesrenderer) << "EntityTreeRenderer::deletingEntity(), Unexpected null scene, possibly during application shutdown";
|
||||
}
|
||||
}
|
||||
render::Transaction transaction;
|
||||
renderable->removeFromScene(entity, scene, transaction);
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::addingEntity(const EntityItemID& entityID) {
|
||||
|
@ -820,18 +835,25 @@ void EntityTreeRenderer::addingEntity(const EntityItemID& entityID) {
|
|||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::addEntityToScene(EntityItemPointer entity) {
|
||||
void EntityTreeRenderer::addEntityToScene(const EntityItemPointer& entity) {
|
||||
// here's where we add the entity payload to the scene
|
||||
render::Transaction transaction;
|
||||
auto scene = _viewState->getMain3DScene();
|
||||
if (scene) {
|
||||
if (entity->addToScene(entity, scene, transaction)) {
|
||||
_entitiesInScene.insert(entity->getEntityItemID(), entity);
|
||||
}
|
||||
scene->enqueueTransaction(transaction);
|
||||
} else {
|
||||
if (!scene) {
|
||||
qCWarning(entitiesrenderer) << "EntityTreeRenderer::addEntityToScene(), Unexpected null scene, possibly during application shutdown";
|
||||
return;
|
||||
}
|
||||
|
||||
auto renderable = entity->getRenderableInterface();
|
||||
if (!renderable) {
|
||||
qCWarning(entitiesrenderer) << "EntityTreeRenderer::addEntityToScene(), Unexpected non-renderable entity";
|
||||
return;
|
||||
}
|
||||
|
||||
render::Transaction transaction;
|
||||
if (renderable->addToScene(entity, scene, transaction)) {
|
||||
_entitiesInScene.insert(entity->getEntityItemID(), entity);
|
||||
}
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1050,3 +1072,4 @@ bool EntityTreeRenderer::LayeredZones::contains(const LayeredZones& other) {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,9 +20,10 @@
|
|||
#include <EntityTree.h>
|
||||
#include <QMouseEvent>
|
||||
#include <PointerEvent.h>
|
||||
#include <OctreeRenderer.h>
|
||||
#include <ScriptCache.h>
|
||||
#include <TextureCache.h>
|
||||
#include <OctreeProcessor.h>
|
||||
#include <render/Forward.h>
|
||||
|
||||
class AbstractScriptingServicesInterface;
|
||||
class AbstractViewStateInterface;
|
||||
|
@ -38,7 +39,7 @@ using ModelWeakPointer = std::weak_ptr<Model>;
|
|||
using CalculateEntityLoadingPriority = std::function<float(const EntityItem& item)>;
|
||||
|
||||
// Generic client side Octree renderer class.
|
||||
class EntityTreeRenderer : public OctreeRenderer, public EntityItemFBXService, public Dependency {
|
||||
class EntityTreeRenderer : public OctreeProcessor, public EntityItemFBXService, public Dependency {
|
||||
Q_OBJECT
|
||||
public:
|
||||
EntityTreeRenderer(bool wantScripts, AbstractViewStateInterface* viewState,
|
||||
|
@ -144,7 +145,7 @@ protected:
|
|||
private:
|
||||
void resetEntitiesScriptEngine();
|
||||
|
||||
void addEntityToScene(EntityItemPointer entity);
|
||||
void addEntityToScene(const EntityItemPointer& entity);
|
||||
bool findBestZoneAndMaybeContainingEntities(QVector<EntityItemID>* entitiesContainingAvatar = nullptr);
|
||||
|
||||
bool applyLayeredZones();
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace render {
|
|||
template <> void payloadRender(const RenderableEntityItemProxy::Pointer& payload, RenderArgs* args) {
|
||||
if (args) {
|
||||
if (payload && payload->_entity && payload->_entity->getVisible()) {
|
||||
payload->_entity->render(args);
|
||||
payload->_entity->getRenderableInterface()->render(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,13 +34,23 @@ enum class RenderItemStatusIcon {
|
|||
void makeEntityItemStatusGetters(EntityItemPointer entity, render::Item::Status::Getters& statusGetters);
|
||||
|
||||
|
||||
// Renderable entity item interface
|
||||
class RenderableEntityInterface {
|
||||
public:
|
||||
virtual void render(RenderArgs* args) {};
|
||||
virtual bool addToScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) = 0;
|
||||
virtual void removeFromScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) = 0;
|
||||
virtual RenderableEntityInterface* getRenderableInterface() { return nullptr; }
|
||||
};
|
||||
|
||||
class RenderableEntityItemProxy {
|
||||
public:
|
||||
RenderableEntityItemProxy(EntityItemPointer entity, render::ItemID metaID) : _entity(entity), _metaID(metaID) { }
|
||||
RenderableEntityItemProxy(const EntityItemPointer& entity, render::ItemID metaID)
|
||||
: _entity(entity), _metaID(metaID) {}
|
||||
typedef render::Payload<RenderableEntityItemProxy> Payload;
|
||||
typedef Payload::DataPointer Pointer;
|
||||
|
||||
EntityItemPointer _entity;
|
||||
const EntityItemPointer _entity;
|
||||
render::ItemID _metaID;
|
||||
};
|
||||
|
||||
|
@ -51,10 +61,11 @@ namespace render {
|
|||
template <> uint32_t metaFetchMetaSubItems(const RenderableEntityItemProxy::Pointer& payload, ItemIDs& subItems);
|
||||
}
|
||||
|
||||
|
||||
// Mixin class for implementing basic single item rendering
|
||||
class SimpleRenderableEntityItem {
|
||||
class SimplerRenderableEntitySupport : public RenderableEntityInterface {
|
||||
public:
|
||||
bool addToScene(EntityItemPointer self, const render::ScenePointer& scene, render::Transaction& transaction) {
|
||||
bool addToScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) override {
|
||||
_myItem = scene->allocateID();
|
||||
|
||||
auto renderData = std::make_shared<RenderableEntityItemProxy>(self, _myItem);
|
||||
|
@ -69,7 +80,7 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
void removeFromScene(EntityItemPointer self, const render::ScenePointer& scene, render::Transaction& transaction) {
|
||||
void removeFromScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) override {
|
||||
transaction.removeItem(_myItem);
|
||||
render::Item::clearID(_myItem);
|
||||
}
|
||||
|
@ -91,7 +102,6 @@ public:
|
|||
qCWarning(entitiesrenderer) << "SimpleRenderableEntityItem::notifyChanged(), Unexpected null scene, possibly during application shutdown";
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
render::ItemID _myItem { render::Item::INVALID_ITEM_ID };
|
||||
};
|
||||
|
@ -99,20 +109,18 @@ private:
|
|||
|
||||
#define SIMPLE_RENDERABLE() \
|
||||
public: \
|
||||
virtual bool addToScene(EntityItemPointer self, const render::ScenePointer& scene, render::Transaction& transaction) override { return _renderHelper.addToScene(self, scene, transaction); } \
|
||||
virtual void removeFromScene(EntityItemPointer self, const render::ScenePointer& scene, render::Transaction& transaction) override { _renderHelper.removeFromScene(self, scene, transaction); } \
|
||||
virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); _renderHelper.notifyChanged(); } \
|
||||
virtual void dimensionsChanged() override { EntityItem::dimensionsChanged(); _renderHelper.notifyChanged(); } \
|
||||
virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); notifyChanged(); } \
|
||||
virtual void dimensionsChanged() override { EntityItem::dimensionsChanged(); notifyChanged(); } \
|
||||
virtual RenderableEntityInterface* getRenderableInterface() override { return this; } \
|
||||
void checkFading() { \
|
||||
bool transparent = isTransparent(); \
|
||||
if (transparent != _prevIsTransparent) { \
|
||||
_renderHelper.notifyChanged(); \
|
||||
notifyChanged(); \
|
||||
_isFading = false; \
|
||||
_prevIsTransparent = transparent; \
|
||||
} \
|
||||
} \
|
||||
private: \
|
||||
SimpleRenderableEntityItem _renderHelper; \
|
||||
bool _prevIsTransparent { isTransparent() };
|
||||
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ RenderableLightEntityItem::RenderableLightEntityItem(const EntityItemID& entityI
|
|||
{
|
||||
}
|
||||
|
||||
bool RenderableLightEntityItem::addToScene(EntityItemPointer self, const render::ScenePointer& scene, render::Transaction& transaction) {
|
||||
bool RenderableLightEntityItem::addToScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) {
|
||||
_myItem = scene->allocateID();
|
||||
|
||||
auto renderItem = std::make_shared<LightPayload>();
|
||||
|
@ -51,7 +51,7 @@ void RenderableLightEntityItem::somethingChangedNotification() {
|
|||
LightEntityItem::somethingChangedNotification();
|
||||
}
|
||||
|
||||
void RenderableLightEntityItem::removeFromScene(EntityItemPointer self, const render::ScenePointer& scene, render::Transaction& transaction) {
|
||||
void RenderableLightEntityItem::removeFromScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) {
|
||||
transaction.removeItem(_myItem);
|
||||
render::Item::clearID(_myItem);
|
||||
}
|
||||
|
|
|
@ -17,11 +17,13 @@
|
|||
#include "RenderableEntityItem.h"
|
||||
|
||||
|
||||
class RenderableLightEntityItem : public LightEntityItem {
|
||||
class RenderableLightEntityItem : public LightEntityItem, public RenderableEntityInterface {
|
||||
public:
|
||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
RenderableLightEntityItem(const EntityItemID& entityItemID);
|
||||
|
||||
RenderableEntityInterface* getRenderableInterface() override { return this; }
|
||||
|
||||
virtual bool supportsDetailedRayIntersection() const override { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
|
@ -30,10 +32,10 @@ public:
|
|||
|
||||
void updateLightFromEntity(render::Transaction& transaction);
|
||||
|
||||
virtual bool addToScene(EntityItemPointer self, const render::ScenePointer& scene, render::Transaction& transaction) override;
|
||||
virtual bool addToScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) override;
|
||||
|
||||
virtual void somethingChangedNotification() override;
|
||||
virtual void removeFromScene(EntityItemPointer self, const render::ScenePointer& scene, render::Transaction& transaction) override;
|
||||
virtual void removeFromScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) override;
|
||||
|
||||
virtual void locationChanged(bool tellPhysics = true) override;
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "RenderableEntityItem.h"
|
||||
#include <GeometryCache.h>
|
||||
|
||||
class RenderableLineEntityItem : public LineEntityItem {
|
||||
class RenderableLineEntityItem : public LineEntityItem, public SimplerRenderableEntitySupport {
|
||||
public:
|
||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
RenderableLineEntityItem(const EntityItemID& entityItemID) :
|
||||
|
|
|
@ -213,7 +213,7 @@ namespace render {
|
|||
if (args) {
|
||||
if (payload && payload->entity) {
|
||||
PROFILE_RANGE(render_detail, "MetaModelRender");
|
||||
payload->entity->render(args);
|
||||
payload->entity->getRenderableInterface()->render(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -228,7 +228,7 @@ namespace render {
|
|||
}
|
||||
}
|
||||
|
||||
bool RenderableModelEntityItem::addToScene(EntityItemPointer self, const render::ScenePointer& scene,
|
||||
bool RenderableModelEntityItem::addToScene(const EntityItemPointer& self, const render::ScenePointer& scene,
|
||||
render::Transaction& transaction) {
|
||||
_myMetaItem = scene->allocateID();
|
||||
|
||||
|
@ -249,7 +249,7 @@ bool RenderableModelEntityItem::addToScene(EntityItemPointer self, const render:
|
|||
return true;
|
||||
}
|
||||
|
||||
void RenderableModelEntityItem::removeFromScene(EntityItemPointer self, const render::ScenePointer& scene,
|
||||
void RenderableModelEntityItem::removeFromScene(const EntityItemPointer& self, const render::ScenePointer& scene,
|
||||
render::Transaction& transaction) {
|
||||
transaction.removeItem(_myMetaItem);
|
||||
render::Item::clearID(_myMetaItem);
|
||||
|
@ -390,7 +390,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
|||
if (!_model || _needsModelReload) {
|
||||
// TODO: this getModel() appears to be about 3% of model render time. We should optimize
|
||||
PerformanceTimer perfTimer("getModel");
|
||||
auto renderer = qSharedPointerCast<EntityTreeRenderer>(args->_renderer);
|
||||
auto renderer = qSharedPointerCast<EntityTreeRenderer>(args->_renderData);
|
||||
getModel(renderer);
|
||||
|
||||
// Remap textures immediately after loading to avoid flicker
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
class Model;
|
||||
class EntityTreeRenderer;
|
||||
|
||||
class RenderableModelEntityItem : public ModelEntityItem {
|
||||
class RenderableModelEntityItem : public ModelEntityItem, RenderableEntityInterface {
|
||||
public:
|
||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
||||
|
@ -28,6 +28,8 @@ public:
|
|||
|
||||
virtual ~RenderableModelEntityItem();
|
||||
|
||||
RenderableEntityInterface* getRenderableInterface() override { return this; }
|
||||
|
||||
virtual void setDimensions(const glm::vec3& value) override;
|
||||
virtual void setModelURL(const QString& url) override;
|
||||
|
||||
|
@ -40,8 +42,8 @@ public:
|
|||
|
||||
void doInitialModelSimulation();
|
||||
|
||||
virtual bool addToScene(EntityItemPointer self, const render::ScenePointer& scene, render::Transaction& transaction) override;
|
||||
virtual void removeFromScene(EntityItemPointer self, const render::ScenePointer& scene, render::Transaction& transaction) override;
|
||||
virtual bool addToScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) override;
|
||||
virtual void removeFromScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) override;
|
||||
|
||||
|
||||
void updateModelBounds();
|
||||
|
|
|
@ -161,7 +161,7 @@ RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const Ent
|
|||
}
|
||||
}
|
||||
|
||||
bool RenderableParticleEffectEntityItem::addToScene(EntityItemPointer self,
|
||||
bool RenderableParticleEffectEntityItem::addToScene(const EntityItemPointer& self,
|
||||
const render::ScenePointer& scene,
|
||||
render::Transaction& transaction) {
|
||||
_scene = scene;
|
||||
|
@ -176,7 +176,7 @@ bool RenderableParticleEffectEntityItem::addToScene(EntityItemPointer self,
|
|||
return true;
|
||||
}
|
||||
|
||||
void RenderableParticleEffectEntityItem::removeFromScene(EntityItemPointer self,
|
||||
void RenderableParticleEffectEntityItem::removeFromScene(const EntityItemPointer& self,
|
||||
const render::ScenePointer& scene,
|
||||
render::Transaction& transaction) {
|
||||
transaction.removeItem(_renderItemId);
|
||||
|
|
|
@ -15,18 +15,20 @@
|
|||
#include <TextureCache.h>
|
||||
#include "RenderableEntityItem.h"
|
||||
|
||||
class RenderableParticleEffectEntityItem : public ParticleEffectEntityItem {
|
||||
class RenderableParticleEffectEntityItem : public ParticleEffectEntityItem, public RenderableEntityInterface {
|
||||
friend class ParticlePayloadData;
|
||||
public:
|
||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
RenderableParticleEffectEntityItem(const EntityItemID& entityItemID);
|
||||
|
||||
RenderableEntityInterface* getRenderableInterface() override { return this; }
|
||||
|
||||
virtual void update(const quint64& now) override;
|
||||
|
||||
void updateRenderItem();
|
||||
|
||||
virtual bool addToScene(EntityItemPointer self, const render::ScenePointer& scene, render::Transaction& transaction) override;
|
||||
virtual void removeFromScene(EntityItemPointer self, const render::ScenePointer& scene, render::Transaction& transaction) override;
|
||||
virtual bool addToScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) override;
|
||||
virtual void removeFromScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) override;
|
||||
|
||||
protected:
|
||||
virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); notifyBoundChanged(); }
|
||||
|
|
|
@ -206,7 +206,7 @@ void RenderablePolyLineEntityItem::render(RenderArgs* args) {
|
|||
if (_texture->isLoaded()) {
|
||||
batch.setResourceTexture(PAINTSTROKE_TEXTURE_SLOT, _texture->getGPUTexture());
|
||||
} else {
|
||||
batch.setResourceTexture(PAINTSTROKE_TEXTURE_SLOT, args->_whiteTexture);
|
||||
batch.setResourceTexture(PAINTSTROKE_TEXTURE_SLOT, nullptr);
|
||||
}
|
||||
|
||||
batch.setInputFormat(_format);
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include <QReadWriteLock>
|
||||
|
||||
|
||||
class RenderablePolyLineEntityItem : public PolyLineEntityItem {
|
||||
class RenderablePolyLineEntityItem : public PolyLineEntityItem, public SimplerRenderableEntitySupport {
|
||||
public:
|
||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
static void createPipeline();
|
||||
|
|
|
@ -820,7 +820,7 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
|||
batch.drawIndexed(gpu::TRIANGLES, (gpu::uint32)mesh->getNumIndices(), 0);
|
||||
}
|
||||
|
||||
bool RenderablePolyVoxEntityItem::addToScene(EntityItemPointer self,
|
||||
bool RenderablePolyVoxEntityItem::addToScene(const EntityItemPointer& self,
|
||||
const render::ScenePointer& scene,
|
||||
render::Transaction& transaction) {
|
||||
_myItem = scene->allocateID();
|
||||
|
@ -838,7 +838,7 @@ bool RenderablePolyVoxEntityItem::addToScene(EntityItemPointer self,
|
|||
return true;
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::removeFromScene(EntityItemPointer self,
|
||||
void RenderablePolyVoxEntityItem::removeFromScene(const EntityItemPointer& self,
|
||||
const render::ScenePointer& scene,
|
||||
render::Transaction& transaction) {
|
||||
transaction.removeItem(_myItem);
|
||||
|
@ -865,7 +865,7 @@ namespace render {
|
|||
|
||||
template <> void payloadRender(const PolyVoxPayload::Pointer& payload, RenderArgs* args) {
|
||||
if (args && payload && payload->_owner) {
|
||||
payload->_owner->render(args);
|
||||
payload->_owner->getRenderableInterface()->render(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,13 +41,15 @@ namespace render {
|
|||
}
|
||||
|
||||
|
||||
class RenderablePolyVoxEntityItem : public PolyVoxEntityItem {
|
||||
class RenderablePolyVoxEntityItem : public PolyVoxEntityItem, public RenderableEntityInterface {
|
||||
public:
|
||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
RenderablePolyVoxEntityItem(const EntityItemID& entityItemID);
|
||||
|
||||
virtual ~RenderablePolyVoxEntityItem();
|
||||
|
||||
RenderableEntityInterface* getRenderableInterface() override { return this; }
|
||||
|
||||
void initializePolyVox();
|
||||
|
||||
virtual void somethingChangedNotification() override {
|
||||
|
@ -105,10 +107,10 @@ public:
|
|||
virtual void setYTextureURL(const QString& yTextureURL) override;
|
||||
virtual void setZTextureURL(const QString& zTextureURL) override;
|
||||
|
||||
virtual bool addToScene(EntityItemPointer self,
|
||||
virtual bool addToScene(const EntityItemPointer& self,
|
||||
const render::ScenePointer& scene,
|
||||
render::Transaction& transaction) override;
|
||||
virtual void removeFromScene(EntityItemPointer self,
|
||||
virtual void removeFromScene(const EntityItemPointer& self,
|
||||
const render::ScenePointer& scene,
|
||||
render::Transaction& transaction) override;
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include "RenderableEntityItem.h"
|
||||
|
||||
class RenderableShapeEntityItem : public ShapeEntityItem {
|
||||
class RenderableShapeEntityItem : public ShapeEntityItem, private SimplerRenderableEntitySupport {
|
||||
using Pointer = std::shared_ptr<RenderableShapeEntityItem>;
|
||||
static Pointer baseFactory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
public:
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
const int FIXED_FONT_POINT_SIZE = 40;
|
||||
|
||||
class RenderableTextEntityItem : public TextEntityItem {
|
||||
class RenderableTextEntityItem : public TextEntityItem, public SimplerRenderableEntitySupport {
|
||||
public:
|
||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
RenderableTextEntityItem(const EntityItemID& entityItemID) : TextEntityItem(entityItemID) { }
|
||||
|
|
|
@ -198,7 +198,7 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
|
|||
#endif
|
||||
|
||||
if (!_webSurface) {
|
||||
auto renderer = qSharedPointerCast<EntityTreeRenderer>(args->_renderer);
|
||||
auto renderer = qSharedPointerCast<EntityTreeRenderer>(args->_renderData);
|
||||
if (!buildWebSurface(renderer)) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ class EntityTreeRenderer;
|
|||
class RenderableWebEntityItem;
|
||||
|
||||
|
||||
class RenderableWebEntityItem : public WebEntityItem {
|
||||
class RenderableWebEntityItem : public WebEntityItem, SimplerRenderableEntitySupport {
|
||||
public:
|
||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
RenderableWebEntityItem(const EntityItemID& entityItemID);
|
||||
|
|
|
@ -257,7 +257,7 @@ bool RenderableZoneEntityItem::contains(const glm::vec3& point) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool RenderableZoneEntityItem::addToScene(EntityItemPointer self, const render::ScenePointer& scene,
|
||||
bool RenderableZoneEntityItem::addToScene(const EntityItemPointer& self, const render::ScenePointer& scene,
|
||||
render::Transaction& transaction) {
|
||||
_myMetaItem = scene->allocateID();
|
||||
|
||||
|
@ -277,7 +277,7 @@ bool RenderableZoneEntityItem::addToScene(EntityItemPointer self, const render::
|
|||
return true;
|
||||
}
|
||||
|
||||
void RenderableZoneEntityItem::removeFromScene(EntityItemPointer self, const render::ScenePointer& scene,
|
||||
void RenderableZoneEntityItem::removeFromScene(const EntityItemPointer& self, const render::ScenePointer& scene,
|
||||
render::Transaction& transaction) {
|
||||
transaction.removeItem(_myMetaItem);
|
||||
render::Item::clearID(_myMetaItem);
|
||||
|
|
|
@ -14,13 +14,14 @@
|
|||
|
||||
#include <Model.h>
|
||||
#include <ZoneEntityItem.h>
|
||||
#include "RenderableEntityItem.h"
|
||||
|
||||
class NetworkGeometry;
|
||||
class KeyLightPayload;
|
||||
|
||||
class RenderableZoneEntityItemMeta;
|
||||
|
||||
class RenderableZoneEntityItem : public ZoneEntityItem {
|
||||
class RenderableZoneEntityItem : public ZoneEntityItem, public RenderableEntityInterface {
|
||||
public:
|
||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
||||
|
@ -30,6 +31,8 @@ public:
|
|||
_needsInitialSimulation(true)
|
||||
{ }
|
||||
|
||||
RenderableEntityInterface* getRenderableInterface() override { return this; }
|
||||
|
||||
virtual bool setProperties(const EntityItemProperties& properties) override;
|
||||
virtual void somethingChangedNotification() override;
|
||||
|
||||
|
@ -41,8 +44,8 @@ public:
|
|||
virtual void render(RenderArgs* args) override;
|
||||
virtual bool contains(const glm::vec3& point) const override;
|
||||
|
||||
virtual bool addToScene(EntityItemPointer self, const render::ScenePointer& scene, render::Transaction& transaction) override;
|
||||
virtual void removeFromScene(EntityItemPointer self, const render::ScenePointer& scene, render::Transaction& transaction) override;
|
||||
virtual bool addToScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) override;
|
||||
virtual void removeFromScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) override;
|
||||
|
||||
render::ItemID getRenderItemID() const { return _myMetaItem; }
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
set(TARGET_NAME entities)
|
||||
setup_hifi_library(Network Script)
|
||||
link_hifi_libraries(avatars shared audio octree model model-networking fbx networking animation)
|
||||
include_hifi_library_headers(networking)
|
||||
include_hifi_library_headers(gpu)
|
||||
|
||||
target_bullet()
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ AddEntityOperator::AddEntityOperator(EntityTreePointer tree, EntityItemPointer n
|
|||
_newEntityBox = queryCube.clamp((float)(-HALF_TREE_SCALE), (float)HALF_TREE_SCALE);
|
||||
}
|
||||
|
||||
bool AddEntityOperator::preRecursion(OctreeElementPointer element) {
|
||||
bool AddEntityOperator::preRecursion(const OctreeElementPointer& element) {
|
||||
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
|
||||
|
||||
// In Pre-recursion, we're generally deciding whether or not we want to recurse this
|
||||
|
@ -60,7 +60,7 @@ bool AddEntityOperator::preRecursion(OctreeElementPointer element) {
|
|||
return keepSearching; // if we haven't yet found it, keep looking
|
||||
}
|
||||
|
||||
bool AddEntityOperator::postRecursion(OctreeElementPointer element) {
|
||||
bool AddEntityOperator::postRecursion(const OctreeElementPointer& element) {
|
||||
// Post-recursion is the unwinding process. For this operation, while we
|
||||
// unwind we want to mark the path as being dirty if we changed it below.
|
||||
// We might have two paths, one for the old entity and one for the new entity.
|
||||
|
@ -74,7 +74,7 @@ bool AddEntityOperator::postRecursion(OctreeElementPointer element) {
|
|||
return keepSearching; // if we haven't yet found it, keep looking
|
||||
}
|
||||
|
||||
OctreeElementPointer AddEntityOperator::possiblyCreateChildAt(OctreeElementPointer element, int childIndex) {
|
||||
OctreeElementPointer AddEntityOperator::possiblyCreateChildAt(const OctreeElementPointer& element, int childIndex) {
|
||||
// If we're getting called, it's because there was no child element at this index while recursing.
|
||||
// We only care if this happens while still searching for the new entity location.
|
||||
// Check to see if
|
||||
|
|
|
@ -16,9 +16,9 @@ class AddEntityOperator : public RecurseOctreeOperator {
|
|||
public:
|
||||
AddEntityOperator(EntityTreePointer tree, EntityItemPointer newEntity);
|
||||
|
||||
virtual bool preRecursion(OctreeElementPointer element) override;
|
||||
virtual bool postRecursion(OctreeElementPointer element) override;
|
||||
virtual OctreeElementPointer possiblyCreateChildAt(OctreeElementPointer element, int childIndex) override;
|
||||
virtual bool preRecursion(const OctreeElementPointer& element) override;
|
||||
virtual bool postRecursion(const OctreeElementPointer& element) override;
|
||||
virtual OctreeElementPointer possiblyCreateChildAt(const OctreeElementPointer& element, int childIndex) override;
|
||||
private:
|
||||
EntityTreePointer _tree;
|
||||
EntityItemPointer _newEntity;
|
||||
|
|
|
@ -55,7 +55,7 @@ void DeleteEntityOperator::addEntityIDToDeleteList(const EntityItemID& searchEnt
|
|||
|
||||
|
||||
// does this entity tree element contain the old entity
|
||||
bool DeleteEntityOperator::subTreeContainsSomeEntitiesToDelete(OctreeElementPointer element) {
|
||||
bool DeleteEntityOperator::subTreeContainsSomeEntitiesToDelete(const OctreeElementPointer& element) {
|
||||
bool containsEntity = false;
|
||||
|
||||
// If we don't have an old entity, then we don't contain the entity, otherwise
|
||||
|
@ -72,7 +72,7 @@ bool DeleteEntityOperator::subTreeContainsSomeEntitiesToDelete(OctreeElementPoin
|
|||
return containsEntity;
|
||||
}
|
||||
|
||||
bool DeleteEntityOperator::preRecursion(OctreeElementPointer element) {
|
||||
bool DeleteEntityOperator::preRecursion(const OctreeElementPointer& element) {
|
||||
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
|
||||
|
||||
// In Pre-recursion, we're generally deciding whether or not we want to recurse this
|
||||
|
@ -108,7 +108,7 @@ bool DeleteEntityOperator::preRecursion(OctreeElementPointer element) {
|
|||
return keepSearching; // if we haven't yet found it, keep looking
|
||||
}
|
||||
|
||||
bool DeleteEntityOperator::postRecursion(OctreeElementPointer element) {
|
||||
bool DeleteEntityOperator::postRecursion(const OctreeElementPointer& element) {
|
||||
// Post-recursion is the unwinding process. For this operation, while we
|
||||
// unwind we want to mark the path as being dirty if we changed it below.
|
||||
// We might have two paths, one for the old entity and one for the new entity.
|
||||
|
|
|
@ -36,8 +36,8 @@ public:
|
|||
~DeleteEntityOperator();
|
||||
|
||||
void addEntityIDToDeleteList(const EntityItemID& searchEntityID);
|
||||
virtual bool preRecursion(OctreeElementPointer element) override;
|
||||
virtual bool postRecursion(OctreeElementPointer element) override;
|
||||
virtual bool preRecursion(const OctreeElementPointer& element) override;
|
||||
virtual bool postRecursion(const OctreeElementPointer& element) override;
|
||||
|
||||
const RemovedEntities& getEntities() const { return _entitiesToDelete; }
|
||||
private:
|
||||
|
@ -46,7 +46,7 @@ private:
|
|||
quint64 _changeTime;
|
||||
int _foundCount;
|
||||
int _lookingCount;
|
||||
bool subTreeContainsSomeEntitiesToDelete(OctreeElementPointer element);
|
||||
bool subTreeContainsSomeEntitiesToDelete(const OctreeElementPointer& element);
|
||||
};
|
||||
|
||||
#endif // hifi_DeleteEntityOperator_h
|
||||
|
|
|
@ -51,10 +51,6 @@ typedef std::shared_ptr<EntityTreeElement> EntityTreeElementPointer;
|
|||
using EntityTreeElementExtraEncodeDataPointer = std::shared_ptr<EntityTreeElementExtraEncodeData>;
|
||||
|
||||
|
||||
namespace render {
|
||||
class Scene;
|
||||
class Transaction;
|
||||
}
|
||||
|
||||
#define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0;
|
||||
#define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() override { };
|
||||
|
@ -65,6 +61,8 @@ namespace render {
|
|||
|
||||
class MeshProxyList;
|
||||
|
||||
class RenderableEntityInterface;
|
||||
|
||||
|
||||
/// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available
|
||||
/// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate
|
||||
|
@ -83,6 +81,8 @@ public:
|
|||
EntityItem(const EntityItemID& entityItemID);
|
||||
virtual ~EntityItem();
|
||||
|
||||
virtual RenderableEntityInterface* getRenderableInterface() { return nullptr; }
|
||||
|
||||
inline EntityItemPointer getThisPointer() const {
|
||||
return std::static_pointer_cast<EntityItem>(std::const_pointer_cast<SpatiallyNestable>(shared_from_this()));
|
||||
}
|
||||
|
@ -150,13 +150,6 @@ public:
|
|||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
|
||||
bool& somethingChanged)
|
||||
{ somethingChanged = false; return 0; }
|
||||
|
||||
virtual bool addToScene(EntityItemPointer self, const render::ScenePointer& scene,
|
||||
render::Transaction& transaction) { return false; } // by default entity items don't add to scene
|
||||
virtual void removeFromScene(EntityItemPointer self, const render::ScenePointer& scene,
|
||||
render::Transaction& transaction) { } // by default entity items don't add to scene
|
||||
virtual void render(RenderArgs* args) { } // by default entity items don't know how to render
|
||||
|
||||
static int expectedBytes();
|
||||
|
||||
static void adjustEditPacketForClockSkew(QByteArray& buffer, qint64 clockSkew);
|
||||
|
|
|
@ -554,7 +554,7 @@ public:
|
|||
};
|
||||
|
||||
|
||||
bool EntityTree::findNearPointOperation(OctreeElementPointer element, void* extraData) {
|
||||
bool EntityTree::findNearPointOperation(const OctreeElementPointer& element, void* extraData) {
|
||||
FindNearPointArgs* args = static_cast<FindNearPointArgs*>(extraData);
|
||||
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
|
||||
|
||||
|
@ -589,7 +589,7 @@ bool EntityTree::findNearPointOperation(OctreeElementPointer element, void* extr
|
|||
return false;
|
||||
}
|
||||
|
||||
bool findRayIntersectionOp(OctreeElementPointer element, void* extraData) {
|
||||
bool findRayIntersectionOp(const OctreeElementPointer& element, void* extraData) {
|
||||
RayArgs* args = static_cast<RayArgs*>(extraData);
|
||||
bool keepSearching = true;
|
||||
EntityTreeElementPointer entityTreeElementPointer = std::dynamic_pointer_cast<EntityTreeElement>(element);
|
||||
|
@ -625,7 +625,7 @@ bool EntityTree::findRayIntersection(const glm::vec3& origin, const glm::vec3& d
|
|||
}
|
||||
|
||||
|
||||
EntityItemPointer EntityTree::findClosestEntity(glm::vec3 position, float targetRadius) {
|
||||
EntityItemPointer EntityTree::findClosestEntity(const glm::vec3& position, float targetRadius) {
|
||||
FindNearPointArgs args = { position, targetRadius, false, NULL, FLT_MAX };
|
||||
withReadLock([&] {
|
||||
// NOTE: This should use recursion, since this is a spatial operation
|
||||
|
@ -642,7 +642,7 @@ public:
|
|||
};
|
||||
|
||||
|
||||
bool EntityTree::findInSphereOperation(OctreeElementPointer element, void* extraData) {
|
||||
bool EntityTree::findInSphereOperation(const OctreeElementPointer& element, void* extraData) {
|
||||
FindAllNearPointArgs* args = static_cast<FindAllNearPointArgs*>(extraData);
|
||||
glm::vec3 penetration;
|
||||
bool sphereIntersection = element->getAACube().findSpherePenetration(args->position, args->targetRadius, penetration);
|
||||
|
@ -678,7 +678,7 @@ public:
|
|||
QVector<EntityItemPointer> _foundEntities;
|
||||
};
|
||||
|
||||
bool EntityTree::findInCubeOperation(OctreeElementPointer element, void* extraData) {
|
||||
bool EntityTree::findInCubeOperation(const OctreeElementPointer& element, void* extraData) {
|
||||
FindEntitiesInCubeArgs* args = static_cast<FindEntitiesInCubeArgs*>(extraData);
|
||||
if (element->getAACube().touches(args->_cube)) {
|
||||
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
|
||||
|
@ -707,7 +707,7 @@ public:
|
|||
QVector<EntityItemPointer> _foundEntities;
|
||||
};
|
||||
|
||||
bool EntityTree::findInBoxOperation(OctreeElementPointer element, void* extraData) {
|
||||
bool EntityTree::findInBoxOperation(const OctreeElementPointer& element, void* extraData) {
|
||||
FindEntitiesInBoxArgs* args = static_cast<FindEntitiesInBoxArgs*>(extraData);
|
||||
if (element->getAACube().touches(args->_box)) {
|
||||
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
|
||||
|
@ -732,7 +732,7 @@ public:
|
|||
QVector<EntityItemPointer> entities;
|
||||
};
|
||||
|
||||
bool EntityTree::findInFrustumOperation(OctreeElementPointer element, void* extraData) {
|
||||
bool EntityTree::findInFrustumOperation(const OctreeElementPointer& element, void* extraData) {
|
||||
FindInFrustumArgs* args = static_cast<FindInFrustumArgs*>(extraData);
|
||||
if (element->isInView(args->frustum)) {
|
||||
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
|
||||
|
@ -1527,15 +1527,15 @@ void EntityTree::debugDumpMap() {
|
|||
|
||||
class ContentsDimensionOperator : public RecurseOctreeOperator {
|
||||
public:
|
||||
virtual bool preRecursion(OctreeElementPointer element) override;
|
||||
virtual bool postRecursion(OctreeElementPointer element) override { return true; }
|
||||
virtual bool preRecursion(const OctreeElementPointer& element) override;
|
||||
virtual bool postRecursion(const OctreeElementPointer& element) override { return true; }
|
||||
glm::vec3 getDimensions() const { return _contentExtents.size(); }
|
||||
float getLargestDimension() const { return _contentExtents.largestDimension(); }
|
||||
private:
|
||||
Extents _contentExtents;
|
||||
};
|
||||
|
||||
bool ContentsDimensionOperator::preRecursion(OctreeElementPointer element) {
|
||||
bool ContentsDimensionOperator::preRecursion(const OctreeElementPointer& element) {
|
||||
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
|
||||
entityTreeElement->expandExtentsToContents(_contentExtents);
|
||||
return true;
|
||||
|
@ -1555,11 +1555,11 @@ float EntityTree::getContentsLargestDimension() {
|
|||
|
||||
class DebugOperator : public RecurseOctreeOperator {
|
||||
public:
|
||||
virtual bool preRecursion(OctreeElementPointer element) override;
|
||||
virtual bool postRecursion(OctreeElementPointer element) override { return true; }
|
||||
virtual bool preRecursion(const OctreeElementPointer& element) override;
|
||||
virtual bool postRecursion(const OctreeElementPointer& element) override { return true; }
|
||||
};
|
||||
|
||||
bool DebugOperator::preRecursion(OctreeElementPointer element) {
|
||||
bool DebugOperator::preRecursion(const OctreeElementPointer& element) {
|
||||
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
|
||||
qCDebug(entities) << "EntityTreeElement [" << entityTreeElement.get() << "]";
|
||||
entityTreeElement->debugDump();
|
||||
|
@ -1573,11 +1573,11 @@ void EntityTree::dumpTree() {
|
|||
|
||||
class PruneOperator : public RecurseOctreeOperator {
|
||||
public:
|
||||
virtual bool preRecursion(OctreeElementPointer element) override { return true; }
|
||||
virtual bool postRecursion(OctreeElementPointer element) override;
|
||||
virtual bool preRecursion(const OctreeElementPointer& element) override { return true; }
|
||||
virtual bool postRecursion(const OctreeElementPointer& element) override;
|
||||
};
|
||||
|
||||
bool PruneOperator::postRecursion(OctreeElementPointer element) {
|
||||
bool PruneOperator::postRecursion(const OctreeElementPointer& element) {
|
||||
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
|
||||
entityTreeElement->pruneChildren();
|
||||
return true;
|
||||
|
@ -1639,6 +1639,7 @@ QVector<EntityItemID> EntityTree::sendEntities(EntityEditPacketSender* packetSen
|
|||
// If this is called repeatedly (e.g., multiple pastes with the same data), the new elements will clash unless we
|
||||
// use new identifiers. We need to keep a map so that we can map parent identifiers correctly.
|
||||
QHash<EntityItemID, EntityItemID> map;
|
||||
|
||||
args.map = ↦
|
||||
withReadLock([&] {
|
||||
recurseTreeWithOperation(sendEntitiesOperation, &args);
|
||||
|
@ -1692,7 +1693,7 @@ QVector<EntityItemID> EntityTree::sendEntities(EntityEditPacketSender* packetSen
|
|||
return map.values().toVector();
|
||||
}
|
||||
|
||||
bool EntityTree::sendEntitiesOperation(OctreeElementPointer element, void* extraData) {
|
||||
bool EntityTree::sendEntitiesOperation(const OctreeElementPointer& element, void* extraData) {
|
||||
SendEntitiesOperationArgs* args = static_cast<SendEntitiesOperationArgs*>(extraData);
|
||||
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ public:
|
|||
|
||||
/// \param position point of query in world-frame (meters)
|
||||
/// \param targetRadius radius of query (meters)
|
||||
EntityItemPointer findClosestEntity(glm::vec3 position, float targetRadius);
|
||||
EntityItemPointer findClosestEntity(const glm::vec3& position, float targetRadius);
|
||||
EntityItemPointer findEntityByID(const QUuid& id);
|
||||
EntityItemPointer findEntityByEntityItemID(const EntityItemID& entityID);
|
||||
virtual SpatiallyNestablePointer findByID(const QUuid& id) override { return findEntityByID(id); }
|
||||
|
@ -294,12 +294,12 @@ protected:
|
|||
bool updateEntityWithElement(EntityItemPointer entity, const EntityItemProperties& properties,
|
||||
EntityTreeElementPointer containingElement,
|
||||
const SharedNodePointer& senderNode = SharedNodePointer(nullptr));
|
||||
static bool findNearPointOperation(OctreeElementPointer element, void* extraData);
|
||||
static bool findInSphereOperation(OctreeElementPointer element, void* extraData);
|
||||
static bool findInCubeOperation(OctreeElementPointer element, void* extraData);
|
||||
static bool findInBoxOperation(OctreeElementPointer element, void* extraData);
|
||||
static bool findInFrustumOperation(OctreeElementPointer element, void* extraData);
|
||||
static bool sendEntitiesOperation(OctreeElementPointer element, void* extraData);
|
||||
static bool findNearPointOperation(const OctreeElementPointer& element, void* extraData);
|
||||
static bool findInSphereOperation(const OctreeElementPointer& element, void* extraData);
|
||||
static bool findInCubeOperation(const OctreeElementPointer& element, void* extraData);
|
||||
static bool findInBoxOperation(const OctreeElementPointer& element, void* extraData);
|
||||
static bool findInFrustumOperation(const OctreeElementPointer& element, void* extraData);
|
||||
static bool sendEntitiesOperation(const OctreeElementPointer& element, void* extraData);
|
||||
static void bumpTimestamp(EntityItemProperties& properties);
|
||||
|
||||
void notifyNewlyCreatedEntity(const EntityItem& newEntity, const SharedNodePointer& senderNode);
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
#include <QHash>
|
||||
#include <QString>
|
||||
|
||||
#include <OctreeRenderer.h> // for RenderArgs
|
||||
|
||||
#include "EntitiesLogging.h"
|
||||
|
||||
class EntityItem;
|
||||
|
|
|
@ -109,7 +109,7 @@ void MovingEntitiesOperator::addEntityToMoveList(EntityItemPointer entity, const
|
|||
}
|
||||
|
||||
// does this entity tree element contain the old entity
|
||||
bool MovingEntitiesOperator::shouldRecurseSubTree(OctreeElementPointer element) {
|
||||
bool MovingEntitiesOperator::shouldRecurseSubTree(const OctreeElementPointer& element) {
|
||||
bool containsEntity = false;
|
||||
|
||||
// If we don't have an old entity, then we don't contain the entity, otherwise
|
||||
|
@ -141,7 +141,7 @@ bool MovingEntitiesOperator::shouldRecurseSubTree(OctreeElementPointer element)
|
|||
return containsEntity;
|
||||
}
|
||||
|
||||
bool MovingEntitiesOperator::preRecursion(OctreeElementPointer element) {
|
||||
bool MovingEntitiesOperator::preRecursion(const OctreeElementPointer& element) {
|
||||
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
|
||||
|
||||
// In Pre-recursion, we're generally deciding whether or not we want to recurse this
|
||||
|
@ -221,7 +221,7 @@ bool MovingEntitiesOperator::preRecursion(OctreeElementPointer element) {
|
|||
return keepSearching; // if we haven't yet found it, keep looking
|
||||
}
|
||||
|
||||
bool MovingEntitiesOperator::postRecursion(OctreeElementPointer element) {
|
||||
bool MovingEntitiesOperator::postRecursion(const OctreeElementPointer& element) {
|
||||
// Post-recursion is the unwinding process. For this operation, while we
|
||||
// unwind we want to mark the path as being dirty if we changed it below.
|
||||
// We might have two paths, one for the old entity and one for the new entity.
|
||||
|
@ -261,7 +261,7 @@ bool MovingEntitiesOperator::postRecursion(OctreeElementPointer element) {
|
|||
return keepSearching; // if we haven't yet found it, keep looking
|
||||
}
|
||||
|
||||
OctreeElementPointer MovingEntitiesOperator::possiblyCreateChildAt(OctreeElementPointer element, int childIndex) {
|
||||
OctreeElementPointer MovingEntitiesOperator::possiblyCreateChildAt(const OctreeElementPointer& element, int childIndex) {
|
||||
// If we're getting called, it's because there was no child element at this index while recursing.
|
||||
// We only care if this happens while still searching for the new entity locations.
|
||||
if (_foundNewCount < _lookingCount) {
|
||||
|
|
|
@ -38,9 +38,9 @@ public:
|
|||
~MovingEntitiesOperator();
|
||||
|
||||
void addEntityToMoveList(EntityItemPointer entity, const AACube& newCube);
|
||||
virtual bool preRecursion(OctreeElementPointer element) override;
|
||||
virtual bool postRecursion(OctreeElementPointer element) override;
|
||||
virtual OctreeElementPointer possiblyCreateChildAt(OctreeElementPointer element, int childIndex) override;
|
||||
virtual bool preRecursion(const OctreeElementPointer& element) override;
|
||||
virtual bool postRecursion(const OctreeElementPointer& element) override;
|
||||
virtual OctreeElementPointer possiblyCreateChildAt(const OctreeElementPointer& element, int childIndex) override;
|
||||
bool hasMovingEntities() const { return _entitiesToMove.size() > 0; }
|
||||
private:
|
||||
EntityTreePointer _tree;
|
||||
|
@ -49,7 +49,7 @@ private:
|
|||
int _foundOldCount;
|
||||
int _foundNewCount;
|
||||
int _lookingCount;
|
||||
bool shouldRecurseSubTree(OctreeElementPointer element);
|
||||
bool shouldRecurseSubTree(const OctreeElementPointer& element);
|
||||
|
||||
bool _wantDebug;
|
||||
};
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "EntityItemProperties.h"
|
||||
|
||||
RecurseOctreeToMapOperator::RecurseOctreeToMapOperator(QVariantMap& map,
|
||||
OctreeElementPointer top,
|
||||
const OctreeElementPointer& top,
|
||||
QScriptEngine* engine,
|
||||
bool skipDefaultValues,
|
||||
bool skipThoseWithBadParents) :
|
||||
|
@ -34,14 +34,14 @@ RecurseOctreeToMapOperator::RecurseOctreeToMapOperator(QVariantMap& map,
|
|||
}
|
||||
};
|
||||
|
||||
bool RecurseOctreeToMapOperator::preRecursion(OctreeElementPointer element) {
|
||||
bool RecurseOctreeToMapOperator::preRecursion(const OctreeElementPointer& element) {
|
||||
if (element == _top) {
|
||||
_withinTop = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecurseOctreeToMapOperator::postRecursion(OctreeElementPointer element) {
|
||||
bool RecurseOctreeToMapOperator::postRecursion(const OctreeElementPointer& element) {
|
||||
|
||||
EntityItemProperties defaultProperties;
|
||||
|
||||
|
|
|
@ -13,10 +13,10 @@
|
|||
|
||||
class RecurseOctreeToMapOperator : public RecurseOctreeOperator {
|
||||
public:
|
||||
RecurseOctreeToMapOperator(QVariantMap& map, OctreeElementPointer top, QScriptEngine* engine, bool skipDefaultValues,
|
||||
RecurseOctreeToMapOperator(QVariantMap& map, const OctreeElementPointer& top, QScriptEngine* engine, bool skipDefaultValues,
|
||||
bool skipThoseWithBadParents);
|
||||
bool preRecursion(OctreeElementPointer element) override;
|
||||
bool postRecursion(OctreeElementPointer element) override;
|
||||
bool preRecursion(const OctreeElementPointer& element) override;
|
||||
bool postRecursion(const OctreeElementPointer& element) override;
|
||||
private:
|
||||
QVariantMap& _map;
|
||||
OctreeElementPointer _top;
|
||||
|
|
|
@ -77,7 +77,7 @@ UpdateEntityOperator::~UpdateEntityOperator() {
|
|||
|
||||
|
||||
// does this entity tree element contain the old entity
|
||||
bool UpdateEntityOperator::subTreeContainsOldEntity(OctreeElementPointer element) {
|
||||
bool UpdateEntityOperator::subTreeContainsOldEntity(const OctreeElementPointer& element) {
|
||||
|
||||
// We've found cases where the old entity might be placed in an element that is not actually the best fit
|
||||
// so when we're searching the tree for the old element, we use the known cube for the known containing element
|
||||
|
@ -95,7 +95,7 @@ bool UpdateEntityOperator::subTreeContainsOldEntity(OctreeElementPointer element
|
|||
return elementContainsOldBox;
|
||||
}
|
||||
|
||||
bool UpdateEntityOperator::subTreeContainsNewEntity(OctreeElementPointer element) {
|
||||
bool UpdateEntityOperator::subTreeContainsNewEntity(const OctreeElementPointer& element) {
|
||||
bool elementContainsNewBox = element->getAACube().contains(_newEntityBox);
|
||||
|
||||
if (_wantDebug) {
|
||||
|
@ -112,7 +112,7 @@ bool UpdateEntityOperator::subTreeContainsNewEntity(OctreeElementPointer element
|
|||
}
|
||||
|
||||
|
||||
bool UpdateEntityOperator::preRecursion(OctreeElementPointer element) {
|
||||
bool UpdateEntityOperator::preRecursion(const OctreeElementPointer& element) {
|
||||
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
|
||||
|
||||
// In Pre-recursion, we're generally deciding whether or not we want to recurse this
|
||||
|
@ -238,7 +238,7 @@ bool UpdateEntityOperator::preRecursion(OctreeElementPointer element) {
|
|||
return keepSearching; // if we haven't yet found it, keep looking
|
||||
}
|
||||
|
||||
bool UpdateEntityOperator::postRecursion(OctreeElementPointer element) {
|
||||
bool UpdateEntityOperator::postRecursion(const OctreeElementPointer& element) {
|
||||
// Post-recursion is the unwinding process. For this operation, while we
|
||||
// unwind we want to mark the path as being dirty if we changed it below.
|
||||
// We might have two paths, one for the old entity and one for the new entity.
|
||||
|
@ -270,7 +270,7 @@ bool UpdateEntityOperator::postRecursion(OctreeElementPointer element) {
|
|||
return keepSearching; // if we haven't yet found it, keep looking
|
||||
}
|
||||
|
||||
OctreeElementPointer UpdateEntityOperator::possiblyCreateChildAt(OctreeElementPointer element, int childIndex) {
|
||||
OctreeElementPointer UpdateEntityOperator::possiblyCreateChildAt(const OctreeElementPointer& element, int childIndex) {
|
||||
// If we're getting called, it's because there was no child element at this index while recursing.
|
||||
// We only care if this happens while still searching for the new entity location.
|
||||
// Check to see if
|
||||
|
|
|
@ -25,9 +25,9 @@ public:
|
|||
|
||||
~UpdateEntityOperator();
|
||||
|
||||
virtual bool preRecursion(OctreeElementPointer element) override;
|
||||
virtual bool postRecursion(OctreeElementPointer element) override;
|
||||
virtual OctreeElementPointer possiblyCreateChildAt(OctreeElementPointer element, int childIndex) override;
|
||||
virtual bool preRecursion(const OctreeElementPointer& element) override;
|
||||
virtual bool postRecursion(const OctreeElementPointer& element) override;
|
||||
virtual OctreeElementPointer possiblyCreateChildAt(const OctreeElementPointer& element, int childIndex) override;
|
||||
private:
|
||||
EntityTreePointer _tree;
|
||||
EntityItemPointer _existingEntity;
|
||||
|
@ -45,8 +45,8 @@ private:
|
|||
AABox _oldEntityBox; // clamped to domain
|
||||
AABox _newEntityBox; // clamped to domain
|
||||
|
||||
bool subTreeContainsOldEntity(OctreeElementPointer element);
|
||||
bool subTreeContainsNewEntity(OctreeElementPointer element);
|
||||
bool subTreeContainsOldEntity(const OctreeElementPointer& element);
|
||||
bool subTreeContainsNewEntity(const OctreeElementPointer& element);
|
||||
|
||||
bool _wantDebug;
|
||||
};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
set(TARGET_NAME fbx)
|
||||
setup_hifi_library()
|
||||
link_hifi_libraries(shared model networking)
|
||||
include_hifi_library_headers(gpu)
|
||||
|
|
|
@ -115,6 +115,9 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
|||
|
||||
(&::gpu::gl::GLBackend::do_resetStages),
|
||||
|
||||
(&::gpu::gl::GLBackend::do_disableContextStereo),
|
||||
(&::gpu::gl::GLBackend::do_restoreContextStereo),
|
||||
|
||||
(&::gpu::gl::GLBackend::do_runLambda),
|
||||
|
||||
(&::gpu::gl::GLBackend::do_startNamedCall),
|
||||
|
@ -224,6 +227,14 @@ void GLBackend::renderPassTransfer(const Batch& batch) {
|
|||
_transform.preUpdate(_commandIndex, _stereo);
|
||||
break;
|
||||
|
||||
case Batch::COMMAND_disableContextStereo:
|
||||
_stereo._contextDisable = true;
|
||||
break;
|
||||
|
||||
case Batch::COMMAND_restoreContextStereo:
|
||||
_stereo._contextDisable = false;
|
||||
break;
|
||||
|
||||
case Batch::COMMAND_setViewportTransform:
|
||||
case Batch::COMMAND_setViewTransform:
|
||||
case Batch::COMMAND_setProjectionTransform: {
|
||||
|
@ -308,16 +319,16 @@ void GLBackend::render(const Batch& batch) {
|
|||
}
|
||||
|
||||
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
|
||||
if (_stereo._enable) {
|
||||
if (_stereo.isStereo()) {
|
||||
glEnable(GL_CLIP_DISTANCE0);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
PROFILE_RANGE(render_gpu_gl_detail, _stereo._enable ? "Render Stereo" : "Render");
|
||||
PROFILE_RANGE(render_gpu_gl_detail, _stereo.isStereo() ? "Render Stereo" : "Render");
|
||||
renderPassDraw(batch);
|
||||
}
|
||||
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
|
||||
if (_stereo._enable) {
|
||||
if (_stereo.isStereo()) {
|
||||
glDisable(GL_CLIP_DISTANCE0);
|
||||
}
|
||||
#endif
|
||||
|
@ -358,6 +369,15 @@ void GLBackend::do_resetStages(const Batch& batch, size_t paramOffset) {
|
|||
resetStages();
|
||||
}
|
||||
|
||||
|
||||
void GLBackend::do_disableContextStereo(const Batch& batch, size_t paramOffset) {
|
||||
|
||||
}
|
||||
|
||||
void GLBackend::do_restoreContextStereo(const Batch& batch, size_t paramOffset) {
|
||||
|
||||
}
|
||||
|
||||
void GLBackend::do_runLambda(const Batch& batch, size_t paramOffset) {
|
||||
std::function<void()> f = batch._lambdas.get(batch._params[paramOffset]._uint);
|
||||
f();
|
||||
|
|
|
@ -143,6 +143,9 @@ public:
|
|||
// Reset stages
|
||||
virtual void do_resetStages(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
virtual void do_disableContextStereo(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_restoreContextStereo(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
virtual void do_runLambda(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
virtual void do_startNamedCall(const Batch& batch, size_t paramOffset) final;
|
||||
|
|
|
@ -48,7 +48,7 @@ void GLBackend::do_setFramebuffer(const Batch& batch, size_t paramOffset) {
|
|||
}
|
||||
|
||||
void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) {
|
||||
if (_stereo._enable && !_pipeline._stateCache.scissorEnable) {
|
||||
if (_stereo.isStereo() && !_pipeline._stateCache.scissorEnable) {
|
||||
qWarning("Clear without scissor in stereo mode");
|
||||
}
|
||||
|
||||
|
|
|
@ -322,7 +322,7 @@ void GLBackend::do_setStateScissorRect(const Batch& batch, size_t paramOffset) {
|
|||
Vec4i rect;
|
||||
memcpy(&rect, batch.readData(batch._params[paramOffset]._uint), sizeof(Vec4i));
|
||||
|
||||
if (_stereo._enable) {
|
||||
if (_stereo.isStereo()) {
|
||||
rect.z /= 2;
|
||||
if (_stereo._pass) {
|
||||
rect.x += rect.z;
|
||||
|
|
|
@ -37,7 +37,7 @@ void GLBackend::do_setViewportTransform(const Batch& batch, size_t paramOffset)
|
|||
glViewport(vp.x, vp.y, vp.z, vp.w);
|
||||
|
||||
// Where we assign the GL viewport
|
||||
if (_stereo._enable) {
|
||||
if (_stereo.isStereo()) {
|
||||
vp.z /= 2;
|
||||
if (_stereo._pass) {
|
||||
vp.x += vp.z;
|
||||
|
@ -119,7 +119,7 @@ void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const Stereo
|
|||
size_t offset = _cameraUboSize * _cameras.size();
|
||||
_cameraOffsets.push_back(TransformStageState::Pair(commandIndex, offset));
|
||||
|
||||
if (stereo._enable) {
|
||||
if (stereo.isStereo()) {
|
||||
#ifdef GPU_STEREO_CAMERA_BUFFER
|
||||
_cameras.push_back(CameraBufferElement(_camera.getEyeCamera(0, stereo, _view), _camera.getEyeCamera(1, stereo, _view)));
|
||||
#else
|
||||
|
@ -151,7 +151,7 @@ void GLBackend::TransformStageState::update(size_t commandIndex, const StereoSta
|
|||
#ifdef GPU_STEREO_CAMERA_BUFFER
|
||||
bindCurrentCamera(0);
|
||||
#else
|
||||
if (!stereo._enable) {
|
||||
if (!stereo.isStereo()) {
|
||||
bindCurrentCamera(0);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -223,12 +223,21 @@ TransferJob::TransferJob(const GLTexture& parent, uint16_t sourceMip, uint16_t t
|
|||
|
||||
// Buffering can invoke disk IO, so it should be off of the main and render threads
|
||||
_bufferingLambda = [=] {
|
||||
_mipData = _parent._gpuObject.accessStoredMipFace(sourceMip, face)->createView(_transferSize, _transferOffset);
|
||||
auto mipStorage = _parent._gpuObject.accessStoredMipFace(sourceMip, face);
|
||||
if (mipStorage) {
|
||||
_mipData = mipStorage->createView(_transferSize, _transferOffset);
|
||||
} else {
|
||||
qCWarning(gpugllogging) << "Buffering failed because mip could not be retrieved from texture " << _parent._source.c_str() ;
|
||||
}
|
||||
};
|
||||
|
||||
_transferLambda = [=] {
|
||||
_parent.copyMipFaceLinesFromTexture(targetMip, face, transferDimensions, lineOffset, internalFormat, format, type, _mipData->size(), _mipData->readData());
|
||||
_mipData.reset();
|
||||
if (_mipData) {
|
||||
_parent.copyMipFaceLinesFromTexture(targetMip, face, transferDimensions, lineOffset, internalFormat, format, type, _mipData->size(), _mipData->readData());
|
||||
_mipData.reset();
|
||||
} else {
|
||||
qCWarning(gpugllogging) << "Transfer failed because mip could not be retrieved from texture " << _parent._source.c_str();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ GLuint GL45Texture::allocate(const Texture& texture) {
|
|||
glCreateTextures(getGLTextureType(texture), 1, &result);
|
||||
#ifdef DEBUG
|
||||
auto source = texture.source();
|
||||
glObjectLabel(GL_TEXTURE, result, source.length(), source.data());
|
||||
glObjectLabel(GL_TEXTURE, result, (GLsizei)source.length(), source.data());
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -390,6 +390,15 @@ void Batch::resetStages() {
|
|||
ADD_COMMAND(resetStages);
|
||||
}
|
||||
|
||||
|
||||
void Batch::disableContextStereo() {
|
||||
ADD_COMMAND(disableContextStereo);
|
||||
}
|
||||
|
||||
void Batch::restoreContextStereo() {
|
||||
ADD_COMMAND(restoreContextStereo);
|
||||
}
|
||||
|
||||
void Batch::runLambda(std::function<void()> f) {
|
||||
ADD_COMMAND(runLambda);
|
||||
_params.emplace_back(_lambdas.cache(f));
|
||||
|
|
|
@ -217,6 +217,9 @@ public:
|
|||
// Reset the stage caches and states
|
||||
void resetStages();
|
||||
|
||||
void disableContextStereo();
|
||||
void restoreContextStereo();
|
||||
|
||||
// Debugging
|
||||
void pushProfileRange(const char* name);
|
||||
void popProfileRange();
|
||||
|
@ -301,6 +304,9 @@ public:
|
|||
|
||||
COMMAND_resetStages,
|
||||
|
||||
COMMAND_disableContextStereo,
|
||||
COMMAND_restoreContextStereo,
|
||||
|
||||
COMMAND_runLambda,
|
||||
|
||||
COMMAND_startNamedCall,
|
||||
|
@ -467,7 +473,7 @@ public:
|
|||
NamedBatchDataMap _namedData;
|
||||
|
||||
bool _enableStereo{ true };
|
||||
bool _enableSkybox{ false };
|
||||
bool _enableSkybox { false };
|
||||
|
||||
protected:
|
||||
friend class Context;
|
||||
|
|
|
@ -145,7 +145,7 @@ void Context::enableStereo(bool enable) {
|
|||
}
|
||||
|
||||
bool Context::isStereo() {
|
||||
return _stereo._enable;
|
||||
return _stereo.isStereo();
|
||||
}
|
||||
|
||||
void Context::setStereoProjections(const mat4 eyeProjections[2]) {
|
||||
|
|
|
@ -118,7 +118,7 @@ public:
|
|||
|
||||
protected:
|
||||
virtual bool isStereo() {
|
||||
return _stereo._enable;
|
||||
return _stereo.isStereo();
|
||||
}
|
||||
|
||||
void getStereoProjections(mat4* eyeProjections) const {
|
||||
|
|
|
@ -93,7 +93,11 @@ namespace gpu {
|
|||
using TextureViews = std::vector<TextureView>;
|
||||
|
||||
struct StereoState {
|
||||
bool isStereo() const {
|
||||
return _enable && !_contextDisable;
|
||||
}
|
||||
bool _enable{ false };
|
||||
bool _contextDisable { false };
|
||||
bool _skybox{ false };
|
||||
// 0 for left eye, 1 for right eye
|
||||
uint8 _pass{ 0 };
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <QUrl>
|
||||
|
||||
#include <shared/Storage.h>
|
||||
|
||||
#include <shared/FileCache.h>
|
||||
#include "Forward.h"
|
||||
#include "Resource.h"
|
||||
#include "Metric.h"
|
||||
|
@ -311,6 +311,7 @@ public:
|
|||
class KtxStorage : public Storage {
|
||||
public:
|
||||
KtxStorage(const std::string& filename);
|
||||
KtxStorage(const cache::FilePointer& file);
|
||||
PixelsPointer getMipFace(uint16 level, uint8 face = 0) const override;
|
||||
Size getMipFaceSize(uint16 level, uint8 face = 0) const override;
|
||||
bool isMipAvailable(uint16 level, uint8 face = 0) const override;
|
||||
|
@ -328,6 +329,7 @@ public:
|
|||
mutable std::weak_ptr<storage::FileStorage> _cacheFile;
|
||||
|
||||
std::string _filename;
|
||||
cache::FilePointer _cacheEntry;
|
||||
std::atomic<uint8_t> _minMipLevelAvailable;
|
||||
size_t _offsetToMinMipKV;
|
||||
|
||||
|
@ -499,6 +501,7 @@ public:
|
|||
|
||||
void setStorage(std::unique_ptr<Storage>& newStorage);
|
||||
void setKtxBacking(const std::string& filename);
|
||||
void setKtxBacking(const cache::FilePointer& cacheEntry);
|
||||
|
||||
// Usage is a a set of flags providing Semantic about the usage of the Texture.
|
||||
void setUsage(const Usage& usage) { _usage = usage; }
|
||||
|
@ -529,8 +532,9 @@ public:
|
|||
// Serialize a texture into a KTX file
|
||||
static ktx::KTXUniquePointer serialize(const Texture& texture);
|
||||
|
||||
static TexturePointer build(const ktx::KTXDescriptor& descriptor);
|
||||
static TexturePointer unserialize(const std::string& ktxFile);
|
||||
static TexturePointer unserialize(const std::string& ktxFile, const ktx::KTXDescriptor& descriptor);
|
||||
static TexturePointer unserialize(const cache::FilePointer& cacheEntry);
|
||||
|
||||
static bool evalKTXFormat(const Element& mipFormat, const Element& texelFormat, ktx::Header& header);
|
||||
static bool evalTextureFormat(const ktx::Header& header, Element& mipFormat, Element& texelFormat);
|
||||
|
|
|
@ -154,6 +154,10 @@ struct IrradianceKTXPayload {
|
|||
};
|
||||
const std::string IrradianceKTXPayload::KEY{ "hifi.irradianceSH" };
|
||||
|
||||
KtxStorage::KtxStorage(const cache::FilePointer& cacheEntry) : KtxStorage(cacheEntry->getFilepath()) {
|
||||
_cacheEntry = cacheEntry;
|
||||
}
|
||||
|
||||
KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) {
|
||||
{
|
||||
// We are doing a lot of work here just to get descriptor data
|
||||
|
@ -295,20 +299,35 @@ void KtxStorage::assignMipFaceData(uint16 level, uint8 face, const storage::Stor
|
|||
throw std::runtime_error("Invalid call");
|
||||
}
|
||||
|
||||
bool validKtx(const std::string& filename) {
|
||||
ktx::StoragePointer storage { new storage::FileStorage(filename.c_str()) };
|
||||
auto ktxPointer = ktx::KTX::create(storage);
|
||||
if (!ktxPointer) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Texture::setKtxBacking(const std::string& filename) {
|
||||
// Check the KTX file for validity before using it as backing storage
|
||||
{
|
||||
ktx::StoragePointer storage { new storage::FileStorage(filename.c_str()) };
|
||||
auto ktxPointer = ktx::KTX::create(storage);
|
||||
if (!ktxPointer) {
|
||||
return;
|
||||
}
|
||||
if (!validKtx(filename)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto newBacking = std::unique_ptr<Storage>(new KtxStorage(filename));
|
||||
setStorage(newBacking);
|
||||
}
|
||||
|
||||
void Texture::setKtxBacking(const cache::FilePointer& cacheEntry) {
|
||||
// Check the KTX file for validity before using it as backing storage
|
||||
if (!validKtx(cacheEntry->getFilepath())) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto newBacking = std::unique_ptr<Storage>(new KtxStorage(cacheEntry));
|
||||
setStorage(newBacking);
|
||||
}
|
||||
|
||||
|
||||
ktx::KTXUniquePointer Texture::serialize(const Texture& texture) {
|
||||
ktx::Header header;
|
||||
|
@ -442,21 +461,10 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) {
|
|||
return ktxBuffer;
|
||||
}
|
||||
|
||||
TexturePointer Texture::unserialize(const std::string& ktxfile) {
|
||||
std::unique_ptr<ktx::KTX> ktxPointer = ktx::KTX::create(std::make_shared<storage::FileStorage>(ktxfile.c_str()));
|
||||
if (!ktxPointer) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ktx::KTXDescriptor descriptor { ktxPointer->toDescriptor() };
|
||||
return unserialize(ktxfile, ktxPointer->toDescriptor());
|
||||
}
|
||||
|
||||
TexturePointer Texture::unserialize(const std::string& ktxfile, const ktx::KTXDescriptor& descriptor) {
|
||||
const auto& header = descriptor.header;
|
||||
|
||||
TexturePointer Texture::build(const ktx::KTXDescriptor& descriptor) {
|
||||
Format mipFormat = Format::COLOR_BGRA_32;
|
||||
Format texelFormat = Format::COLOR_SRGBA_32;
|
||||
const auto& header = descriptor.header;
|
||||
|
||||
if (!Texture::evalTextureFormat(header, mipFormat, texelFormat)) {
|
||||
return nullptr;
|
||||
|
@ -485,20 +493,19 @@ TexturePointer Texture::unserialize(const std::string& ktxfile, const ktx::KTXDe
|
|||
}
|
||||
|
||||
auto texture = create(gpuktxKeyValue._usageType,
|
||||
type,
|
||||
texelFormat,
|
||||
header.getPixelWidth(),
|
||||
header.getPixelHeight(),
|
||||
header.getPixelDepth(),
|
||||
1, // num Samples
|
||||
header.getNumberOfSlices(),
|
||||
header.getNumberOfLevels(),
|
||||
gpuktxKeyValue._samplerDesc);
|
||||
type,
|
||||
texelFormat,
|
||||
header.getPixelWidth(),
|
||||
header.getPixelHeight(),
|
||||
header.getPixelDepth(),
|
||||
1, // num Samples
|
||||
header.getNumberOfSlices(),
|
||||
header.getNumberOfLevels(),
|
||||
gpuktxKeyValue._samplerDesc);
|
||||
texture->setUsage(gpuktxKeyValue._usage);
|
||||
|
||||
// Assing the mips availables
|
||||
texture->setStoredMipFormat(mipFormat);
|
||||
texture->setKtxBacking(ktxfile);
|
||||
|
||||
IrradianceKTXPayload irradianceKtxKeyValue;
|
||||
if (IrradianceKTXPayload::findInKeyValues(descriptor.keyValues, irradianceKtxKeyValue)) {
|
||||
|
@ -508,6 +515,36 @@ TexturePointer Texture::unserialize(const std::string& ktxfile, const ktx::KTXDe
|
|||
return texture;
|
||||
}
|
||||
|
||||
|
||||
|
||||
TexturePointer Texture::unserialize(const cache::FilePointer& cacheEntry) {
|
||||
std::unique_ptr<ktx::KTX> ktxPointer = ktx::KTX::create(std::make_shared<storage::FileStorage>(cacheEntry->getFilepath().c_str()));
|
||||
if (!ktxPointer) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto texture = build(ktxPointer->toDescriptor());
|
||||
if (texture) {
|
||||
texture->setKtxBacking(cacheEntry);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
TexturePointer Texture::unserialize(const std::string& ktxfile) {
|
||||
std::unique_ptr<ktx::KTX> ktxPointer = ktx::KTX::create(std::make_shared<storage::FileStorage>(ktxfile.c_str()));
|
||||
if (!ktxPointer) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto texture = build(ktxPointer->toDescriptor());
|
||||
if (texture) {
|
||||
texture->setKtxBacking(ktxfile);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
bool Texture::evalKTXFormat(const Element& mipFormat, const Element& texelFormat, ktx::Header& header) {
|
||||
if (texelFormat == Format::COLOR_RGBA_32 && mipFormat == Format::COLOR_BGRA_32) {
|
||||
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::BGRA, ktx::GLInternalFormat::RGBA8, ktx::GLBaseInternalFormat::RGBA);
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
set(TARGET_NAME ktx)
|
||||
setup_hifi_library()
|
||||
link_hifi_libraries()
|
||||
include_hifi_library_headers(shared)
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
using namespace ktx;
|
||||
|
||||
int ktxDescriptorMetaTypeId = qRegisterMetaType<KTXDescriptor*>();
|
||||
|
||||
const Header::Identifier ktx::Header::IDENTIFIER {{
|
||||
0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
|
||||
}};
|
||||
|
|
|
@ -387,4 +387,6 @@ namespace ktx {
|
|||
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(ktx::KTXDescriptor*);
|
||||
|
||||
#endif // hifi_ktx_KTX_h
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
set(TARGET_NAME model-networking)
|
||||
setup_hifi_library()
|
||||
link_hifi_libraries(shared networking model fbx ktx image)
|
||||
|
||||
include_hifi_library_headers(gpu)
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include <QUrl>
|
||||
|
||||
#include <FileCache.h>
|
||||
#include <shared/FileCache.h>
|
||||
|
||||
namespace ktx {
|
||||
class KTX;
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
#include <mutex>
|
||||
|
||||
#include <QtConcurrent/QtConcurrentRun>
|
||||
|
||||
#include <QCryptographicHash>
|
||||
#include <QImageReader>
|
||||
#include <QRunnable>
|
||||
|
@ -50,6 +52,9 @@ Q_LOGGING_CATEGORY(trace_resource_parse_image_ktx, "trace.resource.parse.image.k
|
|||
const std::string TextureCache::KTX_DIRNAME { "ktx_cache" };
|
||||
const std::string TextureCache::KTX_EXT { "ktx" };
|
||||
|
||||
static const QString RESOURCE_SCHEME = "resource";
|
||||
static const QUrl SPECTATOR_CAMERA_FRAME_URL("resource://spectatorCameraFrame");
|
||||
|
||||
static const float SKYBOX_LOAD_PRIORITY { 10.0f }; // Make sure skybox loads first
|
||||
static const float HIGH_MIPS_LOAD_PRIORITY { 9.0f }; // Make sure high mips loads after skybox but before models
|
||||
|
||||
|
@ -180,6 +185,9 @@ ScriptableResource* TextureCache::prefetch(const QUrl& url, int type, int maxNum
|
|||
}
|
||||
|
||||
NetworkTexturePointer TextureCache::getTexture(const QUrl& url, image::TextureUsage::Type type, const QByteArray& content, int maxNumPixels) {
|
||||
if (url.scheme() == RESOURCE_SCHEME) {
|
||||
return getResourceTexture(url);
|
||||
}
|
||||
TextureExtra extra = { type, content, maxNumPixels };
|
||||
return ResourceCache::getResource(url, QUrl(), &extra).staticCast<NetworkTexture>();
|
||||
}
|
||||
|
@ -265,6 +273,18 @@ QSharedPointer<Resource> TextureCache::createResource(const QUrl& url, const QSh
|
|||
return QSharedPointer<Resource>(texture, &Resource::deleter);
|
||||
}
|
||||
|
||||
NetworkTexture::NetworkTexture(const QUrl& url) :
|
||||
Resource(url),
|
||||
_type(),
|
||||
_sourceIsKTX(false),
|
||||
_maxNumPixels(100)
|
||||
{
|
||||
_textureSource = std::make_shared<gpu::TextureSource>();
|
||||
_lowestRequestedMipLevel = 0;
|
||||
_loaded = true;
|
||||
}
|
||||
|
||||
|
||||
NetworkTexture::NetworkTexture(const QUrl& url, image::TextureUsage::Type type, const QByteArray& content, int maxNumPixels) :
|
||||
Resource(url),
|
||||
_type(type),
|
||||
|
@ -303,14 +323,12 @@ void NetworkTexture::setImage(gpu::TexturePointer texture, int originalWidth,
|
|||
_width = texture->getWidth();
|
||||
_height = texture->getHeight();
|
||||
setSize(texture->getStoredSize());
|
||||
finishedLoading(true);
|
||||
} else {
|
||||
// FIXME: If !gpuTexture, we failed to load!
|
||||
_width = _height = 0;
|
||||
qWarning() << "Texture did not load";
|
||||
finishedLoading(false);
|
||||
}
|
||||
|
||||
finishedLoading(true);
|
||||
|
||||
emit networkTextureCreated(qWeakPointerCast<NetworkTexture, Resource> (_self));
|
||||
}
|
||||
|
||||
|
@ -382,8 +400,7 @@ void NetworkTexture::makeRequest() {
|
|||
|
||||
emit loading();
|
||||
|
||||
connect(_ktxHeaderRequest, &ResourceRequest::progress, this, &NetworkTexture::ktxHeaderRequestProgress);
|
||||
connect(_ktxHeaderRequest, &ResourceRequest::finished, this, &NetworkTexture::ktxHeaderRequestFinished);
|
||||
connect(_ktxHeaderRequest, &ResourceRequest::finished, this, &NetworkTexture::ktxInitialDataRequestFinished);
|
||||
|
||||
_bytesReceived = _bytesTotal = _bytes = 0;
|
||||
|
||||
|
@ -407,18 +424,18 @@ void NetworkTexture::makeRequest() {
|
|||
}
|
||||
|
||||
void NetworkTexture::startRequestForNextMipLevel() {
|
||||
if (_lowestKnownPopulatedMip == 0) {
|
||||
qWarning(networking) << "Requesting next mip level but all have been fulfilled: " << _lowestKnownPopulatedMip
|
||||
<< " " << _textureSource->getGPUTexture()->minAvailableMipLevel() << " " << _url;
|
||||
auto self = _self.lock();
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_ktxResourceState == WAITING_FOR_MIP_REQUEST) {
|
||||
auto self = _self.lock();
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
auto texture = _textureSource->getGPUTexture();
|
||||
if (!texture || _ktxResourceState != WAITING_FOR_MIP_REQUEST) {
|
||||
return;
|
||||
}
|
||||
|
||||
_lowestKnownPopulatedMip = texture->minAvailableMipLevel();
|
||||
if (_lowestRequestedMipLevel < _lowestKnownPopulatedMip) {
|
||||
_ktxResourceState = PENDING_MIP_REQUEST;
|
||||
|
||||
init(false);
|
||||
|
@ -453,6 +470,8 @@ void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) {
|
|||
ByteRange range;
|
||||
range.fromInclusive = -HIGH_MIP_MAX_SIZE;
|
||||
_ktxMipRequest->setByteRange(range);
|
||||
|
||||
connect(_ktxMipRequest, &ResourceRequest::finished, this, &NetworkTexture::ktxInitialDataRequestFinished);
|
||||
} else {
|
||||
ByteRange range;
|
||||
range.fromInclusive = ktx::KTX_HEADER_SIZE + _originalKtxDescriptor->header.bytesOfKeyValueData
|
||||
|
@ -460,228 +479,315 @@ void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) {
|
|||
range.toExclusive = ktx::KTX_HEADER_SIZE + _originalKtxDescriptor->header.bytesOfKeyValueData
|
||||
+ _originalKtxDescriptor->images[high + 1]._imageOffset;
|
||||
_ktxMipRequest->setByteRange(range);
|
||||
}
|
||||
|
||||
connect(_ktxMipRequest, &ResourceRequest::progress, this, &NetworkTexture::ktxMipRequestProgress);
|
||||
connect(_ktxMipRequest, &ResourceRequest::finished, this, &NetworkTexture::ktxMipRequestFinished);
|
||||
connect(_ktxMipRequest, &ResourceRequest::finished, this, &NetworkTexture::ktxMipRequestFinished);
|
||||
}
|
||||
|
||||
_ktxMipRequest->send();
|
||||
}
|
||||
|
||||
|
||||
void NetworkTexture::ktxHeaderRequestFinished() {
|
||||
Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA);
|
||||
|
||||
if (!_ktxHeaderRequest) {
|
||||
// This is called when the header or top mips have been loaded
|
||||
void NetworkTexture::ktxInitialDataRequestFinished() {
|
||||
if (!_ktxHeaderRequest || _ktxHeaderRequest->getState() != ResourceRequest::Finished ||
|
||||
!_ktxMipRequest || _ktxMipRequest->getState() != ResourceRequest::Finished) {
|
||||
// Wait for both request to be finished
|
||||
return;
|
||||
}
|
||||
|
||||
_ktxHeaderRequestFinished = true;
|
||||
maybeHandleFinishedInitialLoad();
|
||||
Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA);
|
||||
Q_ASSERT_X(_ktxHeaderRequest && _ktxMipRequest, __FUNCTION__, "Request should not be null while in ktxInitialDataRequestFinished");
|
||||
|
||||
PROFILE_ASYNC_END(resource, "Resource:" + getType(), QString::number(_requestID), {
|
||||
{ "from_cache", _ktxHeaderRequest->loadedFromCache() },
|
||||
{ "size_mb", _bytesTotal / 1000000.0 }
|
||||
});
|
||||
|
||||
PROFILE_RANGE_EX(resource_parse_image, __FUNCTION__, 0xffff0000, 0, { { "url", _url.toString() } });
|
||||
|
||||
setSize(_bytesTotal);
|
||||
|
||||
TextureCache::requestCompleted(_self);
|
||||
|
||||
auto result = _ktxHeaderRequest->getResult();
|
||||
if (result == ResourceRequest::Success) {
|
||||
result = _ktxMipRequest->getResult();
|
||||
}
|
||||
|
||||
if (result == ResourceRequest::Success) {
|
||||
auto extraInfo = _url == _activeUrl ? "" : QString(", %1").arg(_activeUrl.toDisplayString());
|
||||
qCDebug(networking).noquote() << QString("Request finished for %1%2").arg(_url.toDisplayString(), extraInfo);
|
||||
|
||||
_ktxHeaderData = _ktxHeaderRequest->getData();
|
||||
_ktxHighMipData = _ktxMipRequest->getData();
|
||||
handleFinishedInitialLoad();
|
||||
} else {
|
||||
if (handleFailedRequest(result)) {
|
||||
_ktxResourceState = PENDING_INITIAL_LOAD;
|
||||
} else {
|
||||
_ktxResourceState = FAILED_TO_LOAD;
|
||||
}
|
||||
}
|
||||
|
||||
_ktxHeaderRequest->disconnect(this);
|
||||
_ktxHeaderRequest->deleteLater();
|
||||
_ktxHeaderRequest = nullptr;
|
||||
_ktxMipRequest->disconnect(this);
|
||||
_ktxMipRequest->deleteLater();
|
||||
_ktxMipRequest = nullptr;
|
||||
}
|
||||
|
||||
void NetworkTexture::ktxMipRequestFinished() {
|
||||
Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA || _ktxResourceState == REQUESTING_MIP);
|
||||
Q_ASSERT_X(_ktxMipRequest, __FUNCTION__, "Request should not be null while in ktxMipRequestFinished");
|
||||
Q_ASSERT(_ktxResourceState == REQUESTING_MIP);
|
||||
|
||||
if (!_ktxMipRequest) {
|
||||
PROFILE_ASYNC_END(resource, "Resource:" + getType(), QString::number(_requestID), {
|
||||
{ "from_cache", _ktxMipRequest->loadedFromCache() },
|
||||
{ "size_mb", _bytesTotal / 1000000.0 }
|
||||
});
|
||||
|
||||
PROFILE_RANGE_EX(resource_parse_image, __FUNCTION__, 0xffff0000, 0, { { "url", _url.toString() } });
|
||||
|
||||
|
||||
setSize(_bytesTotal);
|
||||
|
||||
if (!_ktxMipRequest || _ktxMipRequest != sender()) {
|
||||
// This can happen in the edge case that a request is timed out, but a `finished` signal is emitted before it is deleted.
|
||||
qWarning(networking) << "Received signal NetworkTexture::ktxMipRequestFinished from ResourceRequest that is not the current"
|
||||
<< " request: " << sender() << ", " << _ktxMipRequest;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_ktxResourceState == LOADING_INITIAL_DATA) {
|
||||
_ktxHighMipRequestFinished = true;
|
||||
maybeHandleFinishedInitialLoad();
|
||||
} else if (_ktxResourceState == REQUESTING_MIP) {
|
||||
Q_ASSERT(_ktxMipLevelRangeInFlight.first != NULL_MIP_LEVEL);
|
||||
TextureCache::requestCompleted(_self);
|
||||
TextureCache::requestCompleted(_self);
|
||||
|
||||
if (_ktxMipRequest->getResult() == ResourceRequest::Success) {
|
||||
auto result = _ktxMipRequest->getResult();
|
||||
if (result == ResourceRequest::Success) {
|
||||
auto extraInfo = _url == _activeUrl ? "" : QString(", %1").arg(_activeUrl.toDisplayString());
|
||||
qCDebug(networking).noquote() << QString("Request finished for %1%2").arg(_url.toDisplayString(), extraInfo);
|
||||
|
||||
if (_ktxResourceState == REQUESTING_MIP) {
|
||||
Q_ASSERT(_ktxMipLevelRangeInFlight.first != NULL_MIP_LEVEL);
|
||||
Q_ASSERT(_ktxMipLevelRangeInFlight.second - _ktxMipLevelRangeInFlight.first == 0);
|
||||
|
||||
_ktxResourceState = WAITING_FOR_MIP_REQUEST;
|
||||
|
||||
auto self = _self;
|
||||
auto url = _url;
|
||||
auto data = _ktxMipRequest->getData();
|
||||
auto mipLevel = _ktxMipLevelRangeInFlight.first;
|
||||
auto texture = _textureSource->getGPUTexture();
|
||||
if (texture) {
|
||||
texture->assignStoredMip(_ktxMipLevelRangeInFlight.first,
|
||||
_ktxMipRequest->getData().size(), reinterpret_cast<uint8_t*>(_ktxMipRequest->getData().data()));
|
||||
DependencyManager::get<StatTracker>()->incrementStat("PendingProcessing");
|
||||
QtConcurrent::run(QThreadPool::globalInstance(), [self, data, mipLevel, url, texture] {
|
||||
PROFILE_RANGE_EX(resource_parse_image, "NetworkTexture - Processing Mip Data", 0xffff0000, 0, { { "url", url.toString() } });
|
||||
DependencyManager::get<StatTracker>()->decrementStat("PendingProcessing");
|
||||
CounterStat counter("Processing");
|
||||
|
||||
if (texture->minAvailableMipLevel() <= _ktxMipLevelRangeInFlight.first) {
|
||||
_lowestKnownPopulatedMip = texture->minAvailableMipLevel();
|
||||
_ktxResourceState = WAITING_FOR_MIP_REQUEST;
|
||||
} else {
|
||||
qWarning(networking) << "Failed to load mip: " << _url << ":" << _ktxMipLevelRangeInFlight.first;
|
||||
_ktxResourceState = FAILED_TO_LOAD;
|
||||
auto originalPriority = QThread::currentThread()->priority();
|
||||
if (originalPriority == QThread::InheritPriority) {
|
||||
originalPriority = QThread::NormalPriority;
|
||||
}
|
||||
} else {
|
||||
_ktxResourceState = WAITING_FOR_MIP_REQUEST;
|
||||
qWarning(networking) << "Trying to update mips but texture is null";
|
||||
}
|
||||
finishedLoading(true);
|
||||
QThread::currentThread()->setPriority(QThread::LowPriority);
|
||||
Finally restorePriority([originalPriority] { QThread::currentThread()->setPriority(originalPriority); });
|
||||
|
||||
auto resource = self.lock();
|
||||
if (!resource) {
|
||||
// Resource no longer exists, bail
|
||||
return;
|
||||
}
|
||||
|
||||
Q_ASSERT_X(texture, "Async - NetworkTexture::ktxMipRequestFinished", "NetworkTexture should have been assigned a GPU texture by now.");
|
||||
|
||||
texture->assignStoredMip(mipLevel, data.size(), reinterpret_cast<const uint8_t*>(data.data()));
|
||||
|
||||
QMetaObject::invokeMethod(resource.data(), "setImage",
|
||||
Q_ARG(gpu::TexturePointer, texture),
|
||||
Q_ARG(int, texture->getWidth()),
|
||||
Q_ARG(int, texture->getHeight()));
|
||||
|
||||
QMetaObject::invokeMethod(resource.data(), "startRequestForNextMipLevel");
|
||||
});
|
||||
} else {
|
||||
qWarning(networking) << "Mip request finished in an unexpected state: " << _ktxResourceState;
|
||||
finishedLoading(false);
|
||||
if (handleFailedRequest(_ktxMipRequest->getResult())) {
|
||||
_ktxResourceState = PENDING_MIP_REQUEST;
|
||||
} else {
|
||||
qWarning(networking) << "Failed to load mip: " << _url;
|
||||
_ktxResourceState = FAILED_TO_LOAD;
|
||||
}
|
||||
}
|
||||
|
||||
_ktxMipRequest->deleteLater();
|
||||
_ktxMipRequest = nullptr;
|
||||
|
||||
if (_ktxResourceState == WAITING_FOR_MIP_REQUEST && _lowestRequestedMipLevel < _lowestKnownPopulatedMip) {
|
||||
startRequestForNextMipLevel();
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Mip request finished in an unexpected state: " << _ktxResourceState;
|
||||
if (handleFailedRequest(result)) {
|
||||
_ktxResourceState = PENDING_MIP_REQUEST;
|
||||
} else {
|
||||
_ktxResourceState = FAILED_TO_LOAD;
|
||||
}
|
||||
}
|
||||
|
||||
_ktxMipRequest->disconnect(this);
|
||||
_ktxMipRequest->deleteLater();
|
||||
_ktxMipRequest = nullptr;
|
||||
}
|
||||
|
||||
// This is called when the header or top mips have been loaded
|
||||
void NetworkTexture::maybeHandleFinishedInitialLoad() {
|
||||
// This is called when the header and top mips have been loaded
|
||||
void NetworkTexture::handleFinishedInitialLoad() {
|
||||
Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA);
|
||||
Q_ASSERT(!_ktxHeaderData.isEmpty() && !_ktxHighMipData.isEmpty());
|
||||
|
||||
if (_ktxHeaderRequestFinished && _ktxHighMipRequestFinished) {
|
||||
// create ktx...
|
||||
auto ktxHeaderData = _ktxHeaderData;
|
||||
auto ktxHighMipData = _ktxHighMipData;
|
||||
_ktxHeaderData.clear();
|
||||
_ktxHighMipData.clear();
|
||||
|
||||
TextureCache::requestCompleted(_self);
|
||||
_ktxResourceState = WAITING_FOR_MIP_REQUEST;
|
||||
|
||||
if (_ktxHeaderRequest->getResult() != ResourceRequest::Success || _ktxMipRequest->getResult() != ResourceRequest::Success) {
|
||||
if (handleFailedRequest(_ktxMipRequest->getResult())) {
|
||||
_ktxResourceState = PENDING_INITIAL_LOAD;
|
||||
}
|
||||
else {
|
||||
_ktxResourceState = FAILED_TO_LOAD;
|
||||
}
|
||||
auto self = _self;
|
||||
auto url = _url;
|
||||
DependencyManager::get<StatTracker>()->incrementStat("PendingProcessing");
|
||||
QtConcurrent::run(QThreadPool::globalInstance(), [self, ktxHeaderData, ktxHighMipData, url] {
|
||||
PROFILE_RANGE_EX(resource_parse_image, "NetworkTexture - Processing Initial Data", 0xffff0000, 0, { { "url", url.toString() } });
|
||||
DependencyManager::get<StatTracker>()->decrementStat("PendingProcessing");
|
||||
CounterStat counter("Processing");
|
||||
|
||||
_ktxHeaderRequest->deleteLater();
|
||||
_ktxHeaderRequest = nullptr;
|
||||
_ktxMipRequest->deleteLater();
|
||||
_ktxMipRequest = nullptr;
|
||||
} else {
|
||||
// create ktx...
|
||||
auto ktxHeaderData = _ktxHeaderRequest->getData();
|
||||
auto ktxHighMipData = _ktxMipRequest->getData();
|
||||
|
||||
auto header = reinterpret_cast<const ktx::Header*>(ktxHeaderData.data());
|
||||
|
||||
if (!ktx::checkIdentifier(header->identifier)) {
|
||||
qWarning() << "Cannot load " << _url << ", invalid header identifier";
|
||||
_ktxResourceState = FAILED_TO_LOAD;
|
||||
finishedLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
auto kvSize = header->bytesOfKeyValueData;
|
||||
if (kvSize > (ktxHeaderData.size() - ktx::KTX_HEADER_SIZE)) {
|
||||
qWarning() << "Cannot load " << _url << ", did not receive all kv data with initial request";
|
||||
_ktxResourceState = FAILED_TO_LOAD;
|
||||
finishedLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
auto keyValues = ktx::KTX::parseKeyValues(header->bytesOfKeyValueData, reinterpret_cast<const ktx::Byte*>(ktxHeaderData.data()) + ktx::KTX_HEADER_SIZE);
|
||||
|
||||
auto imageDescriptors = header->generateImageDescriptors();
|
||||
if (imageDescriptors.size() == 0) {
|
||||
qWarning(networking) << "Failed to process ktx file " << _url;
|
||||
_ktxResourceState = FAILED_TO_LOAD;
|
||||
finishedLoading(false);
|
||||
}
|
||||
_originalKtxDescriptor.reset(new ktx::KTXDescriptor(*header, keyValues, imageDescriptors));
|
||||
|
||||
// Create bare ktx in memory
|
||||
auto found = std::find_if(keyValues.begin(), keyValues.end(), [](const ktx::KeyValue& val) -> bool {
|
||||
return val._key.compare(gpu::SOURCE_HASH_KEY) == 0;
|
||||
});
|
||||
std::string filename;
|
||||
std::string hash;
|
||||
if (found == keyValues.end() || found->_value.size() != gpu::SOURCE_HASH_BYTES) {
|
||||
qWarning("Invalid source hash key found, bailing");
|
||||
_ktxResourceState = FAILED_TO_LOAD;
|
||||
finishedLoading(false);
|
||||
return;
|
||||
} else {
|
||||
// at this point the source hash is in binary 16-byte form
|
||||
// and we need it in a hexadecimal string
|
||||
auto binaryHash = QByteArray(reinterpret_cast<char*>(found->_value.data()), gpu::SOURCE_HASH_BYTES);
|
||||
hash = filename = binaryHash.toHex().toStdString();
|
||||
}
|
||||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
|
||||
gpu::TexturePointer texture = textureCache->getTextureByHash(hash);
|
||||
|
||||
if (!texture) {
|
||||
KTXFilePointer ktxFile = textureCache->_ktxCache.getFile(hash);
|
||||
if (ktxFile) {
|
||||
texture = gpu::Texture::unserialize(ktxFile->getFilepath());
|
||||
if (texture) {
|
||||
texture = textureCache->cacheTextureByHash(hash, texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!texture) {
|
||||
|
||||
auto memKtx = ktx::KTX::createBare(*header, keyValues);
|
||||
if (!memKtx) {
|
||||
qWarning() << " Ktx could not be created, bailing";
|
||||
finishedLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Move ktx to file
|
||||
const char* data = reinterpret_cast<const char*>(memKtx->_storage->data());
|
||||
size_t length = memKtx->_storage->size();
|
||||
KTXFilePointer file;
|
||||
auto& ktxCache = textureCache->_ktxCache;
|
||||
if (!memKtx || !(file = ktxCache.writeFile(data, KTXCache::Metadata(filename, length)))) {
|
||||
qCWarning(modelnetworking) << _url << " failed to write cache file";
|
||||
_ktxResourceState = FAILED_TO_LOAD;
|
||||
finishedLoading(false);
|
||||
return;
|
||||
} else {
|
||||
_file = file;
|
||||
}
|
||||
|
||||
auto newKtxDescriptor = memKtx->toDescriptor();
|
||||
|
||||
texture = gpu::Texture::unserialize(_file->getFilepath(), newKtxDescriptor);
|
||||
texture->setKtxBacking(file->getFilepath());
|
||||
texture->setSource(filename);
|
||||
|
||||
auto& images = _originalKtxDescriptor->images;
|
||||
size_t imageSizeRemaining = ktxHighMipData.size();
|
||||
uint8_t* ktxData = reinterpret_cast<uint8_t*>(ktxHighMipData.data());
|
||||
ktxData += ktxHighMipData.size();
|
||||
// TODO Move image offset calculation to ktx ImageDescriptor
|
||||
for (int level = static_cast<int>(images.size()) - 1; level >= 0; --level) {
|
||||
auto& image = images[level];
|
||||
if (image._imageSize > imageSizeRemaining) {
|
||||
break;
|
||||
}
|
||||
ktxData -= image._imageSize;
|
||||
texture->assignStoredMip(static_cast<gpu::uint16>(level), image._imageSize, ktxData);
|
||||
ktxData -= ktx::IMAGE_SIZE_WIDTH;
|
||||
imageSizeRemaining -= (image._imageSize + ktx::IMAGE_SIZE_WIDTH);
|
||||
}
|
||||
|
||||
// We replace the texture with the one stored in the cache. This deals with the possible race condition of two different
|
||||
// images with the same hash being loaded concurrently. Only one of them will make it into the cache by hash first and will
|
||||
// be the winner
|
||||
texture = textureCache->cacheTextureByHash(filename, texture);
|
||||
}
|
||||
|
||||
_lowestKnownPopulatedMip = texture->minAvailableMipLevel();
|
||||
|
||||
_ktxResourceState = WAITING_FOR_MIP_REQUEST;
|
||||
setImage(texture, header->getPixelWidth(), header->getPixelHeight());
|
||||
|
||||
_ktxHeaderRequest->deleteLater();
|
||||
_ktxHeaderRequest = nullptr;
|
||||
_ktxMipRequest->deleteLater();
|
||||
_ktxMipRequest = nullptr;
|
||||
auto originalPriority = QThread::currentThread()->priority();
|
||||
if (originalPriority == QThread::InheritPriority) {
|
||||
originalPriority = QThread::NormalPriority;
|
||||
}
|
||||
startRequestForNextMipLevel();
|
||||
}
|
||||
QThread::currentThread()->setPriority(QThread::LowPriority);
|
||||
Finally restorePriority([originalPriority] { QThread::currentThread()->setPriority(originalPriority); });
|
||||
|
||||
auto resource = self.lock();
|
||||
if (!resource) {
|
||||
// Resource no longer exists, bail
|
||||
return;
|
||||
}
|
||||
|
||||
auto header = reinterpret_cast<const ktx::Header*>(ktxHeaderData.data());
|
||||
|
||||
if (!ktx::checkIdentifier(header->identifier)) {
|
||||
qWarning() << "Cannot load " << url << ", invalid header identifier";
|
||||
QMetaObject::invokeMethod(resource.data(), "setImage",
|
||||
Q_ARG(gpu::TexturePointer, nullptr),
|
||||
Q_ARG(int, 0),
|
||||
Q_ARG(int, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
auto kvSize = header->bytesOfKeyValueData;
|
||||
if (kvSize > (ktxHeaderData.size() - ktx::KTX_HEADER_SIZE)) {
|
||||
qWarning() << "Cannot load " << url << ", did not receive all kv data with initial request";
|
||||
QMetaObject::invokeMethod(resource.data(), "setImage",
|
||||
Q_ARG(gpu::TexturePointer, nullptr),
|
||||
Q_ARG(int, 0),
|
||||
Q_ARG(int, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
auto keyValues = ktx::KTX::parseKeyValues(header->bytesOfKeyValueData, reinterpret_cast<const ktx::Byte*>(ktxHeaderData.data()) + ktx::KTX_HEADER_SIZE);
|
||||
|
||||
auto imageDescriptors = header->generateImageDescriptors();
|
||||
if (imageDescriptors.size() == 0) {
|
||||
qWarning(networking) << "Failed to process ktx file " << url;
|
||||
QMetaObject::invokeMethod(resource.data(), "setImage",
|
||||
Q_ARG(gpu::TexturePointer, nullptr),
|
||||
Q_ARG(int, 0),
|
||||
Q_ARG(int, 0));
|
||||
return;
|
||||
}
|
||||
auto originalKtxDescriptor = new ktx::KTXDescriptor(*header, keyValues, imageDescriptors);
|
||||
QMetaObject::invokeMethod(resource.data(), "setOriginalDescriptor",
|
||||
Q_ARG(ktx::KTXDescriptor*, originalKtxDescriptor));
|
||||
|
||||
// Create bare ktx in memory
|
||||
auto found = std::find_if(keyValues.begin(), keyValues.end(), [](const ktx::KeyValue& val) -> bool {
|
||||
return val._key.compare(gpu::SOURCE_HASH_KEY) == 0;
|
||||
});
|
||||
std::string filename;
|
||||
std::string hash;
|
||||
if (found == keyValues.end() || found->_value.size() != gpu::SOURCE_HASH_BYTES) {
|
||||
qWarning("Invalid source hash key found, bailing");
|
||||
QMetaObject::invokeMethod(resource.data(), "setImage",
|
||||
Q_ARG(gpu::TexturePointer, nullptr),
|
||||
Q_ARG(int, 0),
|
||||
Q_ARG(int, 0));
|
||||
return;
|
||||
} else {
|
||||
// at this point the source hash is in binary 16-byte form
|
||||
// and we need it in a hexadecimal string
|
||||
auto binaryHash = QByteArray(reinterpret_cast<char*>(found->_value.data()), gpu::SOURCE_HASH_BYTES);
|
||||
hash = filename = binaryHash.toHex().toStdString();
|
||||
}
|
||||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
|
||||
gpu::TexturePointer texture = textureCache->getTextureByHash(hash);
|
||||
|
||||
if (!texture) {
|
||||
KTXFilePointer ktxFile = textureCache->_ktxCache.getFile(hash);
|
||||
if (ktxFile) {
|
||||
texture = gpu::Texture::unserialize(ktxFile);
|
||||
if (texture) {
|
||||
texture = textureCache->cacheTextureByHash(hash, texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!texture) {
|
||||
|
||||
auto memKtx = ktx::KTX::createBare(*header, keyValues);
|
||||
if (!memKtx) {
|
||||
qWarning() << " Ktx could not be created, bailing";
|
||||
QMetaObject::invokeMethod(resource.data(), "setImage",
|
||||
Q_ARG(gpu::TexturePointer, nullptr),
|
||||
Q_ARG(int, 0),
|
||||
Q_ARG(int, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
// Move ktx to file
|
||||
const char* data = reinterpret_cast<const char*>(memKtx->_storage->data());
|
||||
size_t length = memKtx->_storage->size();
|
||||
KTXFilePointer file;
|
||||
auto& ktxCache = textureCache->_ktxCache;
|
||||
if (!memKtx || !(file = ktxCache.writeFile(data, KTXCache::Metadata(filename, length)))) {
|
||||
qCWarning(modelnetworking) << url << " failed to write cache file";
|
||||
QMetaObject::invokeMethod(resource.data(), "setImage",
|
||||
Q_ARG(gpu::TexturePointer, nullptr),
|
||||
Q_ARG(int, 0),
|
||||
Q_ARG(int, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
auto newKtxDescriptor = memKtx->toDescriptor();
|
||||
|
||||
texture = gpu::Texture::build(newKtxDescriptor);
|
||||
texture->setKtxBacking(file);
|
||||
texture->setSource(filename);
|
||||
|
||||
auto& images = originalKtxDescriptor->images;
|
||||
size_t imageSizeRemaining = ktxHighMipData.size();
|
||||
const uint8_t* ktxData = reinterpret_cast<const uint8_t*>(ktxHighMipData.data());
|
||||
ktxData += ktxHighMipData.size();
|
||||
// TODO Move image offset calculation to ktx ImageDescriptor
|
||||
for (int level = static_cast<int>(images.size()) - 1; level >= 0; --level) {
|
||||
auto& image = images[level];
|
||||
if (image._imageSize > imageSizeRemaining) {
|
||||
break;
|
||||
}
|
||||
ktxData -= image._imageSize;
|
||||
texture->assignStoredMip(static_cast<gpu::uint16>(level), image._imageSize, ktxData);
|
||||
ktxData -= ktx::IMAGE_SIZE_WIDTH;
|
||||
imageSizeRemaining -= (image._imageSize + ktx::IMAGE_SIZE_WIDTH);
|
||||
}
|
||||
|
||||
// We replace the texture with the one stored in the cache. This deals with the possible race condition of two different
|
||||
// images with the same hash being loaded concurrently. Only one of them will make it into the cache by hash first and will
|
||||
// be the winner
|
||||
texture = textureCache->cacheTextureByHash(filename, texture);
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(resource.data(), "setImage",
|
||||
Q_ARG(gpu::TexturePointer, texture),
|
||||
Q_ARG(int, texture->getWidth()),
|
||||
Q_ARG(int, texture->getHeight()));
|
||||
|
||||
QMetaObject::invokeMethod(resource.data(), "startRequestForNextMipLevel");
|
||||
});
|
||||
}
|
||||
|
||||
void NetworkTexture::downloadFinished(const QByteArray& data) {
|
||||
|
@ -796,7 +902,7 @@ void ImageReader::read() {
|
|||
if (!texture) {
|
||||
KTXFilePointer ktxFile = textureCache->_ktxCache.getFile(hash);
|
||||
if (ktxFile) {
|
||||
texture = gpu::Texture::unserialize(ktxFile->getFilepath());
|
||||
texture = gpu::Texture::unserialize(ktxFile);
|
||||
if (texture) {
|
||||
texture = textureCache->cacheTextureByHash(hash, texture);
|
||||
} else {
|
||||
|
@ -844,11 +950,11 @@ void ImageReader::read() {
|
|||
const char* data = reinterpret_cast<const char*>(memKtx->_storage->data());
|
||||
size_t length = memKtx->_storage->size();
|
||||
auto& ktxCache = textureCache->_ktxCache;
|
||||
networkTexture->_file = ktxCache.writeFile(data, KTXCache::Metadata(hash, length)); //
|
||||
if (!networkTexture->_file) {
|
||||
auto file = ktxCache.writeFile(data, KTXCache::Metadata(hash, length));
|
||||
if (!file) {
|
||||
qCWarning(modelnetworking) << _url << "file cache failed";
|
||||
} else {
|
||||
texture->setKtxBacking(networkTexture->_file->getFilepath());
|
||||
texture->setKtxBacking(file);
|
||||
}
|
||||
} else {
|
||||
qCWarning(modelnetworking) << "Unable to serialize texture to KTX " << _url;
|
||||
|
@ -865,3 +971,32 @@ void ImageReader::read() {
|
|||
Q_ARG(int, texture->getWidth()),
|
||||
Q_ARG(int, texture->getHeight()));
|
||||
}
|
||||
|
||||
|
||||
NetworkTexturePointer TextureCache::getResourceTexture(QUrl resourceTextureUrl) {
|
||||
gpu::TexturePointer texture;
|
||||
if (resourceTextureUrl == SPECTATOR_CAMERA_FRAME_URL) {
|
||||
if (!_spectatorCameraNetworkTexture) {
|
||||
_spectatorCameraNetworkTexture.reset(new NetworkTexture(resourceTextureUrl));
|
||||
}
|
||||
texture = _spectatorCameraFramebuffer->getRenderBuffer(0);
|
||||
if (texture) {
|
||||
_spectatorCameraNetworkTexture->setImage(texture, texture->getWidth(), texture->getHeight());
|
||||
return _spectatorCameraNetworkTexture;
|
||||
}
|
||||
}
|
||||
|
||||
return NetworkTexturePointer();
|
||||
}
|
||||
|
||||
const gpu::FramebufferPointer& TextureCache::getSpectatorCameraFramebuffer() {
|
||||
if (!_spectatorCameraFramebuffer) {
|
||||
resetSpectatorCameraFramebuffer(2048, 1024);
|
||||
}
|
||||
return _spectatorCameraFramebuffer;
|
||||
}
|
||||
|
||||
void TextureCache::resetSpectatorCameraFramebuffer(int width, int height) {
|
||||
_spectatorCameraFramebuffer.reset(gpu::Framebuffer::create("spectatorCamera", gpu::Element::COLOR_SRGBA_32, width, height));
|
||||
_spectatorCameraNetworkTexture.reset();
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ class NetworkTexture : public Resource, public Texture {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
NetworkTexture(const QUrl& url);
|
||||
NetworkTexture(const QUrl& url, image::TextureUsage::Type type, const QByteArray& content, int maxNumPixels);
|
||||
~NetworkTexture() override;
|
||||
|
||||
|
@ -58,14 +59,13 @@ public:
|
|||
|
||||
void refresh() override;
|
||||
|
||||
Q_INVOKABLE void setOriginalDescriptor(ktx::KTXDescriptor* descriptor) { _originalKtxDescriptor.reset(descriptor); }
|
||||
|
||||
signals:
|
||||
void networkTextureCreated(const QWeakPointer<NetworkTexture>& self);
|
||||
|
||||
public slots:
|
||||
void ktxHeaderRequestProgress(uint64_t bytesReceived, uint64_t bytesTotal) { }
|
||||
void ktxHeaderRequestFinished();
|
||||
|
||||
void ktxMipRequestProgress(uint64_t bytesReceived, uint64_t bytesTotal) { }
|
||||
void ktxInitialDataRequestFinished();
|
||||
void ktxMipRequestFinished();
|
||||
|
||||
protected:
|
||||
|
@ -74,14 +74,14 @@ protected:
|
|||
virtual bool isCacheable() const override { return _loaded; }
|
||||
|
||||
virtual void downloadFinished(const QByteArray& data) override;
|
||||
|
||||
|
||||
Q_INVOKABLE void loadContent(const QByteArray& content);
|
||||
Q_INVOKABLE void setImage(gpu::TexturePointer texture, int originalWidth, int originalHeight);
|
||||
|
||||
void startRequestForNextMipLevel();
|
||||
Q_INVOKABLE void startRequestForNextMipLevel();
|
||||
|
||||
void startMipRangeRequest(uint16_t low, uint16_t high);
|
||||
void maybeHandleFinishedInitialLoad();
|
||||
void handleFinishedInitialLoad();
|
||||
|
||||
private:
|
||||
friend class KTXReader;
|
||||
|
@ -102,16 +102,13 @@ private:
|
|||
bool _sourceIsKTX { false };
|
||||
KTXResourceState _ktxResourceState { PENDING_INITIAL_LOAD };
|
||||
|
||||
// TODO Can this be removed?
|
||||
KTXFilePointer _file;
|
||||
|
||||
// The current mips that are currently being requested w/ _ktxMipRequest
|
||||
std::pair<uint16_t, uint16_t> _ktxMipLevelRangeInFlight{ NULL_MIP_LEVEL, NULL_MIP_LEVEL };
|
||||
|
||||
ResourceRequest* _ktxHeaderRequest { nullptr };
|
||||
ResourceRequest* _ktxMipRequest { nullptr };
|
||||
bool _ktxHeaderRequestFinished{ false };
|
||||
bool _ktxHighMipRequestFinished{ false };
|
||||
QByteArray _ktxHeaderData;
|
||||
QByteArray _ktxHighMipData;
|
||||
|
||||
uint16_t _lowestRequestedMipLevel { NULL_MIP_LEVEL };
|
||||
uint16_t _lowestKnownPopulatedMip { NULL_MIP_LEVEL };
|
||||
|
@ -128,6 +125,8 @@ private:
|
|||
int _width { 0 };
|
||||
int _height { 0 };
|
||||
int _maxNumPixels { ABSOLUTE_MAX_TEXTURE_NUM_PIXELS };
|
||||
|
||||
friend class TextureCache;
|
||||
};
|
||||
|
||||
using NetworkTexturePointer = QSharedPointer<NetworkTexture>;
|
||||
|
@ -166,6 +165,12 @@ public:
|
|||
gpu::TexturePointer getTextureByHash(const std::string& hash);
|
||||
gpu::TexturePointer cacheTextureByHash(const std::string& hash, const gpu::TexturePointer& texture);
|
||||
|
||||
|
||||
/// SpectatorCamera rendering targets.
|
||||
NetworkTexturePointer getResourceTexture(QUrl resourceTextureUrl);
|
||||
const gpu::FramebufferPointer& getSpectatorCameraFramebuffer();
|
||||
void resetSpectatorCameraFramebuffer(int width, int height);
|
||||
|
||||
protected:
|
||||
// Overload ResourceCache::prefetch to allow specifying texture type for loads
|
||||
Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type, int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS);
|
||||
|
@ -183,6 +188,7 @@ private:
|
|||
|
||||
static const std::string KTX_DIRNAME;
|
||||
static const std::string KTX_EXT;
|
||||
|
||||
KTXCache _ktxCache;
|
||||
// Map from image hashes to texture weak pointers
|
||||
std::unordered_map<std::string, std::weak_ptr<gpu::Texture>> _texturesByHashes;
|
||||
|
@ -193,6 +199,9 @@ private:
|
|||
gpu::TexturePointer _grayTexture;
|
||||
gpu::TexturePointer _blueTexture;
|
||||
gpu::TexturePointer _blackTexture;
|
||||
|
||||
NetworkTexturePointer _spectatorCameraNetworkTexture;
|
||||
gpu::FramebufferPointer _spectatorCameraFramebuffer;
|
||||
};
|
||||
|
||||
#endif // hifi_TextureCache_h
|
||||
|
|
|
@ -13,10 +13,10 @@
|
|||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "AABox.h"
|
||||
#include <AABox.h>
|
||||
|
||||
#include "gpu/Resource.h"
|
||||
#include "gpu/Stream.h"
|
||||
#include <gpu/Resource.h>
|
||||
#include <gpu/Stream.h>
|
||||
|
||||
namespace model {
|
||||
typedef gpu::BufferView::Index Index;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue