Merge branch 'master' into feature/qt-update

This commit is contained in:
David Rowe 2020-12-17 22:45:15 +13:00
commit e075f10190
71 changed files with 931 additions and 1252 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
@ -169,7 +171,7 @@ jobs:
- name: Build for Android + Quest
if: matrix.build_type == 'android'
shell: bash
working-directory: ${{runner.workspace}}/project-athena
working-directory: ${{runner.workspace}}/vircadia
run: |
echo "Pre-cache the vcpkg managed dependencies"
$PYTHON_EXEC prebuild.py --build-root ${{runner.workspace}}/build --android interface

View file

@ -66,7 +66,7 @@ The above code to suppress modules is not necessary, but will speed up the build
### Clone the repository
`git clone https://github.com/kasenvr/project-athena.git`
`git clone https://github.com/vircadia/vircadia.git`
## Building & Running
@ -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

@ -4,7 +4,7 @@
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Linux specific instructions are found in this file.
You can use the [Vircadia Builder](https://github.com/kasenvr/vircadia-builder) to build on Linux more easily. Alternatively, you can follow the manual steps below.
You can use the [Vircadia Builder](https://github.com/vircadia/vircadia-builder) to build on Linux more easily. Alternatively, you can follow the manual steps below.
## Ubuntu 16.04/18.04 specific build guide
### Ubuntu 16.04 only
@ -78,7 +78,7 @@ sudo apt-get install nodejs
Clone this repository:
```bash
git clone https://github.com/kasenvr/project-athena.git
git clone https://github.com/vircadia/vircadia.git
```
To compile a DEV version checkout the branch you need. To get a list of all tags:
@ -105,7 +105,7 @@ Qt must be installed in `$HIFI_QT_BASE/$VIRCADIA_USE_QT_VERSION/qt5-install`.
Create the build directory:
```bash
cd project-athena
cd vircadia
mkdir build
cd build
```

View file

@ -100,7 +100,7 @@ Note: You can also run Interface by launching it from command line or File Explo
For any problems after Step #6, first try this:
* Delete your locally cloned copy of the Vircadia repository
* Restart your computer
* Redownload the [repository](https://github.com/kasenvr/project-athena)
* Redownload the [repository](https://github.com/vircadia/vircadia)
* Restart directions from Step #6
#### CMake gives you the same error message repeatedly after the build fails

View file

@ -1,3 +1,4 @@
The project embraces distributed development and if you'd like to help, it would be greatly appreciated. Just open a pull request with the revisions.
Contributing
@ -6,7 +7,7 @@ Contributing
2. Clone your fork of the repository locally
```
git clone git://github.com/USERNAME/project-athena.git
git clone git://github.com/USERNAME/vircadia.git
```
3. Create a new branch
@ -20,7 +21,7 @@ Contributing
6. Update your branch
```
git remote add upstream https://github.com/kasenvr/project-athena
git remote add upstream https://github.com/vircadia/vircadia
git pull upstream master
```
@ -35,13 +36,22 @@ Contributing
*You can follow [GitHub's guide](https://help.github.com/articles/creating-a-pull-request) to find out how to create a pull request.*
Tips for Pull Requests
===
To make the QA process go as smoothly as possible.
1. Have a basic description in your pull request.
2. Write a basic test plan if you are altering or adding features.
3. If a new API is added, try to make sure that some level of basic documentation on how you can utilize it is included.
4. If an added API or feature requires an external service, try to document or link to instructions on how to create a basic working setup.
Reporting Bugs
===
1. Always update to the latest code on master, we make many merges every day and it is possible the bug has already been fixed!
2. Search [issues](https://github.com/kasenvr/project-athena/issues) to make sure that somebody has not already reported the same bug.
3. [Add](https://github.com/kasenvr/project-athena/issues/new) your report to the issues list!
2. Search [issues](https://github.com/vircadia/vircadia/issues) to make sure that somebody has not already reported the same bug.
3. [Add](https://github.com/vircadia/vircadia/issues/new) your report to the issues list!
Requesting a Feature
===
1. Search [issues](https://github.com/kasenvr/project-athena/issues) to make sure that somebody has not already requested the same feature.
2. [Add](https://github.com/kasenvr/project-athena/issues/new) your request to the issues list!
1. Search [issues](https://github.com/vircadia/vircadia/issues) to make sure that somebody has not already requested the same feature.
2. [Add](https://github.com/vircadia/vircadia/issues/new) your request to the issues list!

View file

@ -8,17 +8,17 @@ Vircadia is a 3D social software project seeking to incrementally bring about a
### Releases
[View Releases here](https://github.com/kasenvr/project-athena/releases/)
[View Releases here](https://github.com/vircadia/vircadia/releases/)
### How to build the Interface
[For Windows](https://github.com/kasenvr/project-athena/blob/master/BUILD_WIN.md)
[For Windows](https://github.com/vircadia/vircadia/blob/master/BUILD_WIN.md)
[For Mac](https://github.com/kasenvr/project-athena/blob/master/BUILD_OSX.md)
[For Mac](https://github.com/vircadia/vircadia/blob/master/BUILD_OSX.md)
[For Linux](https://github.com/kasenvr/project-athena/blob/master/BUILD_LINUX.md)
[For Linux](https://github.com/vircadia/vircadia/blob/master/BUILD_LINUX.md)
[For Linux - Vircadia Builder](https://github.com/kasenvr/vircadia-builder)
[For Linux - Vircadia Builder](https://github.com/vircadia/vircadia-builder)
### How to deploy a Server
@ -26,13 +26,13 @@ Vircadia is a 3D social software project seeking to incrementally bring about a
### How to build a Server
[For Linux - Vircadia Builder](https://github.com/kasenvr/vircadia-builder)
[For Linux - Vircadia Builder](https://github.com/vircadia/vircadia-builder)
### How to generate an Installer
[For Windows](https://github.com/kasenvr/project-athena/blob/master/INSTALL.md)
[For Windows](https://github.com/vircadia/vircadia/blob/master/INSTALL.md)
[For Linux - AppImage - Vircadia Builder](https://github.com/kasenvr/vircadia-builder/blob/master/README.md#building-appimages)
[For Linux - AppImage - Vircadia Builder](https://github.com/vircadia/vircadia-builder/blob/master/README.md#building-appimages)
### Boot to Metaverse: The Goal

View file

@ -17,7 +17,7 @@ test -z "$STABLE_BUILD" && export STABLE_BUILD=0
docker run \
--rm \
--security-opt seccomp:unconfined \
-v "${WORKSPACE}":/home/gha/project-athena \
-v "${WORKSPACE}":/home/gha/vircadia \
-e RELEASE_NUMBER \
-e RELEASE_TYPE \
-e ANDROID_APP \

View file

@ -72,17 +72,17 @@ RUN mkdir "$HIFI_BASE" && \
mkdir "$HIFI_ANDROID_PRECOMPILED"
# Download the repo
RUN git clone https://github.com/kasenvr/project-athena.git
RUN git clone https://github.com/vircadia/vircadia.git
WORKDIR /home/gha/project-athena
WORKDIR /home/gha/vircadia
RUN mkdir build
# Pre-cache the vcpkg managed dependencies
WORKDIR /home/gha/project-athena/build
WORKDIR /home/gha/vircadia/build
RUN python3 ../prebuild.py --build-root `pwd` --android interface
# Pre-cache the gradle dependencies
WORKDIR /home/gha/project-athena/android
WORKDIR /home/gha/vircadia/android
RUN ./gradlew -m tasks -PHIFI_ANDROID_PRECOMPILED=$HIFI_ANDROID_PRECOMPILED
#RUN ./gradlew extractDependencies -PHIFI_ANDROID_PRECOMPILED=$HIFI_ANDROID_PRECOMPILED

View file

@ -19,7 +19,7 @@ include(vcpkg_common_functions)
vcpkg_from_github(
OUT_SOURCE_PATH SOURCE_PATH
REPO kasenvr/etc2comp
REPO vircadia/etc2comp
REF 7f1843bf07825c21cab711360c1ddbad04641036
SHA512 d747076acda8537d39585858c793a35c3dcc9ef283d723619a47f8c81ec1454c95b3340ad35f0655a939eae5b8271c801c48a9a7568311a01903a344c44af25b
HEAD_REF master

View file

@ -3,7 +3,7 @@ include(vcpkg_common_functions)
vcpkg_from_github(
OUT_SOURCE_PATH SOURCE_PATH
REPO kasenvr/scribe
REPO vircadia/scribe
REF 1bd638a36ca771e5a68d01985b6389b71835cbd2
SHA512 dbe241d86df3912e544f6b9839873f9875df54efc93822b145e7b13243eaf2e3d690bc8a28b1e52d05bdcd7e68fca6b0b2f5c43ffd0f56a9b7a50d54dcf9e31e
HEAD_REF master

View file

@ -9,7 +9,7 @@ include(vcpkg_common_functions)
vcpkg_from_github(
OUT_SOURCE_PATH SOURCE_PATH
REPO kasenvr/nvidia-texture-tools
REPO vircadia/nvidia-texture-tools
REF 330c4d56274a0f602a5c70596e2eb670a4ed56c2
SHA512 4c0bc2f369120d696cc27710b6d33086b27eef55f537ec66b9a5c8b1839bc2426c0413670b0f65be52c5d353468f0126dfe024be1f0690611d4d7e33ac530127
HEAD_REF master

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

@ -1,3 +1,3 @@
// Here you can put a script that will be run by an assignment-client (AC)
// For examples, please go to https://github.com/kasenvr/project-athena/tree/master/script-archive/acScripts
// For examples, please go to https://github.com/vircadia/vircadia/tree/master/script-archive/acScripts
// The directory named acScripts contains assignment-client specific scripts you can try.

View file

@ -81,7 +81,7 @@ endif()
else:
print("Sorry, " + distro.name(pretty=True) + " is not supported. Please consider helping us out.")
print("It's also possible to build Qt for your distribution, please see the documentation at:")
print("https://github.com/kasenvr/project-athena/tree/master/tools/qt-builder")
print("https://github.com/vircadia/vircadia/tree/master/tools/qt-builder")
raise Exception('UNKNOWN LINUX VERSION!!!')
else:
print("System : " + platform.system())

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

@ -54,10 +54,10 @@ Rectangle {
textFormat: Text.StyledText
linkColor: "#00B4EF"
color: "white"
text: "<a href=\"https://github.com/kasenvr/project-athena\">Vircadia Github</a>."
text: "<a href=\"https://github.com/vircadia/vircadia\">Vircadia Github</a>."
size: 20
onLinkActivated: {
About.openUrl("https:/github.com/kasenvr/project-athena");
About.openUrl("https:/github.com/vircadia/vircadia");
}
}

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

@ -72,7 +72,7 @@ namespace NetworkingConstants {
const QUrl HELP_FORUM_URL { "https://forums.vircadia.dev" };
const QUrl HELP_SCRIPTING_REFERENCE_URL{ "https://apidocs.vircadia.dev/" };
const QUrl HELP_RELEASE_NOTES_URL{ "https://docs.vircadia.dev/release-notes.html" };
const QUrl HELP_BUG_REPORT_URL{ "https://github.com/kasenvr/project-athena/issues" };
const QUrl HELP_BUG_REPORT_URL{ "https://github.com/vircadia/vircadia/issues" };
const QString DEFAULT_VIRCADIA_ADDRESS = "file:///~/serverless/tutorial.json";
const QString DEFAULT_HOME_ADDRESS = "file:///~/serverless/tutorial.json";

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

@ -1,5 +1,5 @@
Collection of scripts to create server distribution packages. Most of these scripts assume
use of the build script at https://github.com/kasenvr/vircadia-builder, specifically that
use of the build script at https://github.com/vircadia/vircadia-builder, specifically that
the following directory structure exists
base folder/

View file

@ -5,8 +5,8 @@ Maintainer: Heather Anderson <heath@odysseus.anderson.name>
Build-Depends: debhelper (>= 10)
Standards-Version: 4.1.2
Homepage: https://vircadia.com
Vcs-Git: https://github.com/kasenvr/project-athena.git
Vcs-Browser: https://github.com/kasenvr/project-athena
Vcs-Git: https://github.com/vircadia/vircadia.git
Vcs-Browser: https://github.com/vircadia/vircadia
Package: vircadia-server
Architecture: any

View file

@ -9,7 +9,7 @@ Summary: Vircadia metaverse platform, based on the High Fidelity Engine.
License: ASL 2.0
URL: https://vircadia.com
Source0: https://github.com/kasenvr/vircadia-builder/blob/master/vircadia-builder
Source0: https://github.com/vircadia/vircadia-builder/blob/master/vircadia-builder
#BuildRequires: systemd-rpm-macros
BuildRequires: chrpath

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

View file

@ -102,7 +102,7 @@ def parse_args():
if True:
args = parser.parse_args()
else:
args = parser.parse_args(['--android', 'questInterface', '--build-root', 'C:/git/project-athena/android/apps/questInterface/.externalNativeBuild/cmake/debug/arm64-v8a'])
args = parser.parse_args(['--android', 'questInterface', '--build-root', 'C:/git/vircadia/android/apps/questInterface/.externalNativeBuild/cmake/debug/arm64-v8a'])
return args
def main():

View file

@ -5,8 +5,8 @@
// Created by Keb Helion, February 2020.
// Copyright 2020 Vircadia contributors.
//
// App maintained in: https://github.com/kasenvr/community-apps
// App copied to: https://github.com/kasenvr/project-athena
// App maintained in: https://github.com/vircadia/community-apps
// App copied to: https://github.com/vircadia/vircadia
//
//
// Distributed under the Apache License, Version 2.0.

View file

@ -13,7 +13,7 @@
},
"repository": {
"type": "git",
"url": "https://github.com/kasenvr/project-athena.git"
"url": "https://github.com/vircadia/vircadia.git"
},
"main": "src/main.js",
"scripts": {