Merge branch 'master' into fix/update-links

This commit is contained in:
David Rowe 2020-12-15 21:09:07 +13:00
commit 086d46018b
52 changed files with 880 additions and 1211 deletions

View file

@ -14,7 +14,9 @@ env:
RELEASE_TYPE: PR
RELEASE_NUMBER: ${{ github.event.number }}
VERSION_CODE: ${{ github.event.number }}
# Sentry Crash Reporting
CMAKE_BACKTRACE_URL: ${{ secrets.MINIDUMP_TOKEN }}
CMAKE_BACKTRACE_TOKEN: PR_${{ github.event.number }}_${{ github.sha }}
# OSX specific variables
DEVELOPER_DIR: /Applications/Xcode_11.2.app/Contents/Developer

View file

@ -119,4 +119,4 @@ Some things you can try if you want to do a clean build
* In Android Studio, click _File > Invalidate Caches / Restart_ and select _Invalidate and Restart_
If you see lots of "couldn't acquire lock" errors,
* Open Task Manager and close any running Clang / Gradle processes
* Open Task Manager and close any running Clang / Gradle processes

View file

@ -2,7 +2,7 @@
//
// index.html
//
// Created by kasenvr@gmail.com on 21 Jul 2020
// Created by somnilibertas@gmail.com on 21 Jul 2020
// Copyright 2020 Vircadia and contributors.
//
// Distributed under the Apache License, Version 2.0.

View file

@ -309,8 +309,8 @@ FocusScope {
if (child.hasOwnProperty("modality")) {
var mappedPoint = mapToItem(child, point.x, point.y);
if (child.hasOwnProperty("frame")) {
var outLine = child.frame.children[2];
var framePoint = outLine.mapFromGlobal(point.x, point.y);
var outLine = child.frame.children[2]; // sizeOutline
var framePoint = mapToItem(outLine, point.x, point.y);
if (outLine.contains(framePoint)) {
return true;
}

View file

@ -2,8 +2,8 @@
// EntityScriptQMLWhitelist.qml
// interface/resources/qml/hifi/dialogs/security
//
// Created by Kasen IO on 2019.12.05 | realities.dev | kasenvr@gmail.com
// Copyright 2019 Kasen IO
// Created by Kalila L. on 2019.12.05 | realities.dev | somnilibertas@gmail.com
// Copyright 2019 Kalila L.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html

View file

@ -314,7 +314,7 @@ Rectangle {
onClicked: {
lightboxPopup.titleText = "Script Plugin Infrastructure";
lightboxPopup.bodyText = "Toggles the activation of scripting plugins in the 'plugins/scripting' folder. \n\n"
+ "Created by:\n humbletim@gmail.com\n kasenvr@gmail.com";
+ "Created by:\n humbletim@gmail.com\n somnilibertas@gmail.com";
lightboxPopup.button1text = "OK";
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;

View file

@ -27,7 +27,6 @@ Item {
readonly property int frameMarginRight: frame.decoration ? frame.decoration.frameMarginRight : 0
readonly property int frameMarginTop: frame.decoration ? frame.decoration.frameMarginTop : 0
readonly property int frameMarginBottom: frame.decoration ? frame.decoration.frameMarginBottom : 0
readonly property int offsetCorrection: 20
// Frames always fill their parents, but their decorations may extend
// beyond the window via negative margin sizes
@ -76,7 +75,7 @@ Item {
Rectangle {
id: sizeOutline
x: -frameMarginLeft
y: -frameMarginTop - offsetCorrection
y: -frameMarginTop
width: window ? window.width + frameMarginLeft + frameMarginRight + 2 : 0
height: window ? window.height + frameMarginTop + frameMarginBottom + 2 : 0
color: hifi.colors.baseGrayHighlight15

View file

@ -8712,7 +8712,7 @@ void Application::notifyPacketVersionMismatch() {
}
void Application::checkSkeleton() const {
if (getMyAvatar()->getSkeletonModel()->isActive() && !getMyAvatar()->getSkeletonModel()->hasSkeleton()) {
if (getMyAvatar()->getSkeletonModel()->isLoaded() && !getMyAvatar()->getSkeletonModel()->hasSkeleton()) {
qCDebug(interfaceapp) << "MyAvatar model has no skeleton";
QString message = "Your selected avatar body has no skeleton.\n\nThe default body will be loaded...";

View file

@ -23,7 +23,7 @@ OverlayConductor::OverlayConductor() {
OverlayConductor::~OverlayConductor() {
}
bool OverlayConductor::headOutsideOverlay() const {
bool OverlayConductor::headNotCenteredInOverlay() const {
glm::mat4 hmdMat = qApp->getHMDSensorPose();
glm::vec3 hmdPos = extractTranslation(hmdMat);
glm::vec3 hmdForward = transformVectorFast(hmdMat, glm::vec3(0.0f, 0.0f, -1.0f));
@ -32,8 +32,8 @@ bool OverlayConductor::headOutsideOverlay() const {
glm::vec3 uiPos = uiTransform.getTranslation();
glm::vec3 uiForward = uiTransform.getRotation() * glm::vec3(0.0f, 0.0f, -1.0f);
const float MAX_COMPOSITOR_DISTANCE = 0.99f; // If you're 1m from center of ui sphere, you're at the surface.
const float MAX_COMPOSITOR_ANGLE = 180.0f; // rotation check is effectively disabled
const float MAX_COMPOSITOR_DISTANCE = 0.33f;
const float MAX_COMPOSITOR_ANGLE = 90.0f;
if (glm::distance(uiPos, hmdPos) > MAX_COMPOSITOR_DISTANCE ||
glm::dot(uiForward, hmdForward) < cosf(glm::radians(MAX_COMPOSITOR_ANGLE))) {
return true;
@ -70,6 +70,8 @@ bool OverlayConductor::updateAvatarIsAtRest() {
void OverlayConductor::centerUI() {
// place the overlay at the current hmd position in sensor space
auto camMat = cancelOutRollAndPitch(qApp->getHMDSensorPose());
// Set its radius.
camMat = glm::scale(camMat, glm::vec3(HUD_RADIUS));
qApp->getApplicationCompositor().setModelTransform(Transform(camMat));
}
@ -83,7 +85,6 @@ void OverlayConductor::update(float dt) {
if (!desktop) {
return;
}
bool currentVisible = !desktop->property("pinned").toBool();
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
// centerUI when hmd mode is first enabled and mounted
@ -96,24 +97,24 @@ void OverlayConductor::update(float dt) {
_hmdMode = false;
}
bool shouldRecenter = false;
if (_suppressedByHead) {
if (updateAvatarIsAtRest()) {
_suppressedByHead = false;
shouldRecenter = true;
}
} else {
if (_hmdMode && headOutsideOverlay()) {
_suppressedByHead = true;
}
bool initiateRecenter = false;
if (_hmdMode && headNotCenteredInOverlay()) {
initiateRecenter = true;
}
bool shouldRecenter = false;
if (initiateRecenter || _suppressedByHead) {
_suppressedByHead = !updateAvatarIsAtRest();
shouldRecenter = !_suppressedByHead;
}
bool currentVisible = !desktop->property("pinned").toBool();
bool targetVisible = Menu::getInstance()->isOptionChecked(MenuOption::Overlays) && !_suppressedByHead;
if (targetVisible != currentVisible) {
offscreenUi->setPinned(!targetVisible);
}
if (shouldRecenter && !_suppressedByHead) {
if (shouldRecenter) {
centerUI();
}
#endif

View file

@ -22,7 +22,7 @@ public:
void centerUI();
private:
bool headOutsideOverlay() const;
bool headNotCenteredInOverlay() const;
bool updateAvatarIsAtRest();
#if !defined(DISABLE_QML)

View file

@ -1246,7 +1246,7 @@ glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const {
}
case CAMERA_MATRIX_INDEX: {
glm::quat rotation;
if (_skeletonModel && _skeletonModel->isActive()) {
if (_skeletonModel && _skeletonModel->isLoaded()) {
int headJointIndex = getJointIndex("Head");
if (headJointIndex >= 0) {
_skeletonModel->getAbsoluteJointRotationInRigFrame(headJointIndex, rotation);
@ -1298,7 +1298,7 @@ glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
}
case CAMERA_MATRIX_INDEX: {
glm::vec3 translation;
if (_skeletonModel && _skeletonModel->isActive()) {
if (_skeletonModel && _skeletonModel->isLoaded()) {
int headJointIndex = getJointIndex("Head");
if (headJointIndex >= 0) {
_skeletonModel->getAbsoluteJointTranslationInRigFrame(headJointIndex, translation);
@ -1427,7 +1427,7 @@ void Avatar::withValidJointIndicesCache(std::function<void()> const& worker) con
QWriteLocker writeLock(&_modelJointIndicesCacheLock);
if (!_modelJointsCached) {
_modelJointIndicesCache.clear();
if (_skeletonModel && _skeletonModel->isActive()) {
if (_skeletonModel && _skeletonModel->isLoaded()) {
_modelJointIndicesCache = _skeletonModel->getHFMModel().jointIndices;
_modelJointsCached = true;
}

View file

@ -176,7 +176,7 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
updateRenderItems();
}
if (!isActive() || !_owningAvatar->isMyAvatar()) {
if (!isLoaded() || !_owningAvatar->isMyAvatar()) {
return; // only simulate for own avatar
}
@ -255,19 +255,19 @@ bool SkeletonModel::getRightHandPosition(glm::vec3& position) const {
}
bool SkeletonModel::getHeadPosition(glm::vec3& headPosition) const {
return isActive() && getJointPositionInWorldFrame(_rig.indexOfJoint("Head"), headPosition);
return isLoaded() && getJointPositionInWorldFrame(_rig.indexOfJoint("Head"), headPosition);
}
bool SkeletonModel::getNeckPosition(glm::vec3& neckPosition) const {
return isActive() && getJointPositionInWorldFrame(_rig.indexOfJoint("Neck"), neckPosition);
return isLoaded() && getJointPositionInWorldFrame(_rig.indexOfJoint("Neck"), neckPosition);
}
bool SkeletonModel::getLocalNeckPosition(glm::vec3& neckPosition) const {
return isActive() && getJointPosition(_rig.indexOfJoint("Neck"), neckPosition);
return isLoaded() && getJointPosition(_rig.indexOfJoint("Neck"), neckPosition);
}
bool SkeletonModel::getEyeModelPositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const {
if (!isActive()) {
if (!isLoaded()) {
return false;
}
@ -361,7 +361,7 @@ void SkeletonModel::renderBoundingCollisionShapes(RenderArgs* args, gpu::Batch&
}
bool SkeletonModel::hasSkeleton() {
return isActive() ? _rig.indexOfJoint("Hips") != -1 : false;
return isLoaded() ? _rig.indexOfJoint("Hips") != -1 : false;
}
void SkeletonModel::onInvalidate() {

View file

@ -44,10 +44,10 @@ public:
bool getIsJointOverridden(int jointIndex) const;
/// Returns the index of the left hand joint, or -1 if not found.
int getLeftHandJointIndex() const { return isActive() ? _rig.indexOfJoint("LeftHand") : -1; }
int getLeftHandJointIndex() const { return isLoaded() ? _rig.indexOfJoint("LeftHand") : -1; }
/// Returns the index of the right hand joint, or -1 if not found.
int getRightHandJointIndex() const { return isActive() ? _rig.indexOfJoint("RightHand") : -1; }
int getRightHandJointIndex() const { return isLoaded() ? _rig.indexOfJoint("RightHand") : -1; }
bool getLeftGrabPosition(glm::vec3& position) const;
bool getRightGrabPosition(glm::vec3& position) const;

View file

@ -41,10 +41,10 @@ static const float reticleSize = TWO_PI / 100.0f;
//EntityItemID CompositorHelper::_noItemId;
static QString _tooltipId;
const uvec2 CompositorHelper::VIRTUAL_SCREEN_SIZE = uvec2(3960, 1188); // ~10% more pixel density than old version, 72dx240d FOV
const QRect CompositorHelper::VIRTUAL_SCREEN_RECOMMENDED_OVERLAY_RECT = QRect(956, 0, 2048, 1188); // don't include entire width only center 2048
const uvec2 CompositorHelper::VIRTUAL_SCREEN_SIZE = uvec2(2640, 1188);
const QRect CompositorHelper::VIRTUAL_SCREEN_RECOMMENDED_OVERLAY_RECT = QRect(296, 0, 2048, 1188); // Center 2048 pixels.
const float CompositorHelper::VIRTUAL_UI_ASPECT_RATIO = (float)VIRTUAL_SCREEN_SIZE.x / (float)VIRTUAL_SCREEN_SIZE.y;
const vec2 CompositorHelper::VIRTUAL_UI_TARGET_FOV = vec2(PI * 3.0f / 2.0f, PI * 3.0f / 2.0f / VIRTUAL_UI_ASPECT_RATIO);
const vec2 CompositorHelper::VIRTUAL_UI_TARGET_FOV = vec2(PI, PI / VIRTUAL_UI_ASPECT_RATIO);
const vec2 CompositorHelper::MOUSE_EXTENTS_ANGULAR_SIZE = vec2(PI * 2.0f, PI * 0.95f); // horizontal: full sphere, vertical: ~5deg from poles
const vec2 CompositorHelper::MOUSE_EXTENTS_PIXELS = vec2(VIRTUAL_SCREEN_SIZE) * (MOUSE_EXTENTS_ANGULAR_SIZE / VIRTUAL_UI_TARGET_FOV);
@ -384,9 +384,9 @@ bool CompositorHelper::calculateRayUICollisionPoint(const glm::vec3& position, c
glm::vec3 localPosition = transformPoint(worldToUi, position);
glm::vec3 localDirection = glm::normalize(transformVectorFast(worldToUi, direction));
const float UI_RADIUS = 1.0f;
const float UNIT_RADIUS = 1.0f;
float intersectionDistance;
if (raySphereIntersect(localDirection, localPosition, UI_RADIUS, &intersectionDistance)) {
if (raySphereIntersect(localDirection, localPosition, UNIT_RADIUS, &intersectionDistance)) {
result = transformPoint(uiToWorld, localPosition + localDirection * intersectionDistance);
#ifdef WANT_DEBUG
DebugDraw::getInstance().drawRay(position, result, glm::vec4(0.0f, 1.0f, 0.0f, 1.0f));
@ -407,9 +407,8 @@ bool CompositorHelper::calculateParabolaUICollisionPoint(const glm::vec3& origin
glm::vec3 localVelocity = glm::normalize(transformVectorFast(worldToUi, velocity));
glm::vec3 localAcceleration = glm::normalize(transformVectorFast(worldToUi, acceleration));
const float UI_RADIUS = 1.0f;
float intersectionDistance;
if (findParabolaSphereIntersection(localOrigin, localVelocity, localAcceleration, glm::vec3(0.0f), UI_RADIUS, intersectionDistance)) {
if (findParabolaSphereIntersection(localOrigin, localVelocity, localAcceleration, glm::vec3(0.0f), HUD_RADIUS, intersectionDistance)) {
result = origin + velocity * intersectionDistance + 0.5f * acceleration * intersectionDistance * intersectionDistance;
parabolicDistance = intersectionDistance;
return true;

View file

@ -27,7 +27,8 @@
class ReticleInterface;
const float DEFAULT_RETICLE_DEPTH = 1.0f; // FIXME - probably should be based on UI radius
const float HUD_RADIUS = 1.5f;
const float DEFAULT_RETICLE_DEPTH = HUD_RADIUS;
const float MAGNIFY_WIDTH = 220.0f;
const float MAGNIFY_HEIGHT = 100.0f;
@ -154,7 +155,7 @@ private:
std::unique_ptr<QPropertyAnimation> _alphaPropertyAnimation;
std::atomic<bool> _reticleVisible { true };
std::atomic<float> _reticleDepth { 1.0f };
std::atomic<float> _reticleDepth { DEFAULT_RETICLE_DEPTH };
// NOTE: when the compositor is running in HMD mode, it will control the reticle position as a custom
// application specific position, when it's in desktop mode, the reticle position will simply move

View file

@ -431,13 +431,13 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa
_visible = entity->getVisible();
setIsVisibleInSecondaryCamera(entity->isVisibleInSecondaryCamera());
setRenderLayer(entity->getRenderLayer());
setPrimitiveMode(entity->getPrimitiveMode());
_primitiveMode = entity->getPrimitiveMode();
_canCastShadow = entity->getCanCastShadow();
setCullWithParent(entity->getCullWithParent());
_cauterized = entity->getCauterized();
if (entity->needsZoneOcclusionUpdate()) {
entity->resetNeedsZoneOcclusionUpdate();
setRenderWithZones(entity->getRenderWithZones());
_renderWithZones = entity->getRenderWithZones();
}
entity->setNeedsRenderUpdate(false);
});
@ -469,11 +469,13 @@ void EntityRenderer::onRemoveFromScene(const EntityItemPointer& entity) {
void EntityRenderer::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {
std::lock_guard<std::mutex> lock(_materialsLock);
_materials[parentMaterialName].push(material);
emit requestRenderUpdate();
}
void EntityRenderer::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {
std::lock_guard<std::mutex> lock(_materialsLock);
_materials[parentMaterialName].remove(material);
emit requestRenderUpdate();
}
glm::vec4 EntityRenderer::calculatePulseColor(const glm::vec4& color, const PulsePropertyGroup& pulseProperties, quint64 start) {

View file

@ -108,18 +108,7 @@ protected:
virtual void setIsVisibleInSecondaryCamera(bool value) { _isVisibleInSecondaryCamera = value; }
virtual void setRenderLayer(RenderLayer value) { _renderLayer = value; }
virtual void setPrimitiveMode(PrimitiveMode value) { _primitiveMode = value; }
virtual void setCullWithParent(bool value) { _cullWithParent = value; }
virtual void setRenderWithZones(const QVector<QUuid>& renderWithZones) { _renderWithZones = renderWithZones; }
template <typename F, typename T>
T withReadLockResult(const std::function<T()>& f) {
T result;
withReadLock([&] {
result = f();
});
return result;
}
signals:
void requestRenderUpdate();

View file

@ -52,14 +52,11 @@ void GizmoEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
void GizmoEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
bool dirty = false;
RingGizmoPropertyGroup ringProperties = entity->getRingProperties();
withWriteLock([&] {
_gizmoType = entity->getGizmoType();
if (_ringProperties != ringProperties) {
_ringProperties = ringProperties;
dirty = true;
}
});
_gizmoType = entity->getGizmoType();
if (_ringProperties != ringProperties) {
_ringProperties = ringProperties;
dirty = true;
}
if (dirty || _prevPrimitiveMode != _primitiveMode || !_ringGeometryID || !_majorTicksGeometryID || !_minorTicksGeometryID) {
_prevPrimitiveMode = _primitiveMode;
@ -242,19 +239,20 @@ void GizmoEntityRenderer::doRender(RenderArgs* args) {
if (_gizmoType == GizmoType::RING) {
Transform transform;
bool hasTickMarks;
glm::vec4 tickProperties;
bool hasTickMarks = _ringProperties.getHasTickMarks();
glm::vec4 tickProperties = glm::vec4(_ringProperties.getMajorTickMarksAngle(), _ringProperties.getMajorTickMarksLength(),
_ringProperties.getMinorTickMarksAngle(), _ringProperties.getMinorTickMarksLength());
bool forward;
bool wireframe;
bool transparent;
withReadLock([&] {
transform = _renderTransform;
hasTickMarks = _ringProperties.getHasTickMarks();
tickProperties = glm::vec4(_ringProperties.getMajorTickMarksAngle(), _ringProperties.getMajorTickMarksLength(),
_ringProperties.getMinorTickMarksAngle(), _ringProperties.getMinorTickMarksLength());
transparent = isTransparent();
wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES;
forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;
});
bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES;
geometryCache->bindSimpleProgram(batch, false, isTransparent(), wireframe, true, true, forward, graphics::MaterialKey::CULL_NONE);
geometryCache->bindSimpleProgram(batch, false, transparent, wireframe, true, true, forward, graphics::MaterialKey::CULL_NONE);
batch.setModelTransform(transform);

View file

@ -30,16 +30,6 @@ bool GridEntityRenderer::isTransparent() const {
}
void GridEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
withWriteLock([&] {
_color = entity->getColor();
_alpha = entity->getAlpha();
_pulseProperties = entity->getPulseProperties();
_followCamera = entity->getFollowCamera();
_majorGridEvery = entity->getMajorGridEvery();
_minorGridEvery = entity->getMinorGridEvery();
});
void* key = (void*)this;
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
withWriteLock([&] {
@ -49,6 +39,16 @@ void GridEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
});
}
void GridEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
_color = entity->getColor();
_alpha = entity->getAlpha();
_pulseProperties = entity->getPulseProperties();
_followCamera = entity->getFollowCamera();
_majorGridEvery = entity->getMajorGridEvery();
_minorGridEvery = entity->getMinorGridEvery();
}
Item::Bound GridEntityRenderer::getBound() {
if (_followCamera) {
// This is a UI element that should always be in view, lie to the octree to avoid culling
@ -73,13 +73,12 @@ ShapeKey GridEntityRenderer::getShapeKey() {
}
void GridEntityRenderer::doRender(RenderArgs* args) {
glm::vec4 color;
glm::vec4 color = glm::vec4(toGlm(_color), _alpha);
color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
glm::vec3 dimensions;
Transform renderTransform;
bool forward;
withReadLock([&] {
color = glm::vec4(toGlm(_color), _alpha);
color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
dimensions = _dimensions;
renderTransform = _renderTransform;
forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;

View file

@ -30,10 +30,11 @@ protected:
private:
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override;
glm::u8vec3 _color;
float _alpha;
float _alpha { NAN };
PulsePropertyGroup _pulseProperties;
bool _followCamera;

View file

@ -29,44 +29,7 @@ bool ImageEntityRenderer::isTransparent() const {
return Parent::isTransparent() || (_textureIsLoaded && _texture->getGPUTexture() && _texture->getGPUTexture()->getUsage().isAlpha()) || _alpha < 1.0f || _pulseProperties.getAlphaMode() != PulseMode::NONE;
}
bool ImageEntityRenderer::needsRenderUpdate() const {
if (resultWithReadLock<bool>([&] {
return !_textureIsLoaded;
})) {
return true;
}
return Parent::needsRenderUpdate();
}
void ImageEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
withWriteLock([&] {
auto imageURL = entity->getImageURL();
if (_imageURL != imageURL) {
_imageURL = imageURL;
if (imageURL.isEmpty()) {
_texture.reset();
} else {
_texture = DependencyManager::get<TextureCache>()->getTexture(_imageURL);
}
_textureIsLoaded = false;
}
_emissive = entity->getEmissive();
_keepAspectRatio = entity->getKeepAspectRatio();
_subImage = entity->getSubImage();
_color = entity->getColor();
_alpha = entity->getAlpha();
_pulseProperties = entity->getPulseProperties();
_billboardMode = entity->getBillboardMode();
if (!_textureIsLoaded) {
emit requestRenderUpdate();
}
_textureIsLoaded = _texture && (_texture->isLoaded() || _texture->isFailed());
});
void* key = (void*)this;
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
withWriteLock([&] {
@ -76,6 +39,33 @@ void ImageEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
});
}
void ImageEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
auto imageURL = entity->getImageURL();
if (_imageURL != imageURL) {
_imageURL = imageURL;
if (imageURL.isEmpty()) {
_texture.reset();
} else {
_texture = DependencyManager::get<TextureCache>()->getTexture(_imageURL);
}
_textureIsLoaded = false;
}
_emissive = entity->getEmissive();
_keepAspectRatio = entity->getKeepAspectRatio();
_subImage = entity->getSubImage();
_color = entity->getColor();
_alpha = entity->getAlpha();
_pulseProperties = entity->getPulseProperties();
_billboardMode = entity->getBillboardMode();
if (!_textureIsLoaded) {
emit requestRenderUpdate();
}
_textureIsLoaded = _texture && (_texture->isLoaded() || _texture->isFailed());
}
Item::Bound ImageEntityRenderer::getBound() {
auto bound = Parent::getBound();
if (_billboardMode != BillboardMode::NONE) {
@ -93,33 +83,26 @@ ShapeKey ImageEntityRenderer::getShapeKey() {
builder.withTranslucent();
}
withReadLock([&] {
if (_emissive) {
builder.withUnlit();
}
if (_emissive) {
builder.withUnlit();
}
if (_primitiveMode == PrimitiveMode::LINES) {
builder.withWireframe();
}
});
if (_primitiveMode == PrimitiveMode::LINES) {
builder.withWireframe();
}
return builder.build();
}
void ImageEntityRenderer::doRender(RenderArgs* args) {
NetworkTexturePointer texture;
QRect subImage;
glm::vec4 color;
glm::vec4 color = glm::vec4(toGlm(_color), _alpha);
color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
Transform transform;
withReadLock([&] {
texture = _texture;
subImage = _subImage;
color = glm::vec4(toGlm(_color), _alpha);
color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
transform = _renderTransform;
});
if (!_visible || !texture || !texture->isLoaded() || color.a == 0.0f) {
if (!_visible || !_texture || !_texture->isLoaded() || color.a == 0.0f) {
return;
}
@ -129,28 +112,28 @@ void ImageEntityRenderer::doRender(RenderArgs* args) {
transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, args->getViewFrustum().getPosition()));
batch->setModelTransform(transform);
batch->setResourceTexture(0, texture->getGPUTexture());
batch->setResourceTexture(0, _texture->getGPUTexture());
float imageWidth = texture->getWidth();
float imageHeight = texture->getHeight();
float imageWidth = _texture->getWidth();
float imageHeight = _texture->getHeight();
QRect fromImage;
if (subImage.width() <= 0) {
if (_subImage.width() <= 0) {
fromImage.setX(0);
fromImage.setWidth(imageWidth);
} else {
float scaleX = imageWidth / texture->getOriginalWidth();
fromImage.setX(scaleX * subImage.x());
fromImage.setWidth(scaleX * subImage.width());
float scaleX = imageWidth / _texture->getOriginalWidth();
fromImage.setX(scaleX * _subImage.x());
fromImage.setWidth(scaleX * _subImage.width());
}
if (subImage.height() <= 0) {
if (_subImage.height() <= 0) {
fromImage.setY(0);
fromImage.setHeight(imageHeight);
} else {
float scaleY = imageHeight / texture->getOriginalHeight();
fromImage.setY(scaleY * subImage.y());
fromImage.setHeight(scaleY * subImage.height());
float scaleY = imageHeight / _texture->getOriginalHeight();
fromImage.setY(scaleY * _subImage.y());
fromImage.setHeight(scaleY * _subImage.height());
}
float maxSize = glm::max(fromImage.width(), fromImage.height());

View file

@ -29,8 +29,8 @@ protected:
bool isTransparent() const override;
private:
virtual bool needsRenderUpdate() const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override;
QString _imageURL;

View file

@ -16,197 +16,177 @@
using namespace render;
using namespace render::entities;
bool MaterialEntityRenderer::needsRenderUpdate() const {
if (_retryApply) {
return true;
}
if (!_texturesLoaded) {
return true;
}
return Parent::needsRenderUpdate();
}
bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
if (resultWithReadLock<bool>([&] {
if (entity->getTransform() != _transform) {
return true;
}
if (entity->getUnscaledDimensions() != _dimensions) {
return true;
}
if (entity->getParentID() != _parentID) {
return true;
}
return false;
})) {
return true;
}
return false;
void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
void* key = (void*)this;
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
withWriteLock([&] {
_renderTransform = getModelTransform();
// Material entities should fit inside a cube entity of the same size, so a sphere that has dimensions 1x1x1
// is a half unit sphere. However, the geometry cache renders a UNIT sphere, so we need to scale down.
const float MATERIAL_ENTITY_SCALE = 0.5f;
_renderTransform.postScale(MATERIAL_ENTITY_SCALE);
_renderTransform.postScale(ENTITY_ITEM_DEFAULT_DIMENSIONS);
});
});
}
void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
withWriteLock([&] {
bool deleteNeeded = false;
bool addNeeded = _retryApply;
bool transformChanged = false;
{
MaterialMappingMode mode = entity->getMaterialMappingMode();
if (mode != _materialMappingMode) {
_materialMappingMode = mode;
transformChanged = true;
}
bool deleteNeeded = false;
bool addNeeded = _retryApply;
bool transformChanged = false;
{
MaterialMappingMode mode = entity->getMaterialMappingMode();
if (mode != _materialMappingMode) {
_materialMappingMode = mode;
transformChanged = true;
}
{
bool repeat = entity->getMaterialRepeat();
if (repeat != _materialRepeat) {
_materialRepeat = repeat;
transformChanged = true;
}
}
{
bool repeat = entity->getMaterialRepeat();
if (repeat != _materialRepeat) {
_materialRepeat = repeat;
transformChanged = true;
}
{
glm::vec2 mappingPos = entity->getMaterialMappingPos();
glm::vec2 mappingScale = entity->getMaterialMappingScale();
float mappingRot = entity->getMaterialMappingRot();
if (mappingPos != _materialMappingPos || mappingScale != _materialMappingScale || mappingRot != _materialMappingRot) {
_materialMappingPos = mappingPos;
_materialMappingScale = mappingScale;
_materialMappingRot = mappingRot;
transformChanged |= _materialMappingMode == MaterialMappingMode::UV;
}
}
{
glm::vec2 mappingPos = entity->getMaterialMappingPos();
glm::vec2 mappingScale = entity->getMaterialMappingScale();
float mappingRot = entity->getMaterialMappingRot();
if (mappingPos != _materialMappingPos || mappingScale != _materialMappingScale || mappingRot != _materialMappingRot) {
_materialMappingPos = mappingPos;
_materialMappingScale = mappingScale;
_materialMappingRot = mappingRot;
transformChanged |= _materialMappingMode == MaterialMappingMode::UV;
}
{
Transform transform = entity->getTransform();
glm::vec3 dimensions = entity->getUnscaledDimensions();
if (transform != _transform || dimensions != _dimensions) {
_transform = transform;
_dimensions = dimensions;
transformChanged |= _materialMappingMode == MaterialMappingMode::PROJECTED;
}
}
{
Transform transform = entity->getTransform();
glm::vec3 dimensions = entity->getUnscaledDimensions();
if (transform != _transform || dimensions != _dimensions) {
_transform = transform;
_dimensions = dimensions;
transformChanged |= _materialMappingMode == MaterialMappingMode::PROJECTED;
}
}
{
auto material = getMaterial();
// Update the old material regardless of if it's going to change
if (transformChanged && material && !_parentID.isNull()) {
deleteNeeded = true;
addNeeded = true;
applyTextureTransform(material);
}
{
auto material = getMaterial();
// Update the old material regardless of if it's going to change
if (transformChanged && material && !_parentID.isNull()) {
deleteNeeded = true;
addNeeded = true;
applyTextureTransform(material);
}
}
bool urlChanged = false;
std::string newCurrentMaterialName = _currentMaterialName;
{
QString materialURL = entity->getMaterialURL();
if (materialURL != _materialURL) {
_materialURL = materialURL;
if (_materialURL.contains("#")) {
auto split = _materialURL.split("#");
newCurrentMaterialName = split.last().toStdString();
} else if (_materialURL.contains("?")) {
qDebug() << "DEPRECATED: Use # instead of ? for material URLS:" << _materialURL;
auto split = _materialURL.split("?");
newCurrentMaterialName = split.last().toStdString();
}
urlChanged = true;
bool urlChanged = false;
std::string newCurrentMaterialName = _currentMaterialName;
{
QString materialURL = entity->getMaterialURL();
if (materialURL != _materialURL) {
_materialURL = materialURL;
if (_materialURL.contains("#")) {
auto split = _materialURL.split("#");
newCurrentMaterialName = split.last().toStdString();
} else if (_materialURL.contains("?")) {
qDebug() << "DEPRECATED: Use # instead of ? for material URLS:" << _materialURL;
auto split = _materialURL.split("?");
newCurrentMaterialName = split.last().toStdString();
}
urlChanged = true;
}
}
bool usingMaterialData = _materialURL.startsWith("materialData");
bool materialDataChanged = false;
QUuid oldParentID = _parentID;
QString oldParentMaterialName = _parentMaterialName;
{
QString materialData = entity->getMaterialData();
if (materialData != _materialData) {
_materialData = materialData;
if (usingMaterialData) {
materialDataChanged = true;
}
bool usingMaterialData = _materialURL.startsWith("materialData");
bool materialDataChanged = false;
QUuid oldParentID = _parentID;
QString oldParentMaterialName = _parentMaterialName;
{
QString materialData = entity->getMaterialData();
if (materialData != _materialData) {
_materialData = materialData;
if (usingMaterialData) {
materialDataChanged = true;
}
}
{
QString parentMaterialName = entity->getParentMaterialName();
if (parentMaterialName != _parentMaterialName) {
_parentMaterialName = parentMaterialName;
deleteNeeded = true;
addNeeded = true;
}
}
{
QString parentMaterialName = entity->getParentMaterialName();
if (parentMaterialName != _parentMaterialName) {
_parentMaterialName = parentMaterialName;
deleteNeeded = true;
addNeeded = true;
}
{
QUuid parentID = entity->getParentID();
if (parentID != _parentID) {
_parentID = parentID;
deleteNeeded = true;
addNeeded = true;
}
}
{
QUuid parentID = entity->getParentID();
if (parentID != _parentID) {
_parentID = parentID;
deleteNeeded = true;
addNeeded = true;
}
{
quint16 priority = entity->getPriority();
if (priority != _priority) {
_priority = priority;
deleteNeeded = true;
addNeeded = true;
}
}
{
quint16 priority = entity->getPriority();
if (priority != _priority) {
_priority = priority;
deleteNeeded = true;
addNeeded = true;
}
}
if (urlChanged && !usingMaterialData) {
_networkMaterial = DependencyManager::get<MaterialCache>()->getMaterial(_materialURL);
auto onMaterialRequestFinished = [this, entity, oldParentID, oldParentMaterialName, newCurrentMaterialName](bool success) {
if (success) {
deleteMaterial(oldParentID, oldParentMaterialName);
_texturesLoaded = false;
_parsedMaterials = _networkMaterial->parsedMaterials;
setCurrentMaterialName(newCurrentMaterialName);
applyMaterial(entity);
} else {
deleteMaterial(oldParentID, oldParentMaterialName);
_retryApply = false;
_texturesLoaded = true;
}
};
if (_networkMaterial) {
if (_networkMaterial->isLoaded()) {
onMaterialRequestFinished(!_networkMaterial->isFailed());
} else {
connect(_networkMaterial.data(), &Resource::finished, this, [this, onMaterialRequestFinished](bool success) {
withWriteLock([&] {
onMaterialRequestFinished(success);
});
});
}
}
} else if (materialDataChanged && usingMaterialData) {
if (urlChanged && !usingMaterialData) {
_networkMaterial = DependencyManager::get<MaterialCache>()->getMaterial(_materialURL);
auto onMaterialRequestFinished = [this, entity, oldParentID, oldParentMaterialName, newCurrentMaterialName](bool success) {
deleteMaterial(oldParentID, oldParentMaterialName);
_texturesLoaded = false;
_parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(_materialData.toUtf8()), _materialURL);
// Since our material changed, the current name might not be valid anymore, so we need to update
setCurrentMaterialName(newCurrentMaterialName);
applyMaterial(entity);
} else {
if (deleteNeeded) {
deleteMaterial(oldParentID, oldParentMaterialName);
}
if (addNeeded) {
if (success) {
_texturesLoaded = false;
_parsedMaterials = _networkMaterial->parsedMaterials;
setCurrentMaterialName(newCurrentMaterialName);
applyMaterial(entity);
emit requestRenderUpdate();
} else {
_retryApply = false;
_texturesLoaded = true;
}
};
if (_networkMaterial) {
if (_networkMaterial->isLoaded()) {
onMaterialRequestFinished(!_networkMaterial->isFailed());
} else {
connect(_networkMaterial.data(), &Resource::finished, this, [this, onMaterialRequestFinished](bool success) {
onMaterialRequestFinished(success);
});
}
}
{
auto material = getMaterial();
bool newTexturesLoaded = material ? !material->isMissingTexture() : false;
if (!_texturesLoaded && newTexturesLoaded) {
material->checkResetOpacityMap();
}
_texturesLoaded = newTexturesLoaded;
} else if (materialDataChanged && usingMaterialData) {
deleteMaterial(oldParentID, oldParentMaterialName);
_texturesLoaded = false;
_parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(_materialData.toUtf8()), _materialURL);
// Since our material changed, the current name might not be valid anymore, so we need to update
setCurrentMaterialName(newCurrentMaterialName);
applyMaterial(entity);
} else {
if (deleteNeeded) {
deleteMaterial(oldParentID, oldParentMaterialName);
}
if (addNeeded) {
applyMaterial(entity);
}
}
_renderTransform = getModelTransform();
const float MATERIAL_ENTITY_SCALE = 0.5f;
_renderTransform.postScale(MATERIAL_ENTITY_SCALE);
_renderTransform.postScale(ENTITY_ITEM_DEFAULT_DIMENSIONS);
});
{
auto material = getMaterial();
bool newTexturesLoaded = material ? !material->isMissingTexture() : false;
if (!_texturesLoaded && newTexturesLoaded) {
material->checkResetOpacityMap();
}
_texturesLoaded = newTexturesLoaded;
}
if (!_texturesLoaded || _retryApply) {
emit requestRenderUpdate();
}
}
ItemKey MaterialEntityRenderer::getKey() {
@ -268,33 +248,30 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
gpu::Batch& batch = *args->_batch;
// Don't render if our parent is set or our material is null
QUuid parentID;
withReadLock([&] {
parentID = _parentID;
});
if (!parentID.isNull()) {
if (!_parentID.isNull()) {
return;
}
Transform renderTransform;
graphics::MaterialPointer drawMaterial;
graphics::MaterialPointer drawMaterial = getMaterial();
bool proceduralRender = false;
Transform textureTransform;
textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0));
textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialMappingRot)));
textureTransform.setScale(glm::vec3(_materialMappingScale, 1));
Transform renderTransform;
withReadLock([&] {
renderTransform = _renderTransform;
drawMaterial = getMaterial();
textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0));
textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialMappingRot)));
textureTransform.setScale(glm::vec3(_materialMappingScale, 1));
if (drawMaterial && drawMaterial->isProcedural() && drawMaterial->isReady()) {
proceduralRender = true;
}
});
if (!drawMaterial) {
return;
}
if (drawMaterial->isProcedural() && drawMaterial->isReady()) {
proceduralRender = true;
}
batch.setModelTransform(renderTransform);
if (!proceduralRender) {

View file

@ -27,8 +27,7 @@ public:
~MaterialEntityRenderer() { deleteMaterial(_parentID, _parentMaterialName); }
private:
virtual bool needsRenderUpdate() const override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override;

View file

@ -51,12 +51,6 @@ ModelPointer ModelEntityWrapper::getModel() const {
});
}
bool ModelEntityWrapper::isModelLoaded() const {
return resultWithReadLock<bool>([&] {
return _model.operator bool() && _model->isLoaded();
});
}
EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItemPointer entity(new RenderableModelEntityItem(entityID, properties.getDimensionsInitialized()),
[](EntityItem* ptr) { ptr->deleteLater(); });
@ -69,8 +63,7 @@ EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityI
RenderableModelEntityItem::RenderableModelEntityItem(const EntityItemID& entityItemID, bool dimensionsInitialized) :
ModelEntityWrapper(entityItemID),
_dimensionsInitialized(dimensionsInitialized) {
}
RenderableModelEntityItem::~RenderableModelEntityItem() { }
@ -83,34 +76,6 @@ void RenderableModelEntityItem::setUnscaledDimensions(const glm::vec3& value) {
}
}
void RenderableModelEntityItem::doInitialModelSimulation() {
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
ModelPointer model = getModel();
if (!model) {
return;
}
// The machinery for updateModelBounds will give existing models the opportunity to fix their
// translation/rotation/scale/registration. The first two are straightforward, but the latter two have guards to
// make sure they don't happen after they've already been set. Here we reset those guards. This doesn't cause the
// entity values to change -- it just allows the model to match once it comes in.
model->setScaleToFit(false, getScaledDimensions());
model->setSnapModelToRegistrationPoint(false, getRegistrationPoint());
// now recalculate the bounds and registration
model->setScaleToFit(true, getScaledDimensions());
model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
model->setRotation(getWorldOrientation());
model->setTranslation(getWorldPosition());
glm::vec3 scale = model->getScale();
model->setUseDualQuaternionSkinning(!isNonUniformScale(scale));
if (_needsInitialSimulation) {
model->simulate(0.0f);
_needsInitialSimulation = false;
}
}
void RenderableModelEntityItem::autoResizeJointArrays() {
ModelPointer model = getModel();
if (model && model->isLoaded() && !_needsInitialSimulation) {
@ -125,7 +90,7 @@ bool RenderableModelEntityItem::needsUpdateModelBounds() const {
return false;
}
if (!_dimensionsInitialized || !model->isActive()) {
if (!_dimensionsInitialized || !model->isLoaded()) {
return false;
}
@ -182,22 +147,25 @@ void RenderableModelEntityItem::updateModelBounds() {
}
bool overridingModelTransform = model->isOverridingModelTransformAndOffset();
glm::vec3 scaledDimensions = getScaledDimensions();
glm::vec3 registrationPoint = getRegistrationPoint();
if (!overridingModelTransform &&
(model->getScaleToFitDimensions() != getScaledDimensions() ||
model->getRegistrationPoint() != getRegistrationPoint() ||
!model->getIsScaledToFit())) {
(model->getScaleToFitDimensions() != scaledDimensions ||
model->getRegistrationPoint() != registrationPoint ||
!model->getIsScaledToFit() || _needsToRescaleModel)) {
// The machinery for updateModelBounds will give existing models the opportunity to fix their
// translation/rotation/scale/registration. The first two are straightforward, but the latter two
// have guards to make sure they don't happen after they've already been set. Here we reset those guards.
// This doesn't cause the entity values to change -- it just allows the model to match once it comes in.
model->setScaleToFit(false, getScaledDimensions());
model->setSnapModelToRegistrationPoint(false, getRegistrationPoint());
model->setScaleToFit(false, scaledDimensions);
model->setSnapModelToRegistrationPoint(false, registrationPoint);
// now recalculate the bounds and registration
model->setScaleToFit(true, getScaledDimensions());
model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
model->setScaleToFit(true, scaledDimensions);
model->setSnapModelToRegistrationPoint(true, registrationPoint);
updateRenderItems = true;
model->scaleToFit();
_needsToRescaleModel = false;
}
bool success;
@ -221,6 +189,9 @@ void RenderableModelEntityItem::updateModelBounds() {
glm::vec3 scale = model->getScale();
model->setUseDualQuaternionSkinning(!isNonUniformScale(scale));
model->updateRenderItems();
markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
locationChanged();
}
}
@ -248,8 +219,6 @@ EntityItemProperties RenderableModelEntityItem::getProperties(const EntityProper
}
}
return properties;
}
@ -261,7 +230,7 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori
OctreeElementPointer& element, float& distance, BoxFace& face,
glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const {
auto model = getModel();
if (!model || !isModelLoaded()) {
if (!model || !model->isLoaded()) {
return false;
}
@ -273,7 +242,7 @@ bool RenderableModelEntityItem::findDetailedParabolaIntersection(const glm::vec3
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance, BoxFace& face,
glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const {
auto model = getModel();
if (!model || !isModelLoaded()) {
if (!model || !model->isLoaded()) {
return false;
}
@ -281,8 +250,23 @@ bool RenderableModelEntityItem::findDetailedParabolaIntersection(const glm::vec3
face, surfaceNormal, extraInfo, precisionPicking, false);
}
QString RenderableModelEntityItem::getCollisionShapeURL() const {
return getShapeType() == SHAPE_TYPE_COMPOUND ? getCompoundShapeURL() : getModelURL();
}
void RenderableModelEntityItem::fetchCollisionGeometryResource() {
_collisionGeometryResource = DependencyManager::get<ModelCache>()->getCollisionGeometryResource(getCollisionShapeURL());
if (_collisionGeometryResource) {
if (_collisionGeometryResource->isLoaded()) {
markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
locationChanged();
} else {
connect(_collisionGeometryResource.get(), &GeometryResource::finished, this, [&] {
markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
locationChanged();
});
}
}
}
bool RenderableModelEntityItem::unableToLoadCollisionShape() {
@ -299,7 +283,7 @@ void RenderableModelEntityItem::setShapeType(ShapeType type) {
if (!_collisionGeometryResource && !getCollisionShapeURL().isEmpty()) {
fetchCollisionGeometryResource();
}
} else if (_collisionGeometryResource && !getCompoundShapeURL().isEmpty()) {
} else if (_collisionGeometryResource) {
// the compoundURL has been set but the shapeType does not agree
_collisionGeometryResource.reset();
}
@ -308,49 +292,43 @@ void RenderableModelEntityItem::setShapeType(ShapeType type) {
void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) {
auto currentCompoundShapeURL = getCompoundShapeURL();
ModelEntityItem::setCompoundShapeURL(url);
if (getCompoundShapeURL() != currentCompoundShapeURL || !getModel()) {
if (getShapeType() == SHAPE_TYPE_COMPOUND) {
if (url != currentCompoundShapeURL && !url.isEmpty()) {
auto shapeType = getShapeType();
if (shapeType == SHAPE_TYPE_COMPOUND) {
fetchCollisionGeometryResource();
}
}
}
void RenderableModelEntityItem::setModelURL(const QString& url) {
auto currentModelURL = getModelURL();
ModelEntityItem::setModelURL(url);
if (url != currentModelURL && !url.isEmpty()) {
auto shapeType = getShapeType();
if (shapeType == SHAPE_TYPE_SIMPLE_COMPOUND) {
fetchCollisionGeometryResource();
}
}
}
bool RenderableModelEntityItem::isReadyToComputeShape() const {
ShapeType type = getShapeType();
auto model = getModel();
auto shapeType = getShapeType();
if (shapeType == SHAPE_TYPE_COMPOUND || shapeType == SHAPE_TYPE_SIMPLE_COMPOUND) {
auto shapeURL = getCollisionShapeURL();
if (!model || shapeURL.isEmpty()) {
return false;
}
if (model->getURL().isEmpty() || !_dimensionsInitialized) {
// we need a render geometry with a scale to proceed, so give up.
return false;
}
if (model->isLoaded()) {
if (!shapeURL.isEmpty() && !_collisionGeometryResource) {
// we need a render geometry with a scale to proceed
if (model && !model->getURL().isEmpty() && !shapeURL.isEmpty() && _dimensionsInitialized && model->isLoaded()) {
if (!_collisionGeometryResource) {
const_cast<RenderableModelEntityItem*>(this)->fetchCollisionGeometryResource();
}
if (_collisionGeometryResource && _collisionGeometryResource->isLoaded()) {
// we have both URLs AND both geometries AND they are both fully loaded.
if (_needsInitialSimulation) {
// the _model's offset will be wrong until _needsInitialSimulation is false
DETAILED_PERFORMANCE_TIMER("_model->simulate");
const_cast<RenderableModelEntityItem*>(this)->doInitialModelSimulation();
}
return true;
}
// do we have both URLs AND both geometries AND they are both fully loaded?
return _collisionGeometryResource && _collisionGeometryResource->isLoaded() && _collisionGeometryResource->isHFMModelLoaded();
}
// the model is still being downloaded.
return false;
} else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) {
return isModelLoaded();
} else if (shapeType >= SHAPE_TYPE_SIMPLE_HULL && shapeType <= SHAPE_TYPE_STATIC_MESH) {
return model && model->isLoaded() && _dimensionsInitialized;
}
return true;
}
@ -362,20 +340,31 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
ShapeType type = getShapeType();
auto model = getModel();
if (!model || !model->isLoaded()) {
type = SHAPE_TYPE_NONE;
if (type >= SHAPE_TYPE_COMPOUND && type <= SHAPE_TYPE_STATIC_MESH) {
if (!model) {
type = SHAPE_TYPE_NONE;
} else if (!model->isLoaded()) {
type = SHAPE_TYPE_NONE;
if (!model->didVisualGeometryRequestFail()) {
markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
locationChanged();
}
}
}
if (type == SHAPE_TYPE_COMPOUND || type == SHAPE_TYPE_SIMPLE_COMPOUND) {
if (!_collisionGeometryResource || !_collisionGeometryResource->isLoaded() || !_collisionGeometryResource->isHFMModelLoaded()) {
type = SHAPE_TYPE_NONE;
if (!_collisionGeometryResource->isFailed()) {
markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
locationChanged();
}
}
}
if (type == SHAPE_TYPE_COMPOUND) {
if (!_collisionGeometryResource || !_collisionGeometryResource->isLoaded()) {
return;
}
updateModelBounds();
// should never fall in here when collision model not fully loaded
// TODO: assert that all geometries exist and are loaded
//assert(_model && _model->isLoaded() && _collisionGeometryResource && _collisionGeometryResource->isLoaded());
const HFMModel& collisionGeometry = _collisionGeometryResource->getHFMModel();
ShapeInfo::PointCollection& pointCollection = shapeInfo.getPointCollection();
@ -452,7 +441,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
// collision model's extents).
glm::vec3 dimensions = getScaledDimensions();
glm::vec3 scaleToFit = dimensions / model->getHFMModel().getUnscaledMeshExtents().size();
glm::vec3 extents = model->getHFMModel().getUnscaledMeshExtents().size();
glm::vec3 scaleToFit = dimensions / extents;
// multiply each point by scale before handing the point-set off to the physics engine.
// also determine the extents of the collision model.
glm::vec3 registrationOffset = dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint());
@ -462,12 +452,10 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
pointCollection[i][j] = scaleToFit * (pointCollection[i][j] + model->getOffset()) - registrationOffset;
}
}
shapeInfo.setParams(type, dimensions, getCompoundShapeURL());
shapeInfo.setParams(type, 0.5f * extents, getCompoundShapeURL());
adjustShapeInfoByRegistration(shapeInfo);
} else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) {
updateModelBounds();
// assert we never fall in here when model not fully loaded
assert(model && model->isLoaded());
model->updateGeometry();
// compute meshPart local transforms
@ -476,16 +464,16 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
int numHFMMeshes = hfmModel.meshes.size();
int totalNumVertices = 0;
glm::vec3 dimensions = getScaledDimensions();
glm::mat4 invRegistraionOffset = glm::translate(dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT));
glm::mat4 invRegistrationOffset = glm::translate(dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT));
for (int i = 0; i < numHFMMeshes; i++) {
const HFMMesh& mesh = hfmModel.meshes.at(i);
if (mesh.clusters.size() > 0) {
const HFMCluster& cluster = mesh.clusters.at(0);
auto jointMatrix = model->getRig().getJointTransform(cluster.jointIndex);
// we backtranslate by the registration offset so we can apply that offset to the shapeInfo later
localTransforms.push_back(invRegistraionOffset * jointMatrix * cluster.inverseBindMatrix);
localTransforms.push_back(invRegistrationOffset * jointMatrix * cluster.inverseBindMatrix);
} else {
localTransforms.push_back(invRegistraionOffset);
localTransforms.push_back(invRegistrationOffset);
}
totalNumVertices += mesh.vertices.size();
}
@ -697,7 +685,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
}
}
shapeInfo.setParams(type, 0.5f * dimensions, getModelURL());
shapeInfo.setParams(type, 0.5f * extents.size(), getModelURL());
adjustShapeInfoByRegistration(shapeInfo);
} else {
EntityItem::computeShapeInfo(shapeInfo);
@ -716,8 +704,8 @@ void RenderableModelEntityItem::setJointMap(std::vector<int> jointMap) {
int RenderableModelEntityItem::avatarJointIndex(int modelJointIndex) {
int result = -1;
int mapSize = (int) _jointMap.size();
if (modelJointIndex >=0 && modelJointIndex < mapSize) {
int mapSize = (int)_jointMap.size();
if (modelJointIndex >= 0 && modelJointIndex < mapSize) {
result = _jointMap[modelJointIndex];
}
@ -726,28 +714,44 @@ int RenderableModelEntityItem::avatarJointIndex(int modelJointIndex) {
bool RenderableModelEntityItem::contains(const glm::vec3& point) const {
auto model = getModel();
if (EntityItem::contains(point) && model && _collisionGeometryResource && _collisionGeometryResource->isLoaded()) {
glm::mat4 worldToHFMMatrix = model->getWorldToHFMMatrix();
glm::vec3 hfmPoint = worldToHFMMatrix * glm::vec4(point, 1.0f);
return _collisionGeometryResource->getHFMModel().convexHullContains(hfmPoint);
if (model && model->isLoaded()) {
auto shapeType = getShapeType();
if (shapeType == SHAPE_TYPE_COMPOUND || shapeType == SHAPE_TYPE_SIMPLE_COMPOUND) {
if (_collisionGeometryResource && _collisionGeometryResource->isLoaded() && _collisionGeometryResource->isHFMModelLoaded() && EntityItem::contains(point)) {
glm::mat4 worldToHFMMatrix = model->getWorldToHFMMatrix();
glm::vec3 hfmPoint = worldToHFMMatrix * glm::vec4(point, 1.0f);
return _collisionGeometryResource->getHFMModel().convexHullContains(hfmPoint);
}
} else if (shapeType >= SHAPE_TYPE_SIMPLE_HULL && shapeType <= SHAPE_TYPE_STATIC_MESH) {
if (EntityItem::contains(point)) {
glm::mat4 worldToHFMMatrix = model->getWorldToHFMMatrix();
glm::vec3 hfmPoint = worldToHFMMatrix * glm::vec4(point, 1.0f);
return model->getHFMModel().convexHullContains(hfmPoint);
}
} else {
return EntityItem::contains(point);
}
}
return false;
}
bool RenderableModelEntityItem::shouldBePhysical() const {
auto model = getModel();
// If we have a model, make sure it hasn't failed to download.
// If it has, we'll report back that we shouldn't be physical so that physics aren't held waiting for us to be ready.
bool physicalModelLoaded = false;
ShapeType shapeType = getShapeType();
if (model) {
if ((shapeType == SHAPE_TYPE_COMPOUND || shapeType == SHAPE_TYPE_SIMPLE_COMPOUND) && model->didCollisionGeometryRequestFail()) {
return false;
} else if (shapeType != SHAPE_TYPE_NONE && model->didVisualGeometryRequestFail()) {
return false;
if (shapeType >= SHAPE_TYPE_COMPOUND && shapeType <= SHAPE_TYPE_STATIC_MESH) {
auto model = getModel();
// If we have a model, make sure it hasn't failed to download.
// If it has, we'll report back that we shouldn't be physical so that physics aren't held waiting for us to be ready.
physicalModelLoaded = model && !model->didVisualGeometryRequestFail();
if (shapeType == SHAPE_TYPE_COMPOUND || shapeType == SHAPE_TYPE_SIMPLE_COMPOUND) {
physicalModelLoaded &= _collisionGeometryResource && !_collisionGeometryResource->isFailed();
}
} else if (shapeType != SHAPE_TYPE_NONE) {
physicalModelLoaded = true;
}
return !isDead() && shapeType != SHAPE_TYPE_NONE && !isLocalEntity() && QUrl(_modelURL).isValid();
return physicalModelLoaded && !isDead() && !isLocalEntity() && QUrl(getModelURL()).isValid();
}
int RenderableModelEntityItem::getJointParent(int index) const {
@ -943,13 +947,13 @@ void RenderableModelEntityItem::locationChanged(bool tellPhysics, bool tellChild
int RenderableModelEntityItem::getJointIndex(const QString& name) const {
auto model = getModel();
return (model && model->isActive()) ? model->getRig().indexOfJoint(name) : -1;
return (model && model->isLoaded()) ? model->getRig().indexOfJoint(name) : -1;
}
QStringList RenderableModelEntityItem::getJointNames() const {
QStringList result;
auto model = getModel();
if (model && model->isActive()) {
if (model && model->isLoaded()) {
const Rig& rig = model->getRig();
int jointCount = rig.getJointStateCount();
for (int jointIndex = 0; jointIndex < jointCount; jointIndex++) {
@ -960,13 +964,13 @@ QStringList RenderableModelEntityItem::getJointNames() const {
}
scriptable::ScriptableModelBase render::entities::ModelEntityRenderer::getScriptableModel() {
auto model = resultWithReadLock<ModelPointer>([this]{ return _model; });
auto model = resultWithReadLock<ModelPointer>([&] { return _model; });
if (!model || !model->isLoaded()) {
return scriptable::ScriptableModelBase();
}
auto result = _model->getScriptableModel();
auto result = model->getScriptableModel();
result.objectID = getEntity()->getID();
{
std::lock_guard<std::mutex> lock(_materialsLock);
@ -1036,7 +1040,7 @@ void RenderableModelEntityItem::copyAnimationJointDataToModel() {
});
if (changed) {
locationChanged(true, true);
locationChanged();
}
}
@ -1054,10 +1058,14 @@ ModelEntityRenderer::ModelEntityRenderer(const EntityItemPointer& entity) : Pare
}
void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed) {
void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed, const ModelPointer& model) {
auto builder = ItemKey::Builder().withTypeMeta().withTagBits(getTagMask()).withLayer(getHifiRenderLayer());
if (!_cullWithParent && _model && _model->isGroupCulled()) {
if (!_visible) {
builder.withInvisible();
}
if (!_cullWithParent && model && model->isGroupCulled()) {
builder.withMetaCullGroup();
} else if (_cullWithParent) {
builder.withSubMetaCulled();
@ -1075,8 +1083,9 @@ ItemKey ModelEntityRenderer::getKey() {
}
uint32_t ModelEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) const {
if (_model) {
auto metaSubItems = _model->fetchRenderItemIDs();
auto model = resultWithReadLock<ModelPointer>([&] { return _model; });
if (model) {
auto metaSubItems = model->fetchRenderItemIDs();
subItems.insert(subItems.end(), metaSubItems.begin(), metaSubItems.end());
return (uint32_t)metaSubItems.size();
}
@ -1089,8 +1098,9 @@ void ModelEntityRenderer::handleBlendedVertices(int blendshapeNumber, const QVec
}
void ModelEntityRenderer::removeFromScene(const ScenePointer& scene, Transaction& transaction) {
if (_model) {
_model->removeFromScene(scene, transaction);
auto model = resultWithReadLock<ModelPointer>([&] { return _model; });
if (model) {
model->removeFromScene(scene, transaction);
}
Parent::removeFromScene(scene, transaction);
}
@ -1099,14 +1109,14 @@ void ModelEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entit
entity->setModel({});
}
void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
void ModelEntityRenderer::animate(const TypedEntityPointer& entity, const ModelPointer& model) {
if (!_animation || !_animation->isLoaded()) {
return;
}
QVector<EntityJointData> jointsData;
const QVector<HFMAnimationFrame>& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy
const QVector<HFMAnimationFrame>& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy
int frameCount = frames.size();
if (frameCount <= 0) {
return;
@ -1124,17 +1134,17 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
_lastKnownCurrentFrame = currentIntegerFrame;
}
if (_jointMapping.size() != _model->getJointStateCount()) {
if (_jointMapping.size() != model->getJointStateCount()) {
qCWarning(entitiesrenderer) << "RenderableModelEntityItem::getAnimationFrame -- joint count mismatch"
<< _jointMapping.size() << _model->getJointStateCount();
<< _jointMapping.size() << model->getJointStateCount();
return;
}
QStringList animationJointNames = _animation->getHFMModel().getJointNames();
auto& hfmJoints = _animation->getHFMModel().joints;
auto& originalHFMJoints = _model->getHFMModel().joints;
auto& originalHFMIndices = _model->getHFMModel().jointIndices;
auto& originalHFMJoints = model->getHFMModel().joints;
auto& originalHFMIndices = model->getHFMModel().jointIndices;
bool allowTranslation = entity->getAnimationAllowTranslation();
@ -1182,146 +1192,49 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
entity->copyAnimationJointDataToModel();
}
bool ModelEntityRenderer::needsRenderUpdate() const {
if (resultWithReadLock<bool>([&] {
if (_moving || _animating) {
return true;
}
if (!_texturesLoaded) {
return true;
}
if (!_prevModelLoaded) {
return true;
}
return false;
})) {
bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
if (entity->blendshapesChanged()) {
return true;
}
ModelPointer model;
QUrl parsedModelURL;
withReadLock([&] {
model = _model;
parsedModelURL = _parsedModelURL;
});
if (model) {
// When the individual mesh parts of a model finish fading, they will mark their Model as needing updating
// we will watch for that and ask the model to update it's render items
if (parsedModelURL != model->getURL()) {
return true;
}
if (model->needsReload()) {
return true;
}
if (model->needsFixupInScene()) {
return true;
}
if (model->getRenderItemsNeedUpdate()) {
return true;
}
}
return Parent::needsRenderUpdate();
}
bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
if (resultWithReadLock<bool>([&] {
if (entity->hasModel() != _hasModel) {
return true;
}
// No model to render, early exit
if (!_hasModel) {
return false;
}
if (_animating != entity->isAnimatingSomething()) {
return true;
}
return false;
})) { return true; }
ModelPointer model;
withReadLock([&] {
model = _model;
});
if (model && model->isLoaded()) {
if (!entity->_dimensionsInitialized || entity->_needsInitialSimulation || !entity->_originalTexturesRead) {
return true;
}
if (entity->blendshapesChanged()) {
return true;
}
// Check to see if we need to update the model bounds
if (entity->needsUpdateModelBounds()) {
return true;
}
// Check to see if we need to update the model bounds
auto transform = entity->getTransform();
if (model->getTranslation() != transform.getTranslation() ||
model->getRotation() != transform.getRotation()) {
return true;
}
if (model->getScaleToFitDimensions() != entity->getScaledDimensions() ||
model->getRegistrationPoint() != entity->getRegistrationPoint()) {
return true;
}
// Check to see if we need to update the model bounds
if (entity->needsUpdateModelBounds()) {
return true;
}
return false;
return Parent::needsRenderUpdateFromTypedEntity(entity);
}
void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
if (_hasModel != entity->hasModel()) {
withWriteLock([&] {
_hasModel = entity->hasModel();
});
_hasModel = entity->hasModel();
QUrl modelURL = QUrl(entity->getModelURL());
if (_parsedModelURL != modelURL) {
_parsedModelURL = modelURL;
}
withWriteLock([&] {
_animating = entity->isAnimatingSomething();
if (_parsedModelURL != entity->getModelURL()) {
_parsedModelURL = QUrl(entity->getModelURL());
}
ModelPointer model = resultWithReadLock<ModelPointer>([&] {
return _model;
});
ModelPointer model;
withReadLock([&] { model = _model; });
bool visuallyReady = model && model->isLoaded() && _didLastVisualGeometryRequestSucceed && _texturesLoaded;
entity->setVisuallyReady(visuallyReady);
withWriteLock([&] {
bool visuallyReady = true;
if (_hasModel) {
if (model && _didLastVisualGeometryRequestSucceed) {
visuallyReady = (_prevModelLoaded && _texturesLoaded);
}
}
entity->setVisuallyReady(visuallyReady);
});
const render::ScenePointer& scene = AbstractViewStateInterface::instance()->getMain3DScene();
render::Transaction transaction;
// Check for removal
if (!_hasModel) {
if (model) {
model->removeFromScene(scene, transaction);
entity->bumpAncestorChainRenderableVersion();
withWriteLock([&] { _model.reset(); });
emit DependencyManager::get<scriptable::ModelProviderFactory>()->
modelRemovedFromScene(entity->getEntityItemID(), NestableType::Entity, _model);
modelRemovedFromScene(entity->getEntityItemID(), NestableType::Entity, model);
withWriteLock([&] { _model.reset(); });
}
setKey(false);
_didLastVisualGeometryRequestSucceed = false;
setKey(_didLastVisualGeometryRequestSucceed, model);
return;
}
@ -1330,48 +1243,52 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
model = std::make_shared<Model>(nullptr, entity.get(), _created);
connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate);
connect(model.get(), &Model::setURLFinished, this, [&](bool didVisualGeometryRequestSucceed) {
setKey(didVisualGeometryRequestSucceed);
_model->setTagMask(getTagMask());
_model->setHifiRenderLayer(getHifiRenderLayer());
_model->setPrimitiveMode(_primitiveMode);
_model->setCullWithParent(_cullWithParent);
_model->setRenderWithZones(_renderWithZones);
emit requestRenderUpdate();
if (didVisualGeometryRequestSucceed) {
emit DependencyManager::get<scriptable::ModelProviderFactory>()->
modelAddedToScene(entity->getEntityItemID(), NestableType::Entity, _model);
}
_didLastVisualGeometryRequestSucceed = didVisualGeometryRequestSucceed;
const render::ScenePointer& scene = AbstractViewStateInterface::instance()->getMain3DScene();
render::Transaction transaction;
transaction.updateItem<PayloadProxyInterface>(_renderItemID, [&](PayloadProxyInterface& self) {
const render::ScenePointer& scene = AbstractViewStateInterface::instance()->getMain3DScene();
withWriteLock([&] {
setKey(didVisualGeometryRequestSucceed, _model);
_model->setVisibleInScene(_visible, scene);
_model->setCauterized(_cauterized, scene);
_model->setCanCastShadow(_canCastShadow, scene);
_model->setGroupCulled(entity->getGroupCulled(), scene);
_model->setTagMask(getTagMask(), scene);
_model->setHifiRenderLayer(getHifiRenderLayer(), scene);
_model->setPrimitiveMode(_primitiveMode, scene);
_model->setCullWithParent(_cullWithParent, scene);
_model->setRenderWithZones(_renderWithZones, scene);
});
if (didVisualGeometryRequestSucceed) {
emit DependencyManager::get<scriptable::ModelProviderFactory>()->
modelAddedToScene(entity->getEntityItemID(), NestableType::Entity, model);
}
entity->_originalTexturesRead = false;
entity->_needsJointSimulation = true;
entity->_needsToRescaleModel = true;
emit requestRenderUpdate();
});
scene->enqueueTransaction(transaction);
});
model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
entity->setModel(model);
withWriteLock([&] { _model = model; });
}
// From here on, we are guaranteed a populated model
if (_parsedModelURL != model->getURL()) {
withWriteLock([&] {
_texturesLoaded = false;
_jointMappingCompleted = false;
model->setURL(_parsedModelURL);
});
_texturesLoaded = false;
_jointMappingCompleted = false;
model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
model->setURL(_parsedModelURL);
}
// Nothing else to do unless the model is loaded
if (!model->isLoaded()) {
withWriteLock([&] {
_prevModelLoaded = false;
});
emit requestRenderUpdate();
return;
} else if (!_prevModelLoaded) {
withWriteLock([&] {
_prevModelLoaded = true;
});
}
// Check for initializing the model
// FIXME: There are several places below here where we are modifying the entity, which we should not be doing from the renderable
if (!entity->_dimensionsInitialized) {
EntityItemProperties properties;
properties.setLastEdited(usecTimestampNow()); // we must set the edit time since we're editing it
@ -1391,53 +1308,39 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
entity->_originalTexturesRead = true;
}
if (_textures != entity->getTextures()) {
auto textures = entity->getTextures();
if (_textures != textures) {
QVariantMap newTextures;
withWriteLock([&] {
_texturesLoaded = false;
_textures = entity->getTextures();
newTextures = parseTexturesToMap(_textures, entity->_originalTextures);
});
_texturesLoaded = false;
_textures = textures;
newTextures = parseTexturesToMap(_textures, entity->_originalTextures);
model->setTextures(newTextures);
}
if (entity->_needsJointSimulation) {
entity->copyAnimationJointDataToModel();
}
entity->updateModelBounds();
entity->stopModelOverrideIfNoParent();
if (model->isVisible() != _visible) {
withWriteLock([&] {
setKey(_didLastVisualGeometryRequestSucceed, model);
model->setVisibleInScene(_visible, scene);
}
if (model->isCauterized() != _cauterized) {
model->setCauterized(_cauterized, scene);
}
render::hifi::Tag tagMask = getTagMask();
if (model->getTagMask() != tagMask) {
model->setTagMask(tagMask, scene);
}
model->setCanCastShadow(_canCastShadow, scene);
model->setGroupCulled(entity->getGroupCulled(), scene);
model->setTagMask(getTagMask(), scene);
model->setHifiRenderLayer(getHifiRenderLayer(), scene);
model->setPrimitiveMode(_primitiveMode, scene);
model->setCullWithParent(_cullWithParent, scene);
model->setRenderWithZones(_renderWithZones, scene);
});
if (entity->blendshapesChanged()) {
model->setBlendshapeCoefficients(entity->getBlendshapeCoefficientVector());
model->updateBlendshapes();
}
// TODO? early exit here when not visible?
if (model->canCastShadow() != _canCastShadow) {
model->setCanCastShadow(_canCastShadow, scene);
}
{
bool groupCulled = entity->getGroupCulled();
if (model->isGroupCulled() != groupCulled) {
model->setGroupCulled(groupCulled);
setKey(_didLastVisualGeometryRequestSucceed);
}
}
{
DETAILED_PROFILE_RANGE(simulation_physics, "Fixup");
if (model->needsFixupInScene()) {
@ -1451,11 +1354,10 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
}
}
bool needsUpdate = false;
if (!_texturesLoaded && model->getGeometry() && model->getGeometry()->areTexturesLoaded()) {
withWriteLock([&] {
_texturesLoaded = true;
});
model->updateRenderItems();
_texturesLoaded = true;
needsUpdate = true;
} else if (!_texturesLoaded) {
emit requestRenderUpdate();
}
@ -1481,19 +1383,23 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
emit requestRenderUpdate();
} else {
_allProceduralMaterialsLoaded = true;
model->setRenderItemsNeedUpdate();
needsUpdate = true;
}
}
// When the individual mesh parts of a model finish fading, they will mark their Model as needing updating
// we will watch for that and ask the model to update it's render items
if (model->getRenderItemsNeedUpdate()) {
if (needsUpdate || model->getRenderItemsNeedUpdate()) {
model->updateRenderItems();
}
scene->enqueueTransaction(transaction);
}
void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
// The code to deal with the change of properties is now in ModelEntityItem.cpp
// That is where _currentFrame and _lastAnimated were updated.
if (_animating) {
if (entity->isAnimatingSomething()) {
DETAILED_PROFILE_RANGE(simulation_physics, "Animate");
auto animationURL = entity->getAnimationURL();
@ -1502,18 +1408,22 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
_animationURL = animationURL;
if (_animation) {
//(_animation->getURL().toString() != entity->getAnimationURL())) { // bad check
// the joints have been mapped before but we have a new animation to load
_animation.reset();
_jointMappingCompleted = false;
}
}
if (!_jointMappingCompleted) {
mapJoints(entity, model);
}
if (entity->readyToAnimate()) {
animate(entity);
ModelPointer model = resultWithReadLock<ModelPointer>([&] {
return _model;
});
if (model && model->isLoaded()) {
if (!_jointMappingCompleted) {
mapJoints(entity, model);
}
if (entity->readyToAnimate()) {
animate(entity, model);
}
}
emit requestRenderUpdate();
}
@ -1521,40 +1431,20 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
void ModelEntityRenderer::setIsVisibleInSecondaryCamera(bool value) {
Parent::setIsVisibleInSecondaryCamera(value);
setKey(_didLastVisualGeometryRequestSucceed);
if (_model) {
_model->setTagMask(getTagMask());
}
// called within a lock so no need to lock for _model
setKey(_didLastVisualGeometryRequestSucceed, _model);
}
void ModelEntityRenderer::setRenderLayer(RenderLayer value) {
Parent::setRenderLayer(value);
setKey(_didLastVisualGeometryRequestSucceed);
if (_model) {
_model->setHifiRenderLayer(getHifiRenderLayer());
}
}
void ModelEntityRenderer::setPrimitiveMode(PrimitiveMode value) {
Parent::setPrimitiveMode(value);
if (_model) {
_model->setPrimitiveMode(_primitiveMode);
}
// called within a lock so no need to lock for _model
setKey(_didLastVisualGeometryRequestSucceed, _model);
}
void ModelEntityRenderer::setCullWithParent(bool value) {
Parent::setCullWithParent(value);
setKey(_didLastVisualGeometryRequestSucceed);
if (_model) {
_model->setCullWithParent(_cullWithParent);
}
}
void ModelEntityRenderer::setRenderWithZones(const QVector<QUuid>& renderWithZones) {
Parent::setRenderWithZones(renderWithZones);
if (_model) {
_model->setRenderWithZones(renderWithZones);
}
// called within a lock so no need to lock for _model
setKey(_didLastVisualGeometryRequestSucceed, _model);
}
// NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items
@ -1570,9 +1460,8 @@ void ModelEntityRenderer::doRender(RenderArgs* args) {
geometryCache->renderWireCubeInstance(args, batch, greenColor, geometryCache->getShapePipelinePointer(false, false, args->_renderMethod == Args::RenderMethod::FORWARD));
#if WANT_EXTRA_DEBUGGING
ModelPointer model;
withReadLock([&] {
model = _model;
ModelPointer model = resultWithReadLock<ModelPointer>([&] {
return _model;
});
if (model) {
model->renderDebugMeshBoxes(batch, args->_renderMethod == Args::RenderMethod::FORWARD);

View file

@ -41,7 +41,6 @@ protected:
ModelEntityWrapper(const EntityItemID& entityItemID) : Parent(entityItemID) {}
void setModel(const ModelPointer& model);
ModelPointer getModel() const;
bool isModelLoaded() const;
bool _needsInitialSimulation{ true };
private:
@ -62,7 +61,6 @@ public:
virtual void setUnscaledDimensions(const glm::vec3& value) override;
virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override;
void doInitialModelSimulation();
void updateModelBounds();
virtual bool supportsDetailedIntersection() const override;
@ -77,6 +75,7 @@ public:
virtual void setShapeType(ShapeType type) override;
virtual void setCompoundShapeURL(const QString& url) override;
virtual void setModelURL(const QString& url) override;
virtual bool isReadyToComputeShape() const override;
virtual void computeShapeInfo(ShapeInfo& shapeInfo) override;
@ -121,6 +120,8 @@ private:
bool readyToAnimate() const;
void fetchCollisionGeometryResource();
QString getCollisionShapeURL() const;
GeometryResource::Pointer _collisionGeometryResource;
std::vector<int> _jointMap;
QVariantMap _originalTextures;
@ -128,6 +129,7 @@ private:
bool _originalTexturesRead { false };
bool _dimensionsInitialized { true };
bool _needsJointSimulation { false };
bool _needsToRescaleModel { false };
};
namespace render { namespace entities {
@ -153,25 +155,23 @@ protected:
virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction) override;
virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override;
void setKey(bool didVisualGeometryRequestSucceed);
void setKey(bool didVisualGeometryRequestSucceed, const ModelPointer& model);
virtual ItemKey getKey() override;
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const override;
virtual void handleBlendedVertices(int blendshapeNumber, const QVector<BlendshapeOffset>& blendshapeOffsets,
const QVector<int>& blendedMeshSizes, const render::ItemIDs& subItemIDs) override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual bool needsRenderUpdate() const override;
virtual void doRender(RenderArgs* args) override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override;
void setIsVisibleInSecondaryCamera(bool value) override;
void setRenderLayer(RenderLayer value) override;
void setPrimitiveMode(PrimitiveMode value) override;
void setCullWithParent(bool value) override;
void setRenderWithZones(const QVector<QUuid>& renderWithZones) override;
private:
void animate(const TypedEntityPointer& entity);
void animate(const TypedEntityPointer& entity, const ModelPointer& model);
void mapJoints(const TypedEntityPointer& entity, const ModelPointer& model);
// Transparency is handled in ModelMeshPartPayload
@ -186,20 +186,16 @@ private:
bool _hasTransitioned{ false };
#endif
const void* _collisionMeshKey { nullptr };
QUrl _parsedModelURL;
bool _jointMappingCompleted { false };
QVector<int> _jointMapping; // domain is index into model-joints, range is index into animation-joints
AnimationPointer _animation;
bool _animating { false };
QString _animationURL;
uint64_t _lastAnimated { 0 };
render::ItemKey _itemKey { render::ItemKey::Builder().withTypeMeta() };
bool _didLastVisualGeometryRequestSucceed { true };
bool _prevModelLoaded { false };
void processMaterials();
bool _allProceduralMaterialsLoaded { false };

View file

@ -64,84 +64,7 @@ ParticleEffectEntityRenderer::ParticleEffectEntityRenderer(const EntityItemPoint
});
}
bool ParticleEffectEntityRenderer::needsRenderUpdate() const {
if (resultWithReadLock<bool>([&] {
return !_textureLoaded;
})) {
return true;
}
return Parent::needsRenderUpdate();
}
void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
auto newParticleProperties = entity->getParticleProperties();
if (!newParticleProperties.valid()) {
qCWarning(entitiesrenderer) << "Bad particle properties";
}
if (resultWithReadLock<bool>([&] { return _particleProperties != newParticleProperties; })) {
_timeUntilNextEmit = 0;
withWriteLock([&] {
_particleProperties = newParticleProperties;
if (!_prevEmitterShouldTrailInitialized) {
_prevEmitterShouldTrailInitialized = true;
_prevEmitterShouldTrail = _particleProperties.emission.shouldTrail;
}
});
}
withWriteLock([&] {
_pulseProperties = entity->getPulseProperties();
_shapeType = entity->getShapeType();
QString compoundShapeURL = entity->getCompoundShapeURL();
if (_compoundShapeURL != compoundShapeURL) {
_compoundShapeURL = compoundShapeURL;
_hasComputedTriangles = false;
fetchGeometryResource();
}
});
_emitting = entity->getIsEmitting();
bool textureEmpty = resultWithReadLock<bool>([&] { return _particleProperties.textures.isEmpty(); });
if (textureEmpty) {
if (_networkTexture) {
withWriteLock([&] {
_networkTexture.reset();
});
}
withWriteLock([&] {
_textureLoaded = true;
entity->setVisuallyReady(true);
});
} else {
bool textureNeedsUpdate = resultWithReadLock<bool>([&] {
return !_networkTexture || _networkTexture->getURL() != QUrl(_particleProperties.textures);
});
if (textureNeedsUpdate) {
withWriteLock([&] {
_networkTexture = DependencyManager::get<TextureCache>()->getTexture(_particleProperties.textures);
_textureLoaded = false;
entity->setVisuallyReady(false);
});
}
if (!_textureLoaded) {
emit requestRenderUpdate();
}
bool textureLoaded = resultWithReadLock<bool>([&] {
return _networkTexture && (_networkTexture->isLoaded() || _networkTexture->isFailed());
});
if (textureLoaded) {
withWriteLock([&] {
entity->setVisuallyReady(true);
_textureLoaded = true;
});
}
}
void* key = (void*)this;
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this] {
withWriteLock([&] {
@ -151,20 +74,66 @@ void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePoi
}
void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
auto newParticleProperties = entity->getParticleProperties();
if (!newParticleProperties.valid()) {
qCWarning(entitiesrenderer) << "Bad particle properties";
}
if (_particleProperties != newParticleProperties) {
_timeUntilNextEmit = 0;
_particleProperties = newParticleProperties;
if (!_prevEmitterShouldTrailInitialized) {
_prevEmitterShouldTrailInitialized = true;
_prevEmitterShouldTrail = _particleProperties.emission.shouldTrail;
}
}
_pulseProperties = entity->getPulseProperties();
_shapeType = entity->getShapeType();
QString compoundShapeURL = entity->getCompoundShapeURL();
if (_compoundShapeURL != compoundShapeURL) {
_compoundShapeURL = compoundShapeURL;
_hasComputedTriangles = false;
fetchGeometryResource();
}
_emitting = entity->getIsEmitting();
if (_particleProperties.textures.isEmpty()) {
if (_networkTexture) {
_networkTexture.reset();
}
_textureLoaded = true;
entity->setVisuallyReady(true);
} else {
if (!_networkTexture || _networkTexture->getURL() != QUrl(_particleProperties.textures)) {
_networkTexture = DependencyManager::get<TextureCache>()->getTexture(_particleProperties.textures);
_textureLoaded = false;
entity->setVisuallyReady(false);
}
if (!_textureLoaded) {
emit requestRenderUpdate();
}
if (_networkTexture && (_networkTexture->isLoaded() || _networkTexture->isFailed())) {
entity->setVisuallyReady(true);
_textureLoaded = true;
}
}
// Fill in Uniforms structure
ParticleUniforms particleUniforms;
withReadLock([&] {
particleUniforms.radius.start = _particleProperties.radius.range.start;
particleUniforms.radius.middle = _particleProperties.radius.gradient.target;
particleUniforms.radius.finish = _particleProperties.radius.range.finish;
particleUniforms.radius.spread = _particleProperties.radius.gradient.spread;
particleUniforms.spin.start = _particleProperties.spin.range.start;
particleUniforms.spin.middle = _particleProperties.spin.gradient.target;
particleUniforms.spin.finish = _particleProperties.spin.range.finish;
particleUniforms.spin.spread = _particleProperties.spin.gradient.spread;
particleUniforms.lifespan = _particleProperties.lifespan;
particleUniforms.rotateWithEntity = _particleProperties.rotateWithEntity ? 1 : 0;
});
particleUniforms.radius.start = _particleProperties.radius.range.start;
particleUniforms.radius.middle = _particleProperties.radius.gradient.target;
particleUniforms.radius.finish = _particleProperties.radius.range.finish;
particleUniforms.radius.spread = _particleProperties.radius.gradient.spread;
particleUniforms.spin.start = _particleProperties.spin.range.start;
particleUniforms.spin.middle = _particleProperties.spin.gradient.target;
particleUniforms.spin.finish = _particleProperties.spin.range.finish;
particleUniforms.spin.spread = _particleProperties.spin.gradient.spread;
particleUniforms.lifespan = _particleProperties.lifespan;
particleUniforms.rotateWithEntity = _particleProperties.rotateWithEntity ? 1 : 0;
// Update particle uniforms
_uniformBuffer.edit<ParticleUniforms>() = particleUniforms;
}
@ -403,27 +372,18 @@ void ParticleEffectEntityRenderer::stepSimulation() {
const auto interval = std::min<uint64_t>(USECS_PER_SECOND / 60, now - _lastSimulated);
_lastSimulated = now;
particle::Properties particleProperties;
ShapeType shapeType;
GeometryResource::Pointer geometryResource;
withReadLock([&] {
particleProperties = _particleProperties;
shapeType = _shapeType;
geometryResource = _geometryResource;
});
const auto& modelTransform = getModelTransform();
if (_emitting && particleProperties.emitting() &&
(shapeType != SHAPE_TYPE_COMPOUND || (geometryResource && geometryResource->isLoaded()))) {
uint64_t emitInterval = particleProperties.emitIntervalUsecs();
if (_emitting && _particleProperties.emitting() &&
(_shapeType != SHAPE_TYPE_COMPOUND || (_geometryResource && _geometryResource->isLoaded()))) {
uint64_t emitInterval = _particleProperties.emitIntervalUsecs();
if (emitInterval > 0 && interval >= _timeUntilNextEmit) {
auto timeRemaining = interval;
while (timeRemaining > _timeUntilNextEmit) {
if (_shapeType == SHAPE_TYPE_COMPOUND && !_hasComputedTriangles) {
computeTriangles(geometryResource->getHFMModel());
computeTriangles(_geometryResource->getHFMModel());
}
// emit particle
_cpuParticles.push_back(createParticle(modelTransform, particleProperties, shapeType, geometryResource, _triangleInfo));
_cpuParticles.push_back(createParticle(modelTransform, _particleProperties, _shapeType, _geometryResource, _triangleInfo));
_timeUntilNextEmit = emitInterval;
if (emitInterval < timeRemaining) {
timeRemaining -= emitInterval;
@ -435,14 +395,14 @@ void ParticleEffectEntityRenderer::stepSimulation() {
}
// Kill any particles that have expired or are over the max size
while (_cpuParticles.size() > particleProperties.maxParticles || (!_cpuParticles.empty() && _cpuParticles.front().expiration == 0)) {
while (_cpuParticles.size() > _particleProperties.maxParticles || (!_cpuParticles.empty() && _cpuParticles.front().expiration == 0)) {
_cpuParticles.pop_front();
}
const float deltaTime = (float)interval / (float)USECS_PER_SECOND;
// update the particles
for (auto& particle : _cpuParticles) {
if (_prevEmitterShouldTrail != particleProperties.emission.shouldTrail) {
if (_prevEmitterShouldTrail != _particleProperties.emission.shouldTrail) {
if (_prevEmitterShouldTrail) {
particle.relativePosition = particle.relativePosition + particle.basePosition - modelTransform.getTranslation();
}
@ -451,14 +411,14 @@ void ParticleEffectEntityRenderer::stepSimulation() {
particle.expiration = particle.expiration >= interval ? particle.expiration - interval : 0;
particle.integrate(deltaTime);
}
_prevEmitterShouldTrail = particleProperties.emission.shouldTrail;
_prevEmitterShouldTrail = _particleProperties.emission.shouldTrail;
// Build particle primitives
static GpuParticles gpuParticles;
gpuParticles.clear();
gpuParticles.reserve(_cpuParticles.size()); // Reserve space
std::transform(_cpuParticles.begin(), _cpuParticles.end(), std::back_inserter(gpuParticles), [&particleProperties, &modelTransform] (const CpuParticle& particle) {
glm::vec3 position = particle.relativePosition + (particleProperties.emission.shouldTrail ? particle.basePosition : modelTransform.getTranslation());
std::transform(_cpuParticles.begin(), _cpuParticles.end(), std::back_inserter(gpuParticles), [this, &modelTransform] (const CpuParticle& particle) {
glm::vec3 position = particle.relativePosition + (_particleProperties.emission.shouldTrail ? particle.basePosition : modelTransform.getTranslation());
return GpuParticle(position, glm::vec2(particle.lifetime, particle.seed));
});
@ -487,13 +447,14 @@ void ParticleEffectEntityRenderer::doRender(RenderArgs* args) {
// if the particles are marked rotateWithEntity
withReadLock([&] {
transform.setRotation(_renderTransform.getRotation());
auto& color = _uniformBuffer.edit<ParticleUniforms>().color;
color.start = EntityRenderer::calculatePulseColor(_particleProperties.getColorStart(), _pulseProperties, _created);
color.middle = EntityRenderer::calculatePulseColor(_particleProperties.getColorMiddle(), _pulseProperties, _created);
color.finish = EntityRenderer::calculatePulseColor(_particleProperties.getColorFinish(), _pulseProperties, _created);
color.spread = EntityRenderer::calculatePulseColor(_particleProperties.getColorSpread(), _pulseProperties, _created);
});
auto& color = _uniformBuffer.edit<ParticleUniforms>().color;
color.start = EntityRenderer::calculatePulseColor(_particleProperties.getColorStart(), _pulseProperties, _created);
color.middle = EntityRenderer::calculatePulseColor(_particleProperties.getColorMiddle(), _pulseProperties, _created);
color.finish = EntityRenderer::calculatePulseColor(_particleProperties.getColorFinish(), _pulseProperties, _created);
color.spread = EntityRenderer::calculatePulseColor(_particleProperties.getColorSpread(), _pulseProperties, _created);
batch.setModelTransform(transform);
batch.setUniformBuffer(0, _uniformBuffer);
batch.setInputFormat(_vertexFormat);

View file

@ -25,7 +25,6 @@ public:
ParticleEffectEntityRenderer(const EntityItemPointer& entity);
protected:
virtual bool needsRenderUpdate() const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;

View file

@ -121,16 +121,6 @@ ShapeKey PolyLineEntityRenderer::getShapeKey() {
return builder.build();
}
bool PolyLineEntityRenderer::needsRenderUpdate() const {
if (resultWithReadLock<bool>([&] {
return (!_textureLoaded && _texture && _texture->isLoaded());
})) {
return true;
}
return Parent::needsRenderUpdate();
}
bool PolyLineEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
if (entity->pointsChanged() || entity->widthsChanged() || entity->normalsChanged() || entity->texturesChanged() || entity->colorsChanged()) {
return true;
@ -140,6 +130,15 @@ bool PolyLineEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityP
}
void PolyLineEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
void* key = (void*)this;
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this] {
withWriteLock([&] {
_renderTransform = getModelTransform();
});
});
}
void PolyLineEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
auto pointsChanged = entity->pointsChanged();
auto widthsChanged = entity->widthsChanged();
auto normalsChanged = entity->normalsChanged();
@ -159,13 +158,15 @@ void PolyLineEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer&
if (!textures.isEmpty()) {
entityTextures = QUrl(textures);
}
withWriteLock([&] {
_texture = DependencyManager::get<TextureCache>()->getTexture(entityTextures);
});
_texture = DependencyManager::get<TextureCache>()->getTexture(entityTextures);
_textureAspectRatio = 1.0f;
_textureLoaded = false;
}
if (!_textureLoaded) {
emit requestRenderUpdate();
}
bool textureChanged = false;
if (!_textureLoaded && _texture && _texture->isLoaded()) {
textureChanged = true;
@ -175,13 +176,11 @@ void PolyLineEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer&
// Data
bool faceCameraChanged = faceCamera != _faceCamera;
withWriteLock([&] {
if (faceCameraChanged || glow != _glow) {
_faceCamera = faceCamera;
_glow = glow;
updateData();
}
});
if (faceCameraChanged || glow != _glow) {
_faceCamera = faceCamera;
_glow = glow;
updateData();
}
// Geometry
if (pointsChanged) {
@ -200,19 +199,10 @@ void PolyLineEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer&
bool uvModeStretchChanged = _isUVModeStretch != isUVModeStretch;
_isUVModeStretch = isUVModeStretch;
bool geometryChanged = uvModeStretchChanged || pointsChanged || widthsChanged || normalsChanged || colorsChanged || textureChanged || faceCameraChanged;
void* key = (void*)this;
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, geometryChanged] {
withWriteLock([&] {
_renderTransform = getModelTransform();
if (geometryChanged) {
updateGeometry();
}
});
});
if (uvModeStretchChanged || pointsChanged || widthsChanged || normalsChanged || colorsChanged || textureChanged || faceCameraChanged) {
updateGeometry();
}
}
void PolyLineEntityRenderer::updateGeometry() {
@ -318,19 +308,16 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) {
Q_ASSERT(args->_batch);
gpu::Batch& batch = *args->_batch;
size_t numVertices;
Transform transform;
gpu::TexturePointer texture;
gpu::TexturePointer texture = _textureLoaded ? _texture->getGPUTexture() : DependencyManager::get<TextureCache>()->getWhiteTexture();
withReadLock([&] {
numVertices = _numVertices;
transform = _renderTransform;
texture = _textureLoaded ? _texture->getGPUTexture() : DependencyManager::get<TextureCache>()->getWhiteTexture();
batch.setResourceBuffer(0, _polylineGeometryBuffer);
batch.setUniformBuffer(0, _polylineDataBuffer);
});
if (numVertices < 2) {
batch.setResourceBuffer(0, _polylineGeometryBuffer);
batch.setUniformBuffer(0, _polylineDataBuffer);
if (_numVertices < 2) {
return;
}
@ -341,5 +328,5 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) {
batch.setPipeline(_pipelines[{args->_renderMethod, isTransparent()}]);
batch.setModelTransform(transform);
batch.setResourceTexture(0, texture);
batch.draw(gpu::TRIANGLE_STRIP, (gpu::uint32)(2 * numVertices), 0);
batch.draw(gpu::TRIANGLE_STRIP, (gpu::uint32)(2 * _numVertices), 0);
}

View file

@ -30,9 +30,9 @@ public:
virtual bool isTransparent() const override;
protected:
virtual bool needsRenderUpdate() const override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual ItemKey getKey() override;
virtual ShapeKey getShapeKey() override;

View file

@ -1802,25 +1802,44 @@ ShapeKey PolyVoxEntityRenderer::getShapeKey() {
}
bool PolyVoxEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
if (entity->voxelToWorldMatrix() != _lastVoxelToWorldMatrix) {
if (resultWithReadLock<bool>([&] {
if (entity->voxelToWorldMatrix() != _lastVoxelToWorldMatrix) {
return true;
}
if (entity->_mesh != _mesh) {
return true;
}
return false;
})) {
return true;
}
if (entity->_mesh != _mesh) {
return true;
}
return false;
return Parent::needsRenderUpdateFromTypedEntity(entity);
}
void PolyVoxEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
#ifdef POLYVOX_ENTITY_USE_FADE_EFFECT
if (!_hasTransitioned) {
transaction.resetTransitionOnItem(_renderItemID, render::Transition::ELEMENT_ENTER_DOMAIN);
_hasTransitioned = true;
}
#endif
}
void PolyVoxEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
_lastVoxelToWorldMatrix = entity->voxelToWorldMatrix();
_lastVoxelVolumeSize = entity->getVoxelVolumeSize();
_params->setSubData(0, vec4(_lastVoxelVolumeSize, 0.0));
graphics::MeshPointer newMesh;
entity->withReadLock([&] {
newMesh = entity->_mesh;
});
if (newMesh && newMesh->getIndexBuffer()._buffer) {
_mesh = newMesh;
}
std::array<QString, 3> xyzTextureURLs{ {
entity->getXTextureURL(),
@ -1838,20 +1857,6 @@ void PolyVoxEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& s
}
}
void PolyVoxEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
_lastVoxelToWorldMatrix = entity->voxelToWorldMatrix();
_lastVoxelVolumeSize = entity->getVoxelVolumeSize();
_params->setSubData(0, vec4(_lastVoxelVolumeSize, 0.0));
graphics::MeshPointer newMesh;
entity->withReadLock([&] {
newMesh = entity->_mesh;
});
if (newMesh && newMesh->getIndexBuffer()._buffer) {
_mesh = newMesh;
}
}
void PolyVoxEntityRenderer::doRender(RenderArgs* args) {
if (!_mesh || !_mesh->getIndexBuffer()._buffer) {
return;

View file

@ -51,24 +51,7 @@ bool ShapeEntityRenderer::needsRenderUpdate() const {
return Parent::needsRenderUpdate();
}
bool ShapeEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
if (_dimensions != entity->getScaledDimensions()) {
return true;
}
if (_proceduralData != entity->getUserData()) {
return true;
}
return false;
}
void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
withWriteLock([&] {
_shape = entity->getShape();
_pulseProperties = entity->getPulseProperties();
});
void* key = (void*)this;
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
withWriteLock([&] {
@ -86,47 +69,53 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
}
void ShapeEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
_shape = entity->getShape();
_pulseProperties = entity->getPulseProperties();
bool materialChanged = false;
glm::vec3 color = toGlm(entity->getColor());
if (_color != color) {
_color = color;
_material->setAlbedo(color);
materialChanged = true;
}
float alpha = entity->getAlpha();
if (_alpha != alpha) {
_alpha = alpha;
_material->setOpacity(alpha);
materialChanged = true;
}
auto userData = entity->getUserData();
if (_proceduralData != userData) {
_proceduralData = userData;
_material->setProceduralData(_proceduralData);
materialChanged = true;
}
withReadLock([&] {
auto mat = _materials.find("0");
if (mat != _materials.end() && mat->second.top().material && mat->second.top().material->isProcedural() && mat->second.top().material->isReady()) {
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(mat->second.top().material);
if (procedural->isFading()) {
procedural->setIsFading(Interpolate::calculateFadeRatio(procedural->getFadeStartTime()) < 1.0f);
}
}
});
withWriteLock([&] {
bool materialChanged = false;
glm::vec3 color = toGlm(entity->getColor());
if (_color != color) {
_color = color;
_material->setAlbedo(color);
materialChanged = true;
}
float alpha = entity->getAlpha();
if (_alpha != alpha) {
_alpha = alpha;
_material->setOpacity(alpha);
materialChanged = true;
}
auto userData = entity->getUserData();
if (_proceduralData != userData) {
_proceduralData = userData;
_material->setProceduralData(_proceduralData);
materialChanged = true;
}
auto materials = _materials.find("0");
if (materials != _materials.end()) {
if (materialChanged) {
materials->second.setNeedsUpdate(true);
}
bool requestUpdate = false;
if (materials->second.top().material && materials->second.top().material->isProcedural() && materials->second.top().material->isReady()) {
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(materials->second.top().material);
if (procedural->isFading()) {
procedural->setIsFading(Interpolate::calculateFadeRatio(procedural->getFadeStartTime()) < 1.0f);
requestUpdate = true;
}
}
if (materials->second.shouldUpdate()) {
RenderPipelines::updateMultiMaterial(materials->second);
requestUpdate = true;
}
if (requestUpdate) {
emit requestRenderUpdate();
}
}
@ -231,13 +220,12 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
graphics::MultiMaterial materials;
auto geometryCache = DependencyManager::get<GeometryCache>();
GeometryCache::Shape geometryShape;
GeometryCache::Shape geometryShape = geometryCache->getShapeForEntityShape(_shape);
PrimitiveMode primitiveMode;
RenderLayer renderLayer;
glm::vec4 outColor;
Pipeline pipelineType;
withReadLock([&] {
geometryShape = geometryCache->getShapeForEntityShape(_shape);
primitiveMode = _primitiveMode;
renderLayer = _renderLayer;
batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation
@ -245,9 +233,10 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
pipelineType = getPipelineType(materials);
auto& schema = materials.getSchemaBuffer().get<graphics::MultiMaterial::Schema>();
outColor = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity);
outColor = EntityRenderer::calculatePulseColor(outColor, _pulseProperties, _created);
});
outColor = EntityRenderer::calculatePulseColor(outColor, _pulseProperties, _created);
if (outColor.a == 0.0f) {
return;
}
@ -256,7 +245,9 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(materials.top().material);
outColor = procedural->getColor(outColor);
outColor.a *= procedural->isFading() ? Interpolate::calculateFadeRatio(procedural->getFadeStartTime()) : 1.0f;
procedural->prepare(batch, _position, _dimensions, _orientation, _created, ProceduralProgramKey(outColor.a < 1.0f));
withReadLock([&] {
procedural->prepare(batch, _position, _dimensions, _orientation, _created, ProceduralProgramKey(outColor.a < 1.0f));
});
if (render::ShapeKey(args->_globalShapeKey).isWireframe() || primitiveMode == PrimitiveMode::LINES) {
geometryCache->renderWireShape(batch, geometryShape, outColor);

View file

@ -30,7 +30,6 @@ protected:
private:
virtual bool needsRenderUpdate() const override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override;

View file

@ -92,14 +92,6 @@ uint32_t TextEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) const {
return parentSubs;
}
bool TextEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
if (_dimensions != entity->getScaledDimensions()) {
return true;
}
return false;
}
void TextEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
void* key = (void*)this;
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
@ -112,26 +104,24 @@ void TextEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
}
void TextEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
withWriteLock([&] {
_pulseProperties = entity->getPulseProperties();
_text = entity->getText();
_lineHeight = entity->getLineHeight();
_textColor = toGlm(entity->getTextColor());
_textAlpha = entity->getTextAlpha();
_backgroundColor = toGlm(entity->getBackgroundColor());
_backgroundAlpha = entity->getBackgroundAlpha();
_billboardMode = entity->getBillboardMode();
_leftMargin = entity->getLeftMargin();
_rightMargin = entity->getRightMargin();
_topMargin = entity->getTopMargin();
_bottomMargin = entity->getBottomMargin();
_unlit = entity->getUnlit();
_font = entity->getFont();
_effect = entity->getTextEffect();
_effectColor = toGlm(entity->getTextEffectColor());
_effectThickness = entity->getTextEffectThickness();
updateTextRenderItem();
});
_pulseProperties = entity->getPulseProperties();
_text = entity->getText();
_lineHeight = entity->getLineHeight();
_textColor = toGlm(entity->getTextColor());
_textAlpha = entity->getTextAlpha();
_backgroundColor = toGlm(entity->getBackgroundColor());
_backgroundAlpha = entity->getBackgroundAlpha();
_billboardMode = entity->getBillboardMode();
_leftMargin = entity->getLeftMargin();
_rightMargin = entity->getRightMargin();
_topMargin = entity->getTopMargin();
_bottomMargin = entity->getBottomMargin();
_unlit = entity->getUnlit();
_font = entity->getFont();
_effect = entity->getTextEffect();
_effectColor = toGlm(entity->getTextEffectColor());
_effectThickness = entity->getTextEffectThickness();
updateTextRenderItem();
}
void TextEntityRenderer::doRender(RenderArgs* args) {
@ -141,25 +131,23 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
glm::vec4 backgroundColor;
Transform modelTransform;
BillboardMode billboardMode;
PrimitiveMode primitiveMode;
RenderLayer renderLayer;
withReadLock([&] {
modelTransform = _renderTransform;
billboardMode = _billboardMode;
primitiveMode = _primitiveMode;
renderLayer = _renderLayer;
float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
backgroundColor = glm::vec4(_backgroundColor, fadeRatio * _backgroundAlpha);
backgroundColor = EntityRenderer::calculatePulseColor(backgroundColor, _pulseProperties, _created);
});
backgroundColor = EntityRenderer::calculatePulseColor(backgroundColor, _pulseProperties, _created);
if (backgroundColor.a <= 0.0f) {
return;
}
modelTransform.setRotation(EntityItem::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), billboardMode, args->getViewFrustum().getPosition()));
modelTransform.setRotation(EntityItem::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), _billboardMode, args->getViewFrustum().getPosition()));
batch.setModelTransform(modelTransform);
auto geometryCache = DependencyManager::get<GeometryCache>();
@ -323,53 +311,36 @@ void entities::TextPayload::render(RenderArgs* args) {
glm::vec3 dimensions;
BillboardMode billboardMode;
QString text;
glm::vec4 textColor;
QString font;
TextEffect effect;
glm::vec3 effectColor;
float effectThickness;
float lineHeight, leftMargin, rightMargin, topMargin, bottomMargin;
bool forward;
textRenderable->withReadLock([&] {
modelTransform = textRenderable->_renderTransform;
dimensions = textRenderable->_dimensions;
billboardMode = textRenderable->_billboardMode;
text = textRenderable->_text;
font = textRenderable->_font;
effect = textRenderable->_effect;
effectThickness = textRenderable->_effectThickness;
lineHeight = textRenderable->_lineHeight;
leftMargin = textRenderable->_leftMargin;
rightMargin = textRenderable->_rightMargin;
topMargin = textRenderable->_topMargin;
bottomMargin = textRenderable->_bottomMargin;
float fadeRatio = textRenderable->_isFading ? Interpolate::calculateFadeRatio(textRenderable->_fadeStartTime) : 1.0f;
textColor = glm::vec4(textRenderable->_textColor, fadeRatio * textRenderable->_textAlpha);
textColor = EntityRenderer::calculatePulseColor(textColor, textRenderable->_pulseProperties, textRenderable->_created);
effectColor = EntityRenderer::calculatePulseColor(textRenderable->_effectColor, textRenderable->_pulseProperties, textRenderable->_created);
forward = textRenderable->_renderLayer != RenderLayer::WORLD || args->_renderMethod == render::Args::FORWARD;
});
textColor = EntityRenderer::calculatePulseColor(textColor, textRenderable->_pulseProperties, textRenderable->_created);
glm::vec3 effectColor = EntityRenderer::calculatePulseColor(textRenderable->_effectColor, textRenderable->_pulseProperties, textRenderable->_created);
if (textColor.a <= 0.0f) {
return;
}
modelTransform.setRotation(EntityItem::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), billboardMode, args->getViewFrustum().getPosition()));
float scale = lineHeight / textRenderer->getFontSize();
float scale = textRenderable->_lineHeight / textRenderer->getFontSize();
modelTransform.postTranslate(glm::vec3(-0.5, 0.5, 1.0f + EPSILON / dimensions.z));
modelTransform.setScale(scale);
batch.setModelTransform(modelTransform);
glm::vec2 bounds = glm::vec2(dimensions.x - (leftMargin + rightMargin), dimensions.y - (topMargin + bottomMargin));
textRenderer->draw(batch, leftMargin / scale, -topMargin / scale, bounds / scale, scale,
text, font, textColor, effectColor, effectThickness, effect,
glm::vec2 bounds = glm::vec2(dimensions.x - (textRenderable->_leftMargin + textRenderable->_rightMargin), dimensions.y - (textRenderable->_topMargin + textRenderable->_bottomMargin));
textRenderer->draw(batch, textRenderable->_leftMargin / scale, -textRenderable->_topMargin / scale, bounds / scale, scale,
textRenderable->_text, textRenderable->_font, textColor, effectColor, textRenderable->_effectThickness, textRenderable->_effect,
textRenderable->_unlit, forward);
}

View file

@ -42,7 +42,6 @@ protected:
void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override;
private:
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override;

View file

@ -125,16 +125,6 @@ bool WebEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointe
return false;
}
bool WebEntityRenderer::needsRenderUpdate() const {
if (resultWithReadLock<bool>([this] {
return !_webSurface;
})) {
return true;
}
return Parent::needsRenderUpdate();
}
void WebEntityRenderer::onTimeout() {
uint64_t lastRenderTime;
if (!resultWithReadLock<bool>([&] {
@ -261,6 +251,8 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
_renderTransform.postScale(entity->getScaledDimensions());
});
});
} else {
emit requestRenderUpdate();
}
});
}
@ -339,8 +331,11 @@ void WebEntityRenderer::buildWebSurface(const EntityItemPointer& entity, const Q
return;
}
++_currentWebCount;
WebEntityRenderer::acquireWebSurface(newSourceURL, _contentType == ContentType::HtmlContent, _webSurface, _cachedWebSurface);
bool isHTML = _contentType == ContentType::HtmlContent;
if (isHTML) {
++_currentWebCount;
}
WebEntityRenderer::acquireWebSurface(newSourceURL, isHTML, _webSurface, _cachedWebSurface);
_fadeStartTime = usecTimestampNow();
_webSurface->resume();
@ -358,12 +353,15 @@ void WebEntityRenderer::destroyWebSurface() {
QSharedPointer<OffscreenQmlSurface> webSurface;
withWriteLock([&] {
webSurface.swap(_webSurface);
_contentType = ContentType::NoContent;
if (webSurface) {
--_currentWebCount;
if (_contentType == ContentType::HtmlContent) {
--_currentWebCount;
}
WebEntityRenderer::releaseWebSurface(webSurface, _cachedWebSurface, _connections);
}
_contentType = ContentType::NoContent;
});
}

View file

@ -55,7 +55,6 @@ public:
virtual QObject* getEventHandler() override;
protected:
virtual bool needsRenderUpdate() const override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override;

View file

@ -189,7 +189,7 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) {
CullTest::_containingZones.insert(_entityID);
}
void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
auto position = entity->getWorldPosition();
auto rotation = entity->getWorldOrientation();
auto dimensions = entity->getScaledDimensions();
@ -199,7 +199,11 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
auto visible = entity->getVisible();
if (transformChanged || visible != _lastVisible) {
_lastVisible = visible;
DependencyManager::get<EntityTreeRenderer>()->updateZone(entity->getID());
void* key = (void*)this;
EntityItemID id = entity->getID();
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [id] {
DependencyManager::get<EntityTreeRenderer>()->updateZone(id);
});
}
auto proceduralUserData = entity->getUserData();
@ -267,10 +271,6 @@ ItemKey ZoneEntityRenderer::getKey() {
}
bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
if (entity->getVisible() != _lastVisible) {
return true;
}
if (entity->keyLightPropertiesChanged() ||
entity->ambientLightPropertiesChanged() ||
entity->hazePropertiesChanged() ||
@ -280,29 +280,11 @@ bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint
return true;
}
if (_skyboxTextureURL != entity->getSkyboxProperties().getURL()) {
return true;
}
if (entity->getWorldPosition() != _lastPosition) {
return true;
}
if (entity->getScaledDimensions() != _lastDimensions) {
return true;
}
if (entity->getWorldOrientation() != _lastRotation) {
return true;
}
if (entity->getUserData() != _proceduralUserData) {
return true;
}
return false;
}
void ZoneEntityRenderer::updateKeySunFromEntity(const TypedEntityPointer& entity) {
setKeyLightMode((ComponentMode)entity->getKeyLightMode());
_keyLightMode = (ComponentMode)entity->getKeyLightMode();
const auto& sunLight = editSunLight();
sunLight->setType(graphics::Light::SUN);
@ -319,7 +301,7 @@ void ZoneEntityRenderer::updateKeySunFromEntity(const TypedEntityPointer& entity
}
void ZoneEntityRenderer::updateAmbientLightFromEntity(const TypedEntityPointer& entity) {
setAmbientLightMode((ComponentMode)entity->getAmbientLightMode());
_ambientLightMode = (ComponentMode)entity->getAmbientLightMode();
const auto& ambientLight = editAmbientLight();
ambientLight->setType(graphics::Light::AMBIENT);
@ -339,11 +321,12 @@ void ZoneEntityRenderer::updateAmbientLightFromEntity(const TypedEntityPointer&
}
void ZoneEntityRenderer::updateHazeFromEntity(const TypedEntityPointer& entity) {
setHazeMode((ComponentMode)entity->getHazeMode());
const uint32_t hazeMode = entity->getHazeMode();
_hazeMode = (ComponentMode)hazeMode;
const auto& haze = editHaze();
const uint32_t hazeMode = entity->getHazeMode();
haze->setHazeActive(hazeMode == COMPONENT_MODE_ENABLED);
haze->setAltitudeBased(_hazeProperties.getHazeAltitudeEffect());
@ -367,7 +350,7 @@ void ZoneEntityRenderer::updateHazeFromEntity(const TypedEntityPointer& entity)
}
void ZoneEntityRenderer::updateBloomFromEntity(const TypedEntityPointer& entity) {
setBloomMode((ComponentMode)entity->getBloomMode());
_bloomMode = (ComponentMode)entity->getBloomMode();
const auto& bloom = editBloom();
@ -377,7 +360,7 @@ void ZoneEntityRenderer::updateBloomFromEntity(const TypedEntityPointer& entity)
}
void ZoneEntityRenderer::updateKeyBackgroundFromEntity(const TypedEntityPointer& entity) {
setSkyboxMode((ComponentMode)entity->getSkyboxMode());
_skyboxMode = (ComponentMode)entity->getSkyboxMode();
editBackground();
setSkyboxColor(toGlm(_skyboxProperties.getColor()));
@ -478,26 +461,6 @@ void ZoneEntityRenderer::updateSkyboxMap() {
}
}
void ZoneEntityRenderer::setHazeMode(ComponentMode mode) {
_hazeMode = mode;
}
void ZoneEntityRenderer::setKeyLightMode(ComponentMode mode) {
_keyLightMode = mode;
}
void ZoneEntityRenderer::setAmbientLightMode(ComponentMode mode) {
_ambientLightMode = mode;
}
void ZoneEntityRenderer::setSkyboxMode(ComponentMode mode) {
_skyboxMode = mode;
}
void ZoneEntityRenderer::setBloomMode(ComponentMode mode) {
_bloomMode = mode;
}
void ZoneEntityRenderer::setSkyboxColor(const glm::vec3& color) {
editSkybox()->setColor(color);
}

View file

@ -38,7 +38,7 @@ protected:
virtual ItemKey getKey() override;
virtual void doRender(RenderArgs* args) override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
private:
void updateKeyZoneItemFromEntity(const TypedEntityPointer& entity);
@ -52,12 +52,6 @@ private:
void setAmbientURL(const QString& ambientUrl);
void setSkyboxURL(const QString& skyboxUrl);
void setHazeMode(ComponentMode mode);
void setKeyLightMode(ComponentMode mode);
void setAmbientLightMode(ComponentMode mode);
void setSkyboxMode(ComponentMode mode);
void setBloomMode(ComponentMode mode);
void setSkyboxColor(const glm::vec3& color);
void setProceduralUserData(const QString& userData);

View file

@ -1911,13 +1911,11 @@ void EntityItem::setUnscaledDimensions(const glm::vec3& value) {
if (glm::length2(getUnscaledDimensions() - newDimensions) > MIN_SCALE_CHANGE_SQUARED) {
withWriteLock([&] {
_unscaledDimensions = newDimensions;
});
locationChanged();
dimensionsChanged();
withWriteLock([&] {
_flags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
_queryAACubeSet = false;
});
locationChanged();
dimensionsChanged();
}
}

View file

@ -78,7 +78,14 @@ void LightEntityItem::setFalloffRadius(float value) {
}
void LightEntityItem::setIsSpotlight(bool value) {
if (value == getIsSpotlight()) {
bool needsRenderUpdate;
withWriteLock([&] {
needsRenderUpdate = value != _isSpotlight;
_needsRenderUpdate |= needsRenderUpdate;
_isSpotlight = value;
});
if (!needsRenderUpdate) {
return;
}
@ -92,25 +99,25 @@ void LightEntityItem::setIsSpotlight(bool value) {
newDimensions = glm::vec3(glm::compMax(dimensions));
}
withWriteLock([&] {
_needsRenderUpdate = true;
_isSpotlight = value;
});
setScaledDimensions(newDimensions);
}
void LightEntityItem::setCutoff(float value) {
value = glm::clamp(value, MIN_CUTOFF, MAX_CUTOFF);
if (value == getCutoff()) {
bool needsRenderUpdate;
bool spotlight;
withWriteLock([&] {
needsRenderUpdate = value != _cutoff;
_needsRenderUpdate |= needsRenderUpdate;
_cutoff = value;
spotlight = _isSpotlight;
});
if (!needsRenderUpdate) {
return;
}
withWriteLock([&] {
_needsRenderUpdate = true;
_cutoff = value;
});
if (getIsSpotlight()) {
if (spotlight) {
// If we are a spotlight, adjusting the cutoff will affect the area we encapsulate,
// so update the dimensions to reflect this.
const float length = getScaledDimensions().z;

View file

@ -254,26 +254,30 @@ void ModelEntityItem::debugDump() const {
}
void ModelEntityItem::setShapeType(ShapeType type) {
bool changed = false;
uint32_t flags = 0;
withWriteLock([&] {
if (type != _shapeType) {
if (type == SHAPE_TYPE_STATIC_MESH && _dynamic) {
// dynamic and STATIC_MESH are incompatible
// since the shape is being set here we clear the dynamic bit
_dynamic = false;
_flags |= Simulation::DIRTY_MOTION_TYPE;
flags = Simulation::DIRTY_MOTION_TYPE;
}
_shapeType = type;
_flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
changed = true;
}
});
if (changed) {
markDirtyFlags(flags);
locationChanged();
}
}
ShapeType ModelEntityItem::getShapeType() const {
return computeTrueShapeType();
}
ShapeType ModelEntityItem::computeTrueShapeType() const {
ShapeType type = _shapeType;
ShapeType type = resultWithReadLock<ShapeType>([&] { return _shapeType; });
if (type == SHAPE_TYPE_STATIC_MESH && _dynamic) {
// dynamic is incompatible with STATIC_MESH
// shouldn't fall in here but just in case --> fall back to COMPOUND
@ -290,7 +294,6 @@ void ModelEntityItem::setModelURL(const QString& url) {
withWriteLock([&] {
if (_modelURL != url) {
_modelURL = url;
_flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
_needsRenderUpdate = true;
}
});
@ -325,18 +328,10 @@ void ModelEntityItem::setCompoundShapeURL(const QString& url) {
withWriteLock([&] {
if (_compoundShapeURL.get() != url) {
_compoundShapeURL.set(url);
_flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
}
});
}
void ModelEntityItem::setAnimationURL(const QString& url) {
_flags |= Simulation::DIRTY_UPDATEABLE;
withWriteLock([&] {
_animationProperties.setURL(url);
});
}
void ModelEntityItem::setAnimationSettings(const QString& value) {
// NOTE: this method only called for old bitstream format
@ -399,20 +394,6 @@ void ModelEntityItem::setAnimationSettings(const QString& value) {
});
}
void ModelEntityItem::setAnimationIsPlaying(bool value) {
_flags |= Simulation::DIRTY_UPDATEABLE;
withWriteLock([&] {
_animationProperties.setRunning(value);
});
}
void ModelEntityItem::setAnimationFPS(float value) {
_flags |= Simulation::DIRTY_UPDATEABLE;
withWriteLock([&] {
_animationProperties.setFPS(value);
});
}
void ModelEntityItem::resizeJointArrays(int newSize) {
if (newSize < 0) {
return;
@ -588,10 +569,6 @@ QString ModelEntityItem::getCompoundShapeURL() const {
return _compoundShapeURL.get();
}
QString ModelEntityItem::getCollisionShapeURL() const {
return getShapeType() == SHAPE_TYPE_COMPOUND ? getCompoundShapeURL() : getModelURL();
}
void ModelEntityItem::setColor(const glm::u8vec3& value) {
withWriteLock([&] {
_color = value;
@ -629,61 +606,18 @@ void ModelEntityItem::setAnimationCurrentFrame(float value) {
});
}
void ModelEntityItem::setAnimationAllowTranslation(bool value) {
withWriteLock([&] {
_animationProperties.setAllowTranslation(value);
});
}
bool ModelEntityItem::getAnimationAllowTranslation() const {
return resultWithReadLock<bool>([&] {
return _animationProperties.getAllowTranslation();
});
}
void ModelEntityItem::setAnimationLoop(bool loop) {
withWriteLock([&] {
_animationProperties.setLoop(loop);
});
}
bool ModelEntityItem::getAnimationLoop() const {
return resultWithReadLock<bool>([&] {
return _animationProperties.getLoop();
});
}
void ModelEntityItem::setAnimationHold(bool hold) {
withWriteLock([&] {
_animationProperties.setHold(hold);
});
}
bool ModelEntityItem::getAnimationHold() const {
return resultWithReadLock<bool>([&] {
return _animationProperties.getHold();
});
}
bool ModelEntityItem::getAnimationIsPlaying() const {
return resultWithReadLock<bool>([&] {
return _animationProperties.getRunning();
});
}
float ModelEntityItem::getAnimationCurrentFrame() const {
return resultWithReadLock<float>([&] {
return _animationProperties.getCurrentFrame();
});
}
float ModelEntityItem::getAnimationFPS() const {
return resultWithReadLock<float>([&] {
return _animationProperties.getFPS();
});
}
bool ModelEntityItem::isAnimatingSomething() const {
return resultWithReadLock<bool>([&] {
return _animationProperties.isValidAndRunning();
@ -722,6 +656,7 @@ bool ModelEntityItem::applyNewAnimationProperties(AnimationPropertyGroup newProp
bool somethingChanged = newProperties != _animationProperties;
if (somethingChanged) {
_animationProperties = newProperties;
_needsRenderUpdate = true;
_flags |= Simulation::DIRTY_UPDATEABLE;
}
return somethingChanged;

View file

@ -76,33 +76,18 @@ public:
static const QString DEFAULT_COMPOUND_SHAPE_URL;
QString getCompoundShapeURL() const;
// Returns the URL used for the collision shape
QString getCollisionShapeURL() const;
// model related properties
virtual void setModelURL(const QString& url);
virtual void setCompoundShapeURL(const QString& url);
// Animation related items...
AnimationPropertyGroup getAnimationProperties() const;
// TODO: audit and remove unused Animation accessors
bool hasAnimation() const;
QString getAnimationURL() const;
virtual void setAnimationURL(const QString& url);
void setAnimationCurrentFrame(float value);
void setAnimationIsPlaying(bool value);
void setAnimationFPS(float value);
void setAnimationAllowTranslation(bool value);
float getAnimationCurrentFrame() const;
bool getAnimationAllowTranslation() const;
void setAnimationLoop(bool loop);
bool getAnimationLoop() const;
void setAnimationHold(bool hold);
bool getAnimationHold() const;
bool isAnimatingSomething() const;
void setRelayParentJoints(bool relayJoints);
bool getRelayParentJoints() const;
@ -110,11 +95,6 @@ public:
void setGroupCulled(bool value);
bool getGroupCulled() const;
bool getAnimationIsPlaying() const;
float getAnimationCurrentFrame() const;
float getAnimationFPS() const;
bool isAnimatingSomething() const;
static const QString DEFAULT_TEXTURES;
const QString getTextures() const;
void setTextures(const QString& textures);
@ -142,7 +122,6 @@ public:
private:
void setAnimationSettings(const QString& value); // only called for old bitstream format
bool applyNewAnimationProperties(AnimationPropertyGroup newProperties);
ShapeType computeTrueShapeType() const;
protected:
void resizeJointArrays(int newSize);

View file

@ -266,21 +266,21 @@ glm::u8vec3 PolyLineEntityItem::getColor() const {
void PolyLineEntityItem::setIsUVModeStretch(bool isUVModeStretch) {
withWriteLock([&] {
_needsRenderUpdate = _isUVModeStretch != isUVModeStretch;
_needsRenderUpdate |= _isUVModeStretch != isUVModeStretch;
_isUVModeStretch = isUVModeStretch;
});
}
void PolyLineEntityItem::setGlow(bool glow) {
withWriteLock([&] {
_needsRenderUpdate = _glow != glow;
_needsRenderUpdate |= _glow != glow;
_glow = glow;
});
}
void PolyLineEntityItem::setFaceCamera(bool faceCamera) {
withWriteLock([&] {
_needsRenderUpdate = _faceCamera != faceCamera;
_needsRenderUpdate |= _faceCamera != faceCamera;
_faceCamera = faceCamera;
});
}

View file

@ -442,4 +442,11 @@ PulsePropertyGroup ShapeEntityItem::getPulseProperties() const {
return resultWithReadLock<PulsePropertyGroup>([&] {
return _pulseProperties;
});
}
void ShapeEntityItem::setUserData(const QString& value) {
withWriteLock([&] {
_needsRenderUpdate |= _userData != value;
_userData = value;
});
}

View file

@ -101,6 +101,8 @@ public:
PulsePropertyGroup getPulseProperties() const;
void setUserData(const QString& value) override;
protected:
glm::u8vec3 _color;
float _alpha { 1.0f };

View file

@ -84,12 +84,12 @@ bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& propertie
// Contains a QString property, must be synchronized
withWriteLock([&] {
_keyLightPropertiesChanged = _keyLightProperties.setProperties(properties);
_ambientLightPropertiesChanged = _ambientLightProperties.setProperties(properties);
_skyboxPropertiesChanged = _skyboxProperties.setProperties(properties);
_keyLightPropertiesChanged |= _keyLightProperties.setProperties(properties);
_ambientLightPropertiesChanged |= _ambientLightProperties.setProperties(properties);
_skyboxPropertiesChanged |= _skyboxProperties.setProperties(properties);
});
_hazePropertiesChanged = _hazeProperties.setProperties(properties);
_bloomPropertiesChanged = _bloomProperties.setProperties(properties);
_hazePropertiesChanged |= _hazeProperties.setProperties(properties);
_bloomPropertiesChanged |= _bloomProperties.setProperties(properties);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(flyingAllowed, setFlyingAllowed);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ghostingAllowed, setGhostingAllowed);
@ -125,7 +125,7 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
bytesFromKeylight = _keyLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, _keyLightPropertiesChanged);
});
somethingChanged = somethingChanged || _keyLightPropertiesChanged;
somethingChanged |= _keyLightPropertiesChanged;
bytesRead += bytesFromKeylight;
dataAt += bytesFromKeylight;
}
@ -136,7 +136,7 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
bytesFromAmbientlight = _ambientLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, _ambientLightPropertiesChanged);
});
somethingChanged = somethingChanged || _ambientLightPropertiesChanged;
somethingChanged |= _ambientLightPropertiesChanged;
bytesRead += bytesFromAmbientlight;
dataAt += bytesFromAmbientlight;
}
@ -147,7 +147,7 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
bytesFromSkybox = _skyboxProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, _skyboxPropertiesChanged);
});
somethingChanged = somethingChanged || _skyboxPropertiesChanged;
somethingChanged |= _skyboxPropertiesChanged;
bytesRead += bytesFromSkybox;
dataAt += bytesFromSkybox;
}
@ -155,7 +155,7 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
{
int bytesFromHaze = _hazeProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, _hazePropertiesChanged);
somethingChanged = somethingChanged || _hazePropertiesChanged;
somethingChanged |= _hazePropertiesChanged;
bytesRead += bytesFromHaze;
dataAt += bytesFromHaze;
}
@ -163,7 +163,7 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
{
int bytesFromBloom = _bloomProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, _bloomPropertiesChanged);
somethingChanged = somethingChanged || _bloomPropertiesChanged;
somethingChanged |= _bloomPropertiesChanged;
bytesRead += bytesFromBloom;
dataAt += bytesFromBloom;
}
@ -444,6 +444,13 @@ uint32_t ZoneEntityItem::getSkyboxMode() const {
return _skyboxMode;
}
void ZoneEntityItem::setUserData(const QString& value) {
withWriteLock([&] {
_needsRenderUpdate |= _userData != value;
_userData = value;
});
}
void ZoneEntityItem::fetchCollisionGeometryResource() {
QUrl hullURL(getCompoundShapeURL());
if (hullURL.isEmpty()) {

View file

@ -104,6 +104,8 @@ public:
uint32_t getScreenshare() const { return _screenshare; }
void setScreenshare(uint32_t value) { _screenshare = value; }
void setUserData(const QString& value) override;
bool keyLightPropertiesChanged() const { return _keyLightPropertiesChanged; }
bool ambientLightPropertiesChanged() const { return _ambientLightPropertiesChanged; }
bool skyboxPropertiesChanged() const { return _skyboxPropertiesChanged; }

View file

@ -425,12 +425,12 @@ void PhysicalEntitySimulation::buildPhysicsTransaction(PhysicsEngine::Transactio
continue;
}
bool needsNewShape = object->needsNewShape();
bool needsNewShape = object->needsNewShape() && object->_entity->isReadyToComputeShape();
if (needsNewShape) {
ShapeType shapeType = object->getShapeType();
if (shapeType == SHAPE_TYPE_STATIC_MESH) {
ShapeRequest shapeRequest(object->_entity);
ShapeRequests::iterator requestItr = _shapeRequests.find(shapeRequest);
ShapeRequests::iterator requestItr = _shapeRequests.find(shapeRequest);
if (requestItr == _shapeRequests.end()) {
ShapeInfo shapeInfo;
object->_entity->computeShapeInfo(shapeInfo);

View file

@ -338,7 +338,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
bool intersectedSomething = false;
// if we aren't active, we can't pick yet...
if (!isActive()) {
if (!isLoaded()) {
return intersectedSomething;
}
@ -493,7 +493,7 @@ bool Model::findParabolaIntersectionAgainstSubMeshes(const glm::vec3& origin, co
bool intersectedSomething = false;
// if we aren't active, we can't pick yet...
if (!isActive()) {
if (!isLoaded()) {
return intersectedSomething;
}
@ -958,16 +958,42 @@ void Model::setCauterized(bool cauterized, const render::ScenePointer& scene) {
}
}
void Model::setPrimitiveMode(PrimitiveMode primitiveMode) {
void Model::setPrimitiveMode(PrimitiveMode primitiveMode, const render::ScenePointer& scene) {
if (_primitiveMode != primitiveMode) {
_primitiveMode = primitiveMode;
updateRenderItemsKey(nullptr);
if (!scene) {
_needsFixupInScene = true;
return;
}
bool useDualQuaternionSkinning = _useDualQuaternionSkinning;
std::unordered_map<int, bool> shouldInvalidatePayloadShapeKeyMap;
for (auto& shape : _modelMeshRenderItemShapes) {
shouldInvalidatePayloadShapeKeyMap[shape.meshIndex] = shouldInvalidatePayloadShapeKey(shape.meshIndex);
}
render::Transaction transaction;
for (int i = 0; i < (int)_modelMeshRenderItemIDs.size(); i++) {
auto itemID = _modelMeshRenderItemIDs[i];
auto meshIndex = _modelMeshRenderItemShapes[i].meshIndex;
bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);
transaction.updateItem<ModelMeshPartPayload>(itemID, [invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning] (ModelMeshPartPayload& data) {
data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning);
});
}
scene->enqueueTransaction(transaction);
}
}
void Model::setCullWithParent(bool cullWithParent) {
void Model::setCullWithParent(bool cullWithParent, const render::ScenePointer& scene) {
if (_cullWithParent != cullWithParent) {
_cullWithParent = cullWithParent;
if (!scene) {
_needsFixupInScene = true;
return;
}
render::Transaction transaction;
auto renderItemsKey = _renderItemKeyGlobalFlags;
@ -977,14 +1003,27 @@ void Model::setCullWithParent(bool cullWithParent) {
data.updateKey(renderItemsKey);
});
}
AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction);
scene->enqueueTransaction(transaction);
}
}
void Model::setRenderWithZones(const QVector<QUuid>& renderWithZones) {
void Model::setRenderWithZones(const QVector<QUuid>& renderWithZones, const render::ScenePointer& scene) {
if (_renderWithZones != renderWithZones) {
_renderWithZones = renderWithZones;
setRenderItemsNeedUpdate();
if (!scene) {
_needsFixupInScene = true;
return;
}
render::Transaction transaction;
auto renderItemsKey = _renderItemKeyGlobalFlags;
for (auto item : _modelMeshRenderItemIDs) {
transaction.updateItem<ModelMeshPartPayload>(item, [renderWithZones, renderItemsKey](ModelMeshPartPayload& data) {
data.setRenderWithZones(renderWithZones);
});
}
scene->enqueueTransaction(transaction);
}
}
@ -1129,7 +1168,7 @@ void Model::renderDebugMeshBoxes(gpu::Batch& batch, bool forward) {
}
Extents Model::getBindExtents() const {
if (!isActive()) {
if (!isLoaded()) {
return Extents();
}
const Extents& bindExtents = getHFMModel().bindExtents;
@ -1143,7 +1182,7 @@ glm::vec3 Model::getNaturalDimensions() const {
}
Extents Model::getMeshExtents() const {
if (!isActive()) {
if (!isLoaded()) {
return Extents();
}
const Extents& extents = getHFMModel().meshExtents;
@ -1157,7 +1196,7 @@ Extents Model::getMeshExtents() const {
}
Extents Model::getUnscaledMeshExtents() const {
if (!isActive()) {
if (!isLoaded()) {
return Extents();
}
@ -1189,7 +1228,7 @@ void Model::setJointTranslation(int index, bool valid, const glm::vec3& translat
}
int Model::getParentJointIndex(int jointIndex) const {
return (isActive() && jointIndex != -1) ? getHFMModel().joints.at(jointIndex).parentIndex : -1;
return (isLoaded() && jointIndex != -1) ? getHFMModel().joints.at(jointIndex).parentIndex : -1;
}
void Model::setTextures(const QVariantMap& textures) {
@ -1290,7 +1329,7 @@ QStringList Model::getJointNames() const {
Q_RETURN_ARG(QStringList, result));
return result;
}
return isActive() ? getHFMModel().getJointNames() : QStringList();
return isLoaded() ? getHFMModel().getJointNames() : QStringList();
}
void Model::setScaleToFit(bool scaleToFit, const glm::vec3& dimensions, bool forceRescale) {
@ -1306,7 +1345,7 @@ void Model::setScaleToFit(bool scaleToFit, float largestDimension, bool forceRes
// mesh, and so we can't do the needed calculations for scaling to fit to a single largest dimension. In this
// case we will record that we do want to do this, but we will stick our desired single dimension into the
// first element of the vec3 for the non-fixed aspect ration dimensions
if (!isActive()) {
if (!isLoaded()) {
_scaleToFit = scaleToFit;
if (scaleToFit) {
_scaleToFitDimensions = glm::vec3(largestDimension, FAKE_DIMENSION_PLACEHOLDER, FAKE_DIMENSION_PLACEHOLDER);
@ -1387,7 +1426,7 @@ void Model::simulate(float deltaTime, bool fullUpdate) {
fullUpdate = updateGeometry() || fullUpdate || (_scaleToFit && !_scaledToFit)
|| (_snapModelToRegistrationPoint && !_snappedToRegistrationPoint);
if (isActive() && fullUpdate) {
if (isLoaded() && fullUpdate) {
onInvalidate();
// check for scale to fit
@ -1454,7 +1493,6 @@ void Model::updateBlendshapes() {
}
void Model::deleteGeometry() {
_deleteGeometryCounter++;
_meshStates.clear();
_rig.destroyAnimGraph();
_blendedBlendshapeCoefficients.clear();

View file

@ -116,14 +116,14 @@ public:
void setHifiRenderLayer(render::hifi::Layer layer, const render::ScenePointer& scene = nullptr);
bool isCauterized() const { return _cauterized; }
void setCauterized(bool value, const render::ScenePointer& scene);
void setCauterized(bool value, const render::ScenePointer& scene = nullptr);
void setPrimitiveMode(PrimitiveMode primitiveMode);
void setPrimitiveMode(PrimitiveMode primitiveMode, const render::ScenePointer& scene = nullptr);
PrimitiveMode getPrimitiveMode() const { return _primitiveMode; }
void setCullWithParent(bool value);
void setCullWithParent(bool value, const render::ScenePointer& scene = nullptr);
void setRenderWithZones(const QVector<QUuid>& renderWithZones);
void setRenderWithZones(const QVector<QUuid>& renderWithZones, const render::ScenePointer& scene = nullptr);
const QVector<QUuid>& getRenderWithZones() const { return _renderWithZones; }
// Access the current RenderItemKey Global Flags used by the model and applied to the render items representing the parts of the model.
@ -183,10 +183,7 @@ public:
const HFMModel& getHFMModel() const { assert(isLoaded()); return _renderGeometry->getHFMModel(); }
const MaterialMapping& getMaterialMapping() const { assert(isLoaded()); return _renderGeometry->getMaterialMapping(); }
bool isActive() const { return isLoaded(); }
bool didVisualGeometryRequestFail() const { return _visualGeometryRequestFailed; }
bool didCollisionGeometryRequestFail() const { return _collisionGeometryRequestFailed; }
glm::mat4 getWorldToHFMMatrix() const;
@ -338,7 +335,6 @@ public:
const MeshState& getMeshState(int index) { return _meshStates.at(index); }
uint32_t getGeometryCounter() const { return _deleteGeometryCounter; }
const QMap<render::ItemID, render::PayloadPointer>& getRenderItems() const { return _modelMeshRenderItemsMap; }
BlendShapeOperator getModelBlendshapeOperator() const { return _modelBlendshapeOperator; }
@ -474,10 +470,7 @@ protected:
friend class ModelMeshPartPayload;
Rig _rig;
uint32_t _deleteGeometryCounter { 0 };
bool _visualGeometryRequestFailed { false };
bool _collisionGeometryRequestFailed { false };
bool _renderItemsNeedUpdate { false };

View file

@ -3,7 +3,7 @@
// plugins/JSAPIExample/src
//
// Copyright (c) 2019-2020 humbletim (humbletim@gmail.com)
// Copyright (c) 2019 Kalila L. (kasenvr@gmail.com)
// Copyright (c) 2019 Kalila L. (somnilibertas@gmail.com)
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html