diff --git a/.github/workflows/linux_server_build.yml b/.github/workflows/linux_server_build.yml index 64f1529221..084287c25b 100644 --- a/.github/workflows/linux_server_build.yml +++ b/.github/workflows/linux_server_build.yml @@ -82,16 +82,6 @@ jobs: arch: aarch64 runner: [self_hosted, type-cax41, image-arm-app-docker-ce] - - os: fedora-39 - image: docker.io/overte/overte-server-build:0.1.4-fedora-39-amd64 - arch: amd64 - runner: [self_hosted, type-cx52, image-x86-app-docker-ce] - - - os: fedora-39 - image: docker.io/overte/overte-server-build:0.1.4-fedora-39-aarch64 - arch: aarch64 - runner: [self_hosted, type-cax41, image-arm-app-docker-ce] - - os: fedora-40 image: docker.io/overte/overte-server-build:0.1.4-fedora-40-amd64 arch: amd64 @@ -224,10 +214,6 @@ jobs: else # RPM if [ "${{ matrix.os }}" == "rockylinux-9" ]; then echo "ARTIFACT_PATTERN=overte-server-$RPMVERSION-1.el9.$INSTALLER_EXT" >> $GITHUB_ENV - elif [ "${{ matrix.os }}" == "fedora-38" ]; then - echo "ARTIFACT_PATTERN=overte-server-$RPMVERSION-1.fc38.$INSTALLER_EXT" >> $GITHUB_ENV - elif [ "${{ matrix.os }}" == "fedora-39" ]; then - echo "ARTIFACT_PATTERN=overte-server-$RPMVERSION-1.fc39.$INSTALLER_EXT" >> $GITHUB_ENV elif [ "${{ matrix.os }}" == "fedora-40" ]; then echo "ARTIFACT_PATTERN=overte-server-$RPMVERSION-1.fc40.$INSTALLER_EXT" >> $GITHUB_ENV else @@ -266,7 +252,7 @@ jobs: - name: Archive cmake logs if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: cmake-logs-${{ matrix.os }}-${{ matrix.arch }}-${{ github.event.number }}.tar.xz path: cmake-logs-${{ matrix.os }}-${{ matrix.arch }}-${{ github.event.number }}.tar.xz diff --git a/.github/workflows/master_build.yml b/.github/workflows/master_build.yml index 6e060e769e..2704ea16d4 100644 --- a/.github/workflows/master_build.yml +++ b/.github/workflows/master_build.yml @@ -65,7 +65,7 @@ jobs: run: | echo "UPLOAD_PREFIX=build/overte/master" >> $GITHUB_ENV - echo ::set-output name=github_sha_short::`echo $GIT_COMMIT | cut -c1-7` + echo "{github_sha_short}={`echo $GIT_COMMIT | cut -c1-7`}" >> $GITHUB_OUTPUT echo "JOB_NAME=build (${{matrix.os}}, ${{matrix.build_type}})" >> $GITHUB_ENV echo "APP_TARGET_NAME=$APP_NAME" >> $GITHUB_ENV # Linux build variables @@ -82,7 +82,7 @@ jobs: echo "ZIP_ARGS=-r" >> $GITHUB_ENV echo "INSTALLER_EXT=dmg" >> $GITHUB_ENV echo "CMAKE_EXTRA=-DOVERTE_CPU_ARCHITECTURE= -DCMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=OFF -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -DOPENSSL_LIBRARIES=/usr/local/opt/openssl/lib -G Xcode" >> $GITHUB_ENV - echo "::set-output name=symbols_archive::${BUILD_NUMBER}-${{ matrix.build_type }}-mac-symbols.zip" + echo "symbols_archive=${BUILD_NUMBER}-${{ matrix.build_type }}-mac-symbols.zip" >> $GITHUB_ENV echo "APP_TARGET_NAME=Overte" >> $GITHUB_ENV fi # Windows build variables @@ -91,7 +91,7 @@ jobs: echo "ZIP_COMMAND=7z" >> $GITHUB_ENV echo "ZIP_ARGS=a" >> $GITHUB_ENV echo "INSTALLER_EXT=exe" >> $GITHUB_ENV - echo "CMAKE_EXTRA=-A x64" >> $GITHUB_ENV + echo "CMAKE_EXTRA=-A x64 -DJSDOC_ENABLED:BOOL=TRUE" >> $GITHUB_ENV echo "SYMBOL_REGEX=\(exe\|dll\|pdb\)" >> $GITHUB_ENV echo "symbols_archive=${BUILD_NUMBER}-${{ matrix.build_type }}-win-symbols.zip" >> $GITHUB_ENV # echo "HF_PFX_PASSPHRASE=${{secrets.pfx_key}}" >> $GITHUB_ENV diff --git a/.github/workflows/master_deploy_apidocs.yml b/.github/workflows/master_deploy_apidocs.yml index 79d4533b40..a4c501ac5a 100644 --- a/.github/workflows/master_deploy_apidocs.yml +++ b/.github/workflows/master_deploy_apidocs.yml @@ -31,7 +31,7 @@ jobs: jsdoc root.js -r api-mainpage.md -c config.json -d output - name: Deploy API-docs - uses: SamKirkland/FTP-Deploy-Action@v4.3.4 + uses: SamKirkland/FTP-Deploy-Action@v4.3.5 with: server: www531.your-server.de protocol: ftps diff --git a/.github/workflows/master_deploy_doxygen.yml b/.github/workflows/master_deploy_doxygen.yml index 9a12a165a8..d2caa15d18 100644 --- a/.github/workflows/master_deploy_doxygen.yml +++ b/.github/workflows/master_deploy_doxygen.yml @@ -29,7 +29,7 @@ jobs: doxygen Doxyfile - name: Deploy Doxygen - uses: SamKirkland/FTP-Deploy-Action@v4.3.4 + uses: SamKirkland/FTP-Deploy-Action@v4.3.5 with: server: www531.your-server.de protocol: ftps diff --git a/.github/workflows/pr_build.yml b/.github/workflows/pr_build.yml index 2bd3b629c4..c9d06d5663 100644 --- a/.github/workflows/pr_build.yml +++ b/.github/workflows/pr_build.yml @@ -64,8 +64,8 @@ jobs: runner: [self_hosted, type-cx52, image-x86-app-docker-ce] arch: amd64 build_type: full - apt-dependencies: pkg-config libxext-dev libdouble-conversion-dev libpcre2-16-0 libpulse0 libharfbuzz-dev libnss3 libnspr4 libxdamage1 libasound2 # add missing dependencies to docker image when convenient - image: docker.io/overte/overte-full-build:0.1.1-ubuntu-20.04-amd64 + # apt-dependencies: # add missing dependencies to docker image when convenient + image: docker.io/overte/overte-full-build:0.1.2-ubuntu-20.04-amd64 # Android builds are currently failing #- os: ubuntu-18.04 # build_type: android @@ -75,7 +75,7 @@ jobs: runner: [self_hosted, type-cax41, image-arm-app-docker-ce] arch: aarch64 build_type: full - image: docker.io/overte/overte-full-build:0.1.1-ubuntu-22.04-aarch64 + image: docker.io/overte/overte-full-build:0.1.2-ubuntu-22.04-aarch64 fail-fast: false runs-on: ${{matrix.runner}} container: ${{matrix.image}} @@ -137,9 +137,9 @@ jobs: echo "PYTHON_EXEC=python" >> $GITHUB_ENV echo "INSTALLER_EXT=exe" >> $GITHUB_ENV if [ "${{ matrix.build_type }}" = "full" ]; then - echo "CMAKE_EXTRA=-A x64" >> $GITHUB_ENV + echo "CMAKE_EXTRA=-A x64 -DJSDOC_ENABLED:BOOL=TRUE" >> $GITHUB_ENV else - echo "CMAKE_EXTRA=-A x64 -DCLIENT_ONLY=1" >> $GITHUB_ENV + echo "CMAKE_EXTRA=-A x64 -DJSDOC_ENABLED:BOOL=TRUE -DCLIENT_ONLY=1" >> $GITHUB_ENV fi fi # Android + Quest build variables @@ -244,7 +244,7 @@ jobs: - name: Archive cmake logs if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: cmake-logs-${{ matrix.os }}-${{ github.event.number }}.tar.xz path: ./cmake-logs-${{ matrix.os }}-${{ github.event.number }}.tar.xz diff --git a/.github/workflows/release_build.yml b/.github/workflows/release_build.yml index 7eaa7f3fa4..b72075017c 100644 --- a/.github/workflows/release_build.yml +++ b/.github/workflows/release_build.yml @@ -56,7 +56,6 @@ jobs: echo "UPLOAD_PREFIX=build/overte/release/" >> $GITHUB_ENV fi - echo ::set-output name=github_sha_short::`echo $GIT_COMMIT | cut -c1-7` echo "JOB_NAME=${{matrix.os}}, ${{matrix.build_type}}" >> $GITHUB_ENV echo "APP_TARGET_NAME=$APP_NAME" >> $GITHUB_ENV @@ -101,7 +100,7 @@ jobs: - name: Configure CMake working-directory: ${{runner.workspace}}/build shell: bash - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DVCPKG_BUILD_TYPE=release -DCLIENT_ONLY:BOOLEAN=$CLIENT_ONLY -DBYPASS_SIGNING:BOOLEAN=TRUE $CMAKE_EXTRA + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DVCPKG_BUILD_TYPE=release -DJSDOC_ENABLED:BOOL=TRUE -DCLIENT_ONLY:BOOLEAN=$CLIENT_ONLY -DBYPASS_SIGNING:BOOLEAN=TRUE $CMAKE_EXTRA - name: Build application working-directory: ${{runner.workspace}}/build diff --git a/.gitignore b/.gitignore index 90ff187027..6c35659bf3 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,7 @@ local.properties !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json +.cache # Workspace *.code-workspace diff --git a/CHANGELOG.md b/CHANGELOG.md index de11f33c5e..c95c32c268 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,9 +12,84 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), This project does **not** adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - +## [2024.11.1] 2024.11.23 -## [2024.07.1] 2023.07.12 +### Fixes +- Hard code link colors in Armored Chat (PR1083) +- ArmoredChat: Alleviate scrolling issue (PR1106) +- Armored Chat: Change the 'open in new window' character (PR1084) +- Fix mouselook ignoring setting. (PR1081) +- Fix controllerScripts uncaught exception. (PR1086) +- Fix wireshark dissector (PR1088) +- Create App: Material Assistant: Add Mtoon, Shader_simple, missing PBR properties and bug fixes. (PR1091) +- Fix login failure handling and improve logging. (PR1093) +- add a setting to workaround the GLES colorspace conversion issue (PR1105) +- Improve model load priority (PR1085) +- fix accidentally clearing url fields when you don't have view permission (PR1138) +- Avatar App: Fixed lingering references to now deleted QML element (PR1155) +- Fix selfie mode movement (PR1127) +- Fix Create App not honoring menu bar actions (PR1123) +- Fix Uuid.NULL behavior (PR1168) +- Rebuild fonts with full charset (NOT -allglyphs) (PR1172) +- fix web entities not accepting keyboard focus (PR1187) +- Fix stutter when an object is fading (PR1185) +- fix density max typo (PR1195) +- Fix ArmoredChat quick_message qml dialog colors on light theme systems (PR1196) +- Fix missing properties in Script API (PR1215) +- Fix ArmoredChat scrolling (PR1210) +- Force enable JSDoc to get scripting console autocomplete working on Windows (PR1219) +- Fix lack of entityHostType property (PR1224) +- Fix access-after-delete on leaving domain with entity scripts (PR1230) +- fix fade out not working in forward rendering (PR1234) +- Fix access-after-delete during entity script engine cleanup (PR1236) +- Fix script-related crashes on exiting a domain (PR1251) +- Update privacy policy link (PR1237) + +### Changes +- Replace Floofchat with ArmoredChat (PR961) +- MouseLook.js refactor (PR1004) +- Custom shader fallbacks (PR1058) +- Update outdated language (PR1102) +- Automated entity property serialization (PR1098) +- Create app: highlight avatar entities (PR1152) +- Update Avatar App icons (PR1141) +- Place App: Weekly promoted place (PR1153) +- Change minimum angular velocity to a lower one (PR1171) +- Places App: Persisted Maturity Filter and Default value for Newbies. (PR1164) + +### Additions +- Mirrors + Portals (PR721) +- Entity tags (PR748) +- Web Entity wantsKeyboardFocus (PR814) +- Audio Zone Properties (PR847) +- Ability to smooth model animations (PR889) +- GPU Particles (PR884) +- Unlit Shapes (PR1041) +- Ambient Light Color (PR1043) +- Dump protocol data (PR1087) +- Sound Entities (PR894) +- Zone properties for tonemapping and ambient occlusion (PR1050) +- Add bloom, haze, AO, and procedural shaders to Graphics settings (PR1053) +- Create App: Revolutionary "Paste" Url buttons for the "Create Model", "Create Material" and "Create Voxels" UI (PR1094) +- Text verticalAlignment, send entity property enums as uint8_t, fix text recalculating too often, fix textSize (PR1111) +- Create app: Grab and Equip (PR1160) +- Create App: Add "Paste" button for NewSoundDialog QML (PR1202) +- Added sounds to all incoming chat messages (PR1250) + +### Removals +- Remove (deprecated) attachments (PR1069) +- Remove unused onFirstRun.js (PR1089) +- Remove Google Poly (PR1137) +- Remove hifi screenshare (PR1165) + +### Build System +- Add CLion-style build directories to .gitignore (PR1135) + +### Security +- Sanitize notificationCore text to prevent XSS (PR1078) + + +## [2024.07.1] 2024.07.12 ### Fixes - Fix more warnings (PR1007) @@ -57,7 +132,7 @@ This project does **not** adhere to [Semantic Versioning](https://semver.org/spe - Remove remnants of RELEASE_NAME. (PR1077) -## [2024.06.1] 2023.06.24 +## [2024.06.1] 2024.06.24 ### Fixes - Fix QNetworkRequest::FollowRedirectsAttribute deprecated warning (PR711) @@ -306,9 +381,6 @@ This project does **not** adhere to [Semantic Versioning](https://semver.org/spe - Added a setting to disable snapshot notifications (PR189) - Added a setting to switch between screenshot formats (PR134) -### Removals -- - ### Build system - Fixed "may be used uninitialized" warning for blendtime (PR269) - Updated SPIRV-Cross to sdk-1.3.231.1 (PR271) diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index 7c288334ba..fd7806b82f 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -567,6 +567,7 @@ void EntityScriptServer::addingEntity(const EntityItemID& entityID) { void EntityScriptServer::deletingEntity(const EntityItemID& entityID) { if (_entityViewer.getTree() && !_shuttingDown && _entitiesScriptManager) { + // TODO: Check if this is running on script engine thread, otherwise lambda capturing script engine pointer is needed _entitiesScriptManager->unloadEntityScript(entityID, true); } } @@ -584,6 +585,7 @@ void EntityScriptServer::checkAndCallPreload(const EntityItemID& entityID, bool EntityScriptDetails details; bool isRunning = _entitiesScriptManager->getEntityScriptDetails(entityID, details); if (entity && (forceRedownload || !isRunning || details.scriptText != entity->getServerScripts())) { + // TODO: Check if this is running on script engine thread, otherwise lambda capturing script engine pointer is needed if (isRunning) { _entitiesScriptManager->unloadEntityScript(entityID, true); } diff --git a/hifi_qt.py b/hifi_qt.py index b4ab5e9b3c..053ff997b7 100644 --- a/hifi_qt.py +++ b/hifi_qt.py @@ -157,7 +157,7 @@ endif() u_major = int( distro.major_version() or '0' ) if distro.id() == 'ubuntu' or distro.id() == 'linuxmint': if (distro.id() == 'ubuntu' and u_major == 20) or distro.id() == 'linuxmint' and u_major == 20: - self.qtUrl = self.assets_url + '/dependencies/qt5/qt5-install-5.15.14-2024.06.17-kde_570f5b2105df1ea052bec0d6dbf8a00137274371-ubuntu-20.04-amd64.tar.xz' + self.qtUrl = self.assets_url + '/dependencies/qt5/qt5-install-5.15.16-2024.12.14-kde_32be154325bfba3ad2ba8bf75dad702f3588e8d3-ubuntu-20.04-amd64.tar.xz' elif (distro.id() == 'ubuntu' and u_major > 20) or (distro.id() == 'linuxmint' and u_major > 20): self.__no_qt_package_error() else: diff --git a/interface/resources/qml/LoginDialog/SignUpBody.qml b/interface/resources/qml/LoginDialog/SignUpBody.qml index 95cc833b56..b133523211 100644 --- a/interface/resources/qml/LoginDialog/SignUpBody.qml +++ b/interface/resources/qml/LoginDialog/SignUpBody.qml @@ -3,6 +3,7 @@ // // Created by Stephen Birarda on 7 Dec 2016 // Copyright 2016 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -395,7 +396,7 @@ Item { text: signUpBody.termsContainerText Component.onCompleted: { // with the link. - termsText.text = qsTr("By signing up, you agree to Overte Terms of Service") + termsText.text = qsTr("By signing up, you agree to Overte Terms of Service") } } diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index a17eb0c765..b842b736d4 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -1039,6 +1039,14 @@ Rectangle { anchors.top: pal.top; anchors.topMargin: 10; anchors.left: pal.left; + RalewayRegular { + text: " Display Name"; + size: hifi.fontSizes.tabularData; + anchors.left: parent.left; + + color: hifi.colors.baseGrayHighlight; + verticalAlignment: Text.AlignTop; + } // This NameCard refers to the current user's NameCard (the one above the nearbyTable) NameCard { id: myCard; @@ -1054,7 +1062,7 @@ Rectangle { width: myCardWidth; height: parent.height; // Anchors - anchors.top: parent.top + anchors.top: parent.children[0].bottom; anchors.left: parent.left; } Item { @@ -1066,7 +1074,7 @@ Rectangle { RalewayRegular { id: availabilityText; - text: "set availability"; + text: "Availability"; // Text size size: hifi.fontSizes.tabularData; // Anchors diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index b2a383f590..20a68237cf 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -2,6 +2,8 @@ // Created by Dante Ruiz on 6/5/17. // Copyright 2017 High Fidelity, Inc. // Copyright 2020 Vircadia contributors. +// Copyright 2024 Overte e.V. +// // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -928,7 +930,7 @@ Flickable { hoverEnabled: true onEntered: privacyPolicyUnderline.visible = true; onExited: privacyPolicyUnderline.visible = false; - onClicked: About.openUrl("https://overte.org/privacy-policy"); + onClicked: About.openUrl("https://overte.org/privacy_policy.html"); } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 762c08c394..6bc57bd200 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -159,6 +159,7 @@ const bool DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR = true; const bool DEFAULT_HMD_TABLET_BECOMES_TOOLBAR = false; const bool DEFAULT_PREFER_STYLUS_OVER_LASER = false; const bool DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS = false; +const bool DEFAULT_SHOW_GRAPHICS_ICON = true; const bool DEFAULT_MINI_TABLET_ENABLED = false; const bool DEFAULT_AWAY_STATE_WHEN_FOCUS_LOST_IN_VR_ENABLED = true; @@ -224,6 +225,7 @@ Application::Application( _hmdTabletBecomesToolbarSetting("hmdTabletBecomesToolbar", DEFAULT_HMD_TABLET_BECOMES_TOOLBAR), _preferStylusOverLaserSetting("preferStylusOverLaser", DEFAULT_PREFER_STYLUS_OVER_LASER), _preferAvatarFingerOverStylusSetting("preferAvatarFingerOverStylus", DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS), + _showGraphicsIconSetting("showGraphicsIcon", DEFAULT_SHOW_GRAPHICS_ICON), _constrainToolbarPosition("toolbar/constrainToolbarToCenterX", true), _awayStateWhenFocusLostInVREnabled("awayStateWhenFocusLostInVREnabled", DEFAULT_AWAY_STATE_WHEN_FOCUS_LOST_IN_VR_ENABLED), _preferredCursor("preferredCursor", DEFAULT_CURSOR_NAME), diff --git a/interface/src/Application.h b/interface/src/Application.h index 941559f265..df72535b0d 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -189,6 +189,9 @@ public: bool getPreferAvatarFingerOverStylus() { return _preferAvatarFingerOverStylusSetting.get(); } void setPreferAvatarFingerOverStylus(bool value) { _preferAvatarFingerOverStylusSetting.set(value); } + bool getShowGraphicsIcon() { return _showGraphicsIconSetting.get(); } + void setShowGraphicsIcon(bool value); + bool getMiniTabletEnabled() { return _miniTabletEnabledSetting.get(); } void setMiniTabletEnabled(bool enabled); @@ -785,6 +788,7 @@ private: Setting::Handle _hmdTabletBecomesToolbarSetting; Setting::Handle _preferStylusOverLaserSetting; Setting::Handle _preferAvatarFingerOverStylusSetting; + Setting::Handle _showGraphicsIconSetting; Setting::Handle _constrainToolbarPosition; Setting::Handle _awayStateWhenFocusLostInVREnabled; Setting::Handle _preferredCursor; diff --git a/interface/src/Application_UI.cpp b/interface/src/Application_UI.cpp index 04331b61e9..6d4dbcbef3 100644 --- a/interface/src/Application_UI.cpp +++ b/interface/src/Application_UI.cpp @@ -269,6 +269,11 @@ void Application::setHmdTabletBecomesToolbarSetting(bool value) { updateSystemTabletMode(); } +void Application::setShowGraphicsIcon(bool value) { + _showGraphicsIconSetting.set(value); + DependencyManager::get()->sendLocalMessage("Overte-ShowGraphicsIconChanged", ""); +} + void Application::setMiniTabletEnabled(bool enabled) { _miniTabletEnabledSetting.set(enabled); emit miniTabletEnabledChanged(enabled); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 69b2d1b735..19159ca993 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -76,6 +76,8 @@ #include "WarningsSuppression.h" #include "ScriptPermissions.h" +#include "Application.h" + using namespace std; const float DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES = 30.0f; @@ -227,6 +229,7 @@ MyAvatar::MyAvatar(QThread* thread) : _scaleSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "scale", _targetScale), _yawSpeedSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "yawSpeed", _yawSpeed), _hmdYawSpeedSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "hmdYawSpeed", _hmdYawSpeed), + _cameraSensitivitySetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "cameraSensitivity", qApp->getCamera().getSensitivity()), _pitchSpeedSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "pitchSpeed", _pitchSpeed), _fullAvatarURLSetting(QStringList() << SETTINGS_FULL_PRIVATE_GROUP_NAME << AVATAR_SETTINGS_GROUP_NAME << "fullAvatarURL", AvatarData::defaultFullAvatarModelUrl()), @@ -1325,6 +1328,7 @@ void MyAvatar::saveData() { _scaleSetting.set(_targetScale); _yawSpeedSetting.set(_yawSpeed); _hmdYawSpeedSetting.set(_hmdYawSpeed); + _cameraSensitivitySetting.set(getCameraSensitivity()); _pitchSpeedSetting.set(_pitchSpeed); // only save the fullAvatarURL if it has not been overwritten on command line @@ -2085,6 +2089,7 @@ void MyAvatar::loadData() { _yawSpeed = _yawSpeedSetting.get(_yawSpeed); _hmdYawSpeed = _hmdYawSpeedSetting.get(_hmdYawSpeed); + setCameraSensitivity(_cameraSensitivitySetting.get(getCameraSensitivity())); _pitchSpeed = _pitchSpeedSetting.get(_pitchSpeed); _prefOverrideAnimGraphUrl.set(_animGraphURLSetting.get().toString()); @@ -7003,3 +7008,11 @@ void MyAvatar::resetPointAt() { POINT_BLEND_LINEAR_ALPHA_NAME, POINT_ALPHA_BLENDING); } } + +float MyAvatar::getCameraSensitivity() const { + return qApp->getCamera().getSensitivity(); +} + +void MyAvatar::setCameraSensitivity(float cameraSensitivity) { + qApp->getCamera().setSensitivity(cameraSensitivity); +} diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 2777d2c82f..a3586db6db 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1407,6 +1407,9 @@ public: float getHMDYawSpeed() const { return _hmdYawSpeed; } void setHMDYawSpeed(float speed) { _hmdYawSpeed = speed; } + float getCameraSensitivity() const; + void setCameraSensitivity(float cameraSensitivity); + static const float ZOOM_MIN; static const float ZOOM_MAX; static const float ZOOM_DEFAULT; @@ -3007,6 +3010,7 @@ private: Setting::Handle _scaleSetting; Setting::Handle _yawSpeedSetting; Setting::Handle _hmdYawSpeedSetting; + Setting::Handle _cameraSensitivitySetting; Setting::Handle _pitchSpeedSetting; Setting::Handle _fullAvatarURLSetting; Setting::Handle _fullAvatarModelNameSetting; diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 65e4daa5e0..4c87f12998 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -225,6 +225,12 @@ void setupPreferences() { preferences->addPreference(delaySlider); } + { + auto getter = []() -> bool { return qApp->getShowGraphicsIcon(); }; + auto setter = [](bool value) { qApp->setShowGraphicsIcon(value); }; + preferences->addPreference(new CheckPreference(UI_CATEGORY, "Show Graphics icon on tablet and toolbar", getter, setter)); + } + static const QString VIEW_CATEGORY{ "View" }; { auto getter = [myAvatar]()->float { return myAvatar->getRealWorldFieldOfView(); }; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 4b63dcb932..fb22db3ce0 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -994,9 +994,9 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const QString statsFormat = QString("(%1 Kbps, %2 Hz)"); if (!renderedDisplayName.isEmpty()) { - statsFormat.prepend(" - "); + statsFormat.append("\n"); } - renderedDisplayName += statsFormat.arg(QString::number(kilobitsPerSecond, 'f', 2)).arg(getReceiveRate()); + renderedDisplayName = statsFormat.arg(QString::number(kilobitsPerSecond, 'f', 2)).arg(getReceiveRate()) + renderedDisplayName; } // Compute display name extent/position offset @@ -1010,18 +1010,18 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const // Compute background position/size static const float SLIGHTLY_IN_FRONT = 0.1f; static const float BORDER_RELATIVE_SIZE = 0.1f; - static const float BEVEL_FACTOR = 0.1f; + // static const float BEVEL_FACTOR = 0.1f; const int border = BORDER_RELATIVE_SIZE * nameDynamicRect.height(); - const int left = text_x - border; - const int bottom = text_y - border; - const int width = nameDynamicRect.width() + 2.0f * border; + // FIXME: Beveled box is broken + // const int left = text_x - border; + // const int bottom = text_y - border; + // const int width = nameDynamicRect.width() + 2.0f * border; const int height = nameDynamicRect.height() + 2.0f * border; - const int bevelDistance = BEVEL_FACTOR * height; + // const int bevelDistance = BEVEL_FACTOR * height; // Display name and background colors glm::vec4 textColor(0.93f, 0.93f, 0.93f, _displayNameAlpha); - glm::vec4 backgroundColor(0.2f, 0.2f, 0.2f, - (_displayNameAlpha / DISPLAYNAME_ALPHA) * DISPLAYNAME_BACKGROUND_ALPHA); + glm::vec4 backgroundColor(0.2f, 0.2f, 0.2f,(_displayNameAlpha / DISPLAYNAME_ALPHA) * DISPLAYNAME_BACKGROUND_ALPHA); // Compute display name transform auto textTransform = calculateDisplayNameTransform(view, textPosition); @@ -1029,12 +1029,11 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const textTransform.postScale(1.0f / height); batch.setModelTransform(textTransform); - { - PROFILE_RANGE_BATCH(batch, __FUNCTION__":renderBevelCornersRect"); - DependencyManager::get()->bindSimpleProgram(batch, false, false, true, true, true, forward); - DependencyManager::get()->renderBevelCornersRect(batch, left, bottom, width, height, - bevelDistance, backgroundColor, _nameRectGeometryID); - } + // { + // PROFILE_RANGE_BATCH(batch, __FUNCTION__":renderBevelCornersRect"); + // DependencyManager::get()->bindSimpleProgram(batch, false, false, true, true, true, forward); + // DependencyManager::get()->renderBevelCornersRect(batch, left, bottom, width, height, bevelDistance, backgroundColor, _nameRectGeometryID); + // } // Render actual name QByteArray nameUTF8 = renderedDisplayName.toLocal8Bit(); @@ -1044,7 +1043,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const batch.setModelTransform(textTransform); { PROFILE_RANGE_BATCH(batch, __FUNCTION__":renderText"); - displayNameRenderer->draw(batch, { nameUTF8.data(), textColor, { text_x, -text_y }, glm::vec2(-1.0f), forward }); + displayNameRenderer->draw(batch, { nameUTF8.data(), textColor, { text_x, -text_y }, glm::vec2(-1.0f), TextAlignment::LEFT, forward }); } } } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 8fba576616..188c68521e 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -220,8 +220,11 @@ void EntityTreeRenderer::setupEntityScriptEngineSignals(const ScriptManagerPoint void EntityTreeRenderer::resetPersistentEntitiesScriptEngine() { // This runs script engine shutdown procedure in a separate thread, avoiding a deadlock when script engine is doing // a blocking call to main thread - if (_persistentEntitiesScriptManager) { - QtConcurrent::run([manager = _persistentEntitiesScriptManager] { + ScriptManagerPointer scriptManager = _persistentEntitiesScriptManager; + // Clear the pointer before lambda is run on another thread. + _persistentEntitiesScriptManager.reset(); + if (scriptManager) { + QtConcurrent::run([manager = scriptManager] { manager->unloadAllEntityScripts(true); manager->stop(); manager->waitTillDoneRunning(); @@ -251,8 +254,11 @@ void EntityTreeRenderer::resetPersistentEntitiesScriptEngine() { void EntityTreeRenderer::resetNonPersistentEntitiesScriptEngine() { // This runs script engine shutdown procedure in a separate thread, avoiding a deadlock when script engine is doing // a blocking call to main thread - if (_nonPersistentEntitiesScriptManager) { - QtConcurrent::run([manager = _nonPersistentEntitiesScriptManager] { + ScriptManagerPointer scriptManager = _nonPersistentEntitiesScriptManager; + // Release the pointer as soon as possible. + _nonPersistentEntitiesScriptManager.reset(); + if (scriptManager) { + QtConcurrent::run([manager = scriptManager] { manager->unloadAllEntityScripts(true); manager->stop(); manager->waitTillDoneRunning(); @@ -288,7 +294,10 @@ void EntityTreeRenderer::stopDomainAndNonOwnedEntities() { EntityItemPointer entityItem = getTree()->findEntityByEntityItemID(entityID); if (entityItem && !entityItem->getScript().isEmpty()) { if (!(entityItem->isLocalEntity() || entityItem->isMyAvatarEntity())) { - _nonPersistentEntitiesScriptManager->unloadEntityScript(entityID, true); + auto scriptEnginePtr = _nonPersistentEntitiesScriptManager; + QMetaObject::invokeMethod(scriptEnginePtr.get(), [scriptEnginePtr, entityID]{ + scriptEnginePtr->unloadEntityScript(entityID, true); + }); } } } @@ -1110,7 +1119,9 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) { if (_currentEntitiesInside.contains(entityID)) { scriptEngine->callEntityScriptMethod(entityID, "leaveEntity"); } - scriptEngine->unloadEntityScript(entityID, true); + QMetaObject::invokeMethod(scriptEngine.get(), [scriptEngine, entityID]{ + scriptEngine->unloadEntityScript(entityID, true); + }); } auto scene = _viewState->getMain3DScene(); @@ -1163,7 +1174,9 @@ void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID, bool if (_currentEntitiesInside.contains(entityID)) { scriptEngine->callEntityScriptMethod(entityID, "leaveEntity"); } - scriptEngine->unloadEntityScript(entityID); + QMetaObject::invokeMethod(scriptEngine.get(), [scriptEngine, entityID]{ + scriptEngine->unloadEntityScript(entityID); + }); } entity->scriptHasUnloaded(); } diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 178e122c32..593a3c020b 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -4,6 +4,7 @@ // // Created by Clement on 4/22/15. // Copyright 2015 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -39,46 +40,46 @@ ZoneEntityRenderer::ZoneEntityRenderer(const EntityItemPointer& entity) void ZoneEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entity) { if (_stage) { if (!LightStage::isIndexInvalid(_sunIndex)) { - _stage->removeLight(_sunIndex); + _stage->removeElement(_sunIndex); _sunIndex = INVALID_INDEX; } if (!LightStage::isIndexInvalid(_ambientIndex)) { - _stage->removeLight(_ambientIndex); + _stage->removeElement(_ambientIndex); _ambientIndex = INVALID_INDEX; } } if (_backgroundStage) { if (!BackgroundStage::isIndexInvalid(_backgroundIndex)) { - _backgroundStage->removeBackground(_backgroundIndex); + _backgroundStage->removeElement(_backgroundIndex); _backgroundIndex = INVALID_INDEX; } } if (_hazeStage) { if (!HazeStage::isIndexInvalid(_hazeIndex)) { - _hazeStage->removeHaze(_hazeIndex); + _hazeStage->removeElement(_hazeIndex); _hazeIndex = INVALID_INDEX; } } if (_bloomStage) { if (!BloomStage::isIndexInvalid(_bloomIndex)) { - _bloomStage->removeBloom(_bloomIndex); + _bloomStage->removeElement(_bloomIndex); _bloomIndex = INVALID_INDEX; } } if (_tonemappingStage) { if (!TonemappingStage::isIndexInvalid(_tonemappingIndex)) { - _tonemappingStage->removeTonemapping(_tonemappingIndex); + _tonemappingStage->removeElement(_tonemappingIndex); _tonemappingIndex = INVALID_INDEX; } } if (_ambientOcclusionStage) { if (!AmbientOcclusionStage::isIndexInvalid(_ambientOcclusionIndex)) { - _ambientOcclusionStage->removeAmbientOcclusion(_ambientOcclusionIndex); + _ambientOcclusionStage->removeElement(_ambientOcclusionIndex); _ambientOcclusionIndex = INVALID_INDEX; } } @@ -123,7 +124,7 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { { // Sun if (_needSunUpdate) { if (LightStage::isIndexInvalid(_sunIndex)) { - _sunIndex = _stage->addLight(_sunLight); + _sunIndex = _stage->addElement(_sunLight); } else { _stage->updateLightArrayBuffer(_sunIndex); } @@ -136,7 +137,7 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { if (_needAmbientUpdate) { if (LightStage::isIndexInvalid(_ambientIndex)) { - _ambientIndex = _stage->addLight(_ambientLight); + _ambientIndex = _stage->addElement(_ambientLight); } else { _stage->updateLightArrayBuffer(_ambientIndex); } @@ -149,7 +150,7 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { if (_needBackgroundUpdate) { if (BackgroundStage::isIndexInvalid(_backgroundIndex)) { - _backgroundIndex = _backgroundStage->addBackground(_background); + _backgroundIndex = _backgroundStage->addElement(_background); } _needBackgroundUpdate = false; } @@ -158,7 +159,7 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { { if (_needHazeUpdate) { if (HazeStage::isIndexInvalid(_hazeIndex)) { - _hazeIndex = _hazeStage->addHaze(_haze); + _hazeIndex = _hazeStage->addElement(_haze); } _needHazeUpdate = false; } @@ -167,7 +168,7 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { { if (_needBloomUpdate) { if (BloomStage::isIndexInvalid(_bloomIndex)) { - _bloomIndex = _bloomStage->addBloom(_bloom); + _bloomIndex = _bloomStage->addElement(_bloom); } _needBloomUpdate = false; } @@ -176,7 +177,7 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { { if (_needTonemappingUpdate) { if (TonemappingStage::isIndexInvalid(_tonemappingIndex)) { - _tonemappingIndex = _tonemappingStage->addTonemapping(_tonemapping); + _tonemappingIndex = _tonemappingStage->addElement(_tonemapping); } _needTonemappingUpdate = false; } @@ -185,7 +186,7 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { { if (_needAmbientOcclusionUpdate) { if (AmbientOcclusionStage::isIndexInvalid(_ambientOcclusionIndex)) { - _ambientOcclusionIndex = _ambientOcclusionStage->addAmbientOcclusion(_ambientOcclusion); + _ambientOcclusionIndex = _ambientOcclusionStage->addElement(_ambientOcclusion); } _needAmbientOcclusionUpdate = false; } @@ -205,9 +206,9 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { } if (_skyboxMode == COMPONENT_MODE_DISABLED) { - _backgroundStage->_currentFrame.pushBackground(INVALID_INDEX); + _backgroundStage->_currentFrame.pushElement(INVALID_INDEX); } else if (_skyboxMode == COMPONENT_MODE_ENABLED) { - _backgroundStage->_currentFrame.pushBackground(_backgroundIndex); + _backgroundStage->_currentFrame.pushElement(_backgroundIndex); } if (_ambientLightMode == COMPONENT_MODE_DISABLED) { @@ -218,25 +219,25 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { // Haze only if the mode is not inherit, as the model deals with on/off if (_hazeMode != COMPONENT_MODE_INHERIT) { - _hazeStage->_currentFrame.pushHaze(_hazeIndex); + _hazeStage->_currentFrame.pushElement(_hazeIndex); } if (_bloomMode == COMPONENT_MODE_DISABLED) { - _bloomStage->_currentFrame.pushBloom(INVALID_INDEX); + _bloomStage->_currentFrame.pushElement(INVALID_INDEX); } else if (_bloomMode == COMPONENT_MODE_ENABLED) { - _bloomStage->_currentFrame.pushBloom(_bloomIndex); + _bloomStage->_currentFrame.pushElement(_bloomIndex); } if (_tonemappingMode == COMPONENT_MODE_DISABLED) { - _tonemappingStage->_currentFrame.pushTonemapping(0); // Use the fallback tonemapping for "off" + _tonemappingStage->_currentFrame.pushElement(0); // Use the fallback tonemapping for "off" } else if (_tonemappingMode == COMPONENT_MODE_ENABLED) { - _tonemappingStage->_currentFrame.pushTonemapping(_tonemappingIndex); + _tonemappingStage->_currentFrame.pushElement(_tonemappingIndex); } if (_ambientOcclusionMode == COMPONENT_MODE_DISABLED) { - _ambientOcclusionStage->_currentFrame.pushAmbientOcclusion(INVALID_INDEX); + _ambientOcclusionStage->_currentFrame.pushElement(INVALID_INDEX); } else if (_ambientOcclusionMode == COMPONENT_MODE_ENABLED) { - _ambientOcclusionStage->_currentFrame.pushAmbientOcclusion(_ambientOcclusionIndex); + _ambientOcclusionStage->_currentFrame.pushElement(_ambientOcclusionIndex); } } diff --git a/libraries/entities/src/EntityItem.cpp.in b/libraries/entities/src/EntityItem.cpp.in index 0d3f721c91..199af74bd5 100644 --- a/libraries/entities/src/EntityItem.cpp.in +++ b/libraries/entities/src/EntityItem.cpp.in @@ -77,6 +77,11 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param @Base_REQUESTED_PROPS@ + // Some of the properties not transmitted over network need to be added manually here: + requestedProperties += PROP_ENTITY_HOST_TYPE; + requestedProperties += PROP_OWNING_AVATAR_ID; + requestedProperties += PROP_VISIBLE_IN_SECONDARY_CAMERA; + return requestedProperties; } diff --git a/libraries/entities/src/EntityItemProperties.txt b/libraries/entities/src/EntityItemProperties.txt index a375ea75eb..6fde40d0ab 100644 --- a/libraries/entities/src/EntityItemProperties.txt +++ b/libraries/entities/src/EntityItemProperties.txt @@ -30,7 +30,7 @@ group:grab, enum:MIRROR_MODE prop:mirrorMode type:MirrorMode default:MirrorMode::NONE enum renderProp, enum:PORTAL_EXIT_ID prop:portalExitID type:QUuid default:UNKNOWN_ENTITY_ID renderProp, Physics -enum:DENSITY prop:density type:float default:ENTITY_ITEM_DEFAULT_DENSITY min:ENTITY_ITEM_MIN_DENSITY max:ENTITY_ITEM_MIN_DENSITY, +enum:DENSITY prop:density type:float default:ENTITY_ITEM_DEFAULT_DENSITY min:ENTITY_ITEM_MIN_DENSITY max:ENTITY_ITEM_MAX_DENSITY, enum:VELOCITY prop:velocity type:vec3 default:ENTITY_ITEM_DEFAULT_VELOCITY inherited variableCopyGetter:getLocalVelocity variableNetworkGetter:getLocalVelocity() variableNetworkSetter:customUpdateVelocityFromNetwork debugString:"m/s" debugGetter:getWorldVelocity(), enum:ANGULAR_VELOCITY prop:angularVelocity type:vec3 default:ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY inherited variableCopyGetter:getLocalAngularVelocity variableNetworkGetter:getLocalAngularVelocity() variableNetworkSetter:customUpdateAngularVelocityFromNetwork debugGetter:getWorldAngularVelocity(), enum:GRAVITY prop:gravity type:vec3 default:ENTITY_ITEM_DEFAULT_GRAVITY debugString:"m/s^2", diff --git a/libraries/entities/src/EntityItemPropertiesDocs.cpp b/libraries/entities/src/EntityItemPropertiesDocs.cpp index 8f8959165c..8195161b77 100644 --- a/libraries/entities/src/EntityItemPropertiesDocs.cpp +++ b/libraries/entities/src/EntityItemPropertiesDocs.cpp @@ -935,7 +935,9 @@ * * @typedef {object} Entities.EntityProperties-Image * @property {Vec3} dimensions=0.1,0.1,0.01 - The dimensions of the entity. - * @property {string} imageURL="" - The URL of the image to use. + * @property {string} imageURL="" - The URL of the image to use. It can also contain a base64 encoded image, in the same format as glTF. + * For network transmitted entities there's about 1000-character limit for the length of this field. For base64 image + * the property string needs to begin with `data:image/png;base64,`, `data:image/jpeg;base64,` or `data:image/webp;base64,`. * @property {boolean} emissive=false - true if the image should be emissive (unlit), false if it * shouldn't. * @property {boolean} keepAspectRatio=true - true if the image should maintain its aspect ratio, diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 3cf8184913..a4e6bf6e05 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -288,6 +288,10 @@ public: _glUniformMatrix3fv(location, 1, false, glm::value_ptr(v)); } + void _glUniform(int location, const glm::mat4& v) { + _glUniformMatrix4fv(location, 1, false, glm::value_ptr(v)); + } + // Maybe useful but shoudln't be public. Please convince me otherwise // Well porting to gles i need it... void runLambda(std::function f); diff --git a/libraries/graphics/src/graphics/Haze.cpp b/libraries/graphics/src/graphics/Haze.cpp index 9e3cc15c57..c53dc680b0 100644 --- a/libraries/graphics/src/graphics/Haze.cpp +++ b/libraries/graphics/src/graphics/Haze.cpp @@ -4,6 +4,7 @@ // // Created by Nissim Hadar on 9/13/2017. // Copyright 2014 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -182,3 +183,7 @@ void Haze::setHazeBackgroundBlend(const float hazeBackgroundBlend) { _hazeParametersBuffer.edit().hazeBackgroundBlend = newBlend; } } + +bool Haze::isActive() const { + return (_hazeParametersBuffer.get().hazeMode & HAZE_MODE_IS_ACTIVE) == HAZE_MODE_IS_ACTIVE; +} diff --git a/libraries/graphics/src/graphics/Haze.h b/libraries/graphics/src/graphics/Haze.h index 25004f098f..415237b879 100644 --- a/libraries/graphics/src/graphics/Haze.h +++ b/libraries/graphics/src/graphics/Haze.h @@ -4,6 +4,7 @@ // // Created by Nissim Hadar on 9/13/2017. // Copyright 2014 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -95,6 +96,8 @@ namespace graphics { using UniformBufferView = gpu::BufferView; UniformBufferView getHazeParametersBuffer() const { return _hazeParametersBuffer; } + bool isActive() const; + protected: class Parameters { public: diff --git a/libraries/material-networking/src/material-networking/TextureCache.cpp b/libraries/material-networking/src/material-networking/TextureCache.cpp index 840fa50a0a..e2d4822543 100644 --- a/libraries/material-networking/src/material-networking/TextureCache.cpp +++ b/libraries/material-networking/src/material-networking/TextureCache.cpp @@ -254,6 +254,18 @@ NetworkTexturePointer TextureCache::getTexture(const QUrl& url, image::TextureUs if (url.scheme() == RESOURCE_SCHEME) { return getResourceTexture(url); } + + QString urlString = url.toString(); + if (content.isEmpty() && (urlString.startsWith("data:image/jpeg;base64,") + || urlString.startsWith("data:image/png;base64,") + || urlString.startsWith("data:image/webp;base64,"))) { + QString binaryUrl = urlString.split(",")[1]; + auto decodedContent = binaryUrl.isEmpty() ? QByteArray() : QByteArray::fromBase64(binaryUrl.toUtf8()); + if (!decodedContent.isEmpty()) { + return getTexture(url, type, decodedContent, maxNumPixels, sourceChannel); + } + } + QString decodedURL = QUrl::fromPercentEncoding(url.toEncoded()); if (decodedURL.startsWith("{")) { return getTextureByUUID(decodedURL); diff --git a/libraries/model-serializers/src/GLTFSerializer.cpp b/libraries/model-serializers/src/GLTFSerializer.cpp index 1440fb22d2..d4cee367d3 100644 --- a/libraries/model-serializers/src/GLTFSerializer.cpp +++ b/libraries/model-serializers/src/GLTFSerializer.cpp @@ -1335,7 +1335,7 @@ HFMTexture GLTFSerializer::getHFMTexture(const cgltf_texture *texture) { hfmTex.filename = textureUrl.toEncoded().append(QString::number(imageIndex).toUtf8()); } - if (url.contains("data:image/jpeg;base64,") || url.contains("data:image/png;base64,") || url.contains("data:image/webp;base64,")) { + if (url.startsWith("data:image/jpeg;base64,") || url.startsWith("data:image/png;base64,") || url.startsWith("data:image/webp;base64,")) { hfmTex.content = requestEmbeddedData(url); } } diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index 3162ab95e6..7b202ad625 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -356,16 +356,53 @@ void Procedural::prepare(gpu::Batch& batch, } } // Then fill in every reflections the new custom bindings - int customSlot = procedural::slot::uniform::Custom; + size_t customSlot = procedural::slot::uniform::Custom; + _slotMap.clear(); for (const auto& key : _data.uniforms.keys()) { - std::string uniformName = key.toLocal8Bit().data(); - for (auto reflection : allFragmentReflections) { - reflection->uniforms[uniformName] = customSlot; + bool isArrayUniform = false; + size_t numSlots = 0; + const QJsonValue& value = _data.uniforms[key]; + if (value.isDouble()) { + numSlots = 1; + } else if (value.isArray()) { + const QJsonArray valueArray = value.toArray(); + if (valueArray.size() > 0) { + if (valueArray[0].isArray()) { + const size_t valueLength = valueArray[0].toArray().size(); + size_t count = 0; + for (const QJsonValue& value : valueArray) { + if (value.isArray()) { + const QJsonArray innerValueArray = value.toArray(); + if (innerValueArray.size() == valueLength) { + if (valueLength == 3 || valueLength == 4 || valueLength == 9 || valueLength == 16) { + count++; + isArrayUniform = true; + } + } + } + } + numSlots = count; + } else if (valueArray[0].isDouble()) { + numSlots = 1; + } + } } - for (auto reflection : allVertexReflections) { - reflection->uniforms[uniformName] = customSlot; + + if (numSlots > 0) { + std::string uniformName = key.toLocal8Bit().data(); + std::string trueUniformName = uniformName; + if (isArrayUniform) { + trueUniformName += "[0]"; + } + for (auto reflection : allFragmentReflections) { + reflection->uniforms[trueUniformName] = customSlot; + } + for (auto reflection : allVertexReflections) { + reflection->uniforms[trueUniformName] = customSlot; + } + _slotMap[uniformName] = customSlot; + customSlot += numSlots; } - ++customSlot; } } @@ -448,59 +485,138 @@ void Procedural::prepare(gpu::Batch& batch, } } - void Procedural::setupUniforms() { _uniforms.clear(); // Set any userdata specified uniforms - int slot = procedural::slot::uniform::Custom; for (const auto& key : _data.uniforms.keys()) { - std::string uniformName = key.toLocal8Bit().data(); - QJsonValue value = _data.uniforms[key]; + const std::string uniformName = key.toLocal8Bit().data(); + auto slotItr = _slotMap.find(uniformName); + if (slotItr == _slotMap.end()) { + continue; + } + + const size_t slot = slotItr->second; + const QJsonValue& value = _data.uniforms[key]; if (value.isDouble()) { - float v = value.toDouble(); + const float v = value.toDouble(); _uniforms.push_back([slot, v](gpu::Batch& batch) { batch._glUniform1f(slot, v); }); } else if (value.isArray()) { - auto valueArray = value.toArray(); - switch (valueArray.size()) { - case 0: - break; - - case 1: { - float v = valueArray[0].toDouble(); - _uniforms.push_back([slot, v](gpu::Batch& batch) { batch._glUniform1f(slot, v); }); - break; - } - - case 2: { - glm::vec2 v{ valueArray[0].toDouble(), valueArray[1].toDouble() }; - _uniforms.push_back([slot, v](gpu::Batch& batch) { batch._glUniform2f(slot, v.x, v.y); }); - break; - } - - case 3: { - glm::vec3 v{ - valueArray[0].toDouble(), - valueArray[1].toDouble(), - valueArray[2].toDouble(), - }; - _uniforms.push_back([slot, v](gpu::Batch& batch) { batch._glUniform3f(slot, v.x, v.y, v.z); }); - break; - } - - default: - case 4: { - glm::vec4 v{ - valueArray[0].toDouble(), - valueArray[1].toDouble(), - valueArray[2].toDouble(), - valueArray[3].toDouble(), - }; - _uniforms.push_back([slot, v](gpu::Batch& batch) { batch._glUniform4f(slot, v.x, v.y, v.z, v.w); }); - break; - } + const QJsonArray valueArray = value.toArray(); + if (valueArray.size() > 0) { + if (valueArray[0].isArray()) { + const size_t valueLength = valueArray[0].toArray().size(); + std::vector vs; + vs.reserve(valueLength * valueArray.size()); + size_t count = 0; + for (const QJsonValue& value : valueArray) { + if (value.isArray()) { + const QJsonArray innerValueArray = value.toArray(); + if (innerValueArray.size() == valueLength) { + if (valueLength == 3 || valueLength == 4 || valueLength == 9 || valueLength == 16) { + for (size_t i = 0; i < valueLength; i++) { + vs.push_back(innerValueArray[i].toDouble()); + } + count++; + } + } + } + } + if (count > 0) { + switch (valueLength) { + case 3: { + _uniforms.push_back([slot, vs, count](gpu::Batch& batch) { batch._glUniform3fv(slot, count, vs.data()); }); + break; + } + case 4: { + _uniforms.push_back([slot, vs, count](gpu::Batch& batch) { batch._glUniform4fv(slot, count, vs.data()); }); + break; + } + case 9: { + _uniforms.push_back([slot, vs, count](gpu::Batch& batch) { batch._glUniformMatrix3fv(slot, count, false, vs.data()); }); + break; + } + case 16: { + _uniforms.push_back([slot, vs, count](gpu::Batch& batch) { batch._glUniformMatrix4fv(slot, count, false, vs.data()); }); + break; + } + default: + break; + } + } + } else if (valueArray[0].isDouble()) { + switch (valueArray.size()) { + case 1: { + const float v = valueArray[0].toDouble(); + _uniforms.push_back([slot, v](gpu::Batch& batch) { batch._glUniform(slot, v); }); + break; + } + case 2: { + const glm::vec2 v{ valueArray[0].toDouble(), valueArray[1].toDouble() }; + _uniforms.push_back([slot, v](gpu::Batch& batch) { batch._glUniform(slot, v); }); + break; + } + case 3: { + const glm::vec3 v{ + valueArray[0].toDouble(), + valueArray[1].toDouble(), + valueArray[2].toDouble(), + }; + _uniforms.push_back([slot, v](gpu::Batch& batch) { batch._glUniform(slot, v); }); + break; + } + case 4: { + const glm::vec4 v{ + valueArray[0].toDouble(), + valueArray[1].toDouble(), + valueArray[2].toDouble(), + valueArray[3].toDouble(), + }; + _uniforms.push_back([slot, v](gpu::Batch& batch) { batch._glUniform(slot, v); }); + break; + } + case 9: { + const glm::mat3 m{ + valueArray[0].toDouble(), + valueArray[1].toDouble(), + valueArray[2].toDouble(), + valueArray[3].toDouble(), + valueArray[4].toDouble(), + valueArray[5].toDouble(), + valueArray[6].toDouble(), + valueArray[7].toDouble(), + valueArray[8].toDouble(), + }; + _uniforms.push_back([slot, m](gpu::Batch& batch) { batch._glUniform(slot, m); }); + break; + } + case 16: { + const glm::mat4 m{ + valueArray[0].toDouble(), + valueArray[1].toDouble(), + valueArray[2].toDouble(), + valueArray[3].toDouble(), + valueArray[4].toDouble(), + valueArray[5].toDouble(), + valueArray[6].toDouble(), + valueArray[7].toDouble(), + valueArray[8].toDouble(), + valueArray[9].toDouble(), + valueArray[10].toDouble(), + valueArray[11].toDouble(), + valueArray[12].toDouble(), + valueArray[13].toDouble(), + valueArray[14].toDouble(), + valueArray[15].toDouble(), + }; + _uniforms.push_back([slot, m](gpu::Batch& batch) { batch._glUniform(slot, m); }); + break; + } + default: + break; + } + } } } - slot++; } _uniforms.push_back([this](gpu::Batch& batch) { @@ -578,4 +694,4 @@ void graphics::ProceduralMaterial::initializeProcedural() { _procedural._transparentFragmentSource = gpu::Shader::getFragmentShaderSource(shader::render_utils::fragment::simple_procedural_translucent); _procedural._errorFallbackFragmentPath = ":" + QUrl("qrc:///shaders/errorShader.frag").path(); -} \ No newline at end of file +} diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h index 3ca2f41f0b..c1836095a7 100644 --- a/libraries/procedural/src/procedural/Procedural.h +++ b/libraries/procedural/src/procedural/Procedural.h @@ -190,6 +190,7 @@ protected: NetworkTexturePointer _channels[MAX_PROCEDURAL_TEXTURE_CHANNELS]; std::unordered_map _vertexReplacements; std::unordered_map _fragmentReplacements; + std::unordered_map _slotMap; std::unordered_map _proceduralPipelines; std::unordered_map _errorPipelines; diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index ab1acc3c91..1a76777888 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -4,6 +4,7 @@ // // Created by Niraj Venkat on 7/15/15. // Copyright 2015 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -606,8 +607,8 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte graphics::AmbientOcclusionPointer ambientOcclusion; if (_debug) { ambientOcclusion = _debugAmbientOcclusion; - } else if (ambientOcclusionStage && ambientOcclusionFrame->_ambientOcclusions.size()) { - ambientOcclusion = ambientOcclusionStage->getAmbientOcclusion(ambientOcclusionFrame->_ambientOcclusions.front()); + } else if (ambientOcclusionStage && ambientOcclusionFrame->_elements.size()) { + ambientOcclusion = ambientOcclusionStage->getElement(ambientOcclusionFrame->_elements.front()); } if (!ambientOcclusion || !lightingModel->isAmbientOcclusionEnabled()) { diff --git a/libraries/render-utils/src/AmbientOcclusionStage.cpp b/libraries/render-utils/src/AmbientOcclusionStage.cpp index 6b3763a39c..55fa290ab7 100644 --- a/libraries/render-utils/src/AmbientOcclusionStage.cpp +++ b/libraries/render-utils/src/AmbientOcclusionStage.cpp @@ -7,50 +7,8 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + #include "AmbientOcclusionStage.h" -#include - -std::string AmbientOcclusionStage::_stageName { "AMBIENT_OCCLUSION_STAGE" }; -const AmbientOcclusionStage::Index AmbientOcclusionStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX }; - -AmbientOcclusionStage::Index AmbientOcclusionStage::findAmbientOcclusion(const AmbientOcclusionPointer& ambientOcclusion) const { - auto found = _ambientOcclusionMap.find(ambientOcclusion); - if (found != _ambientOcclusionMap.end()) { - return INVALID_INDEX; - } else { - return (*found).second; - } -} - -AmbientOcclusionStage::Index AmbientOcclusionStage::addAmbientOcclusion(const AmbientOcclusionPointer& ambientOcclusion) { - auto found = _ambientOcclusionMap.find(ambientOcclusion); - if (found == _ambientOcclusionMap.end()) { - auto ambientOcclusionId = _ambientOcclusions.newElement(ambientOcclusion); - // Avoid failing to allocate a ambientOcclusion, just pass - if (ambientOcclusionId != INVALID_INDEX) { - // Insert the ambientOcclusion and its index in the reverse map - _ambientOcclusionMap.insert(AmbientOcclusionMap::value_type(ambientOcclusion, ambientOcclusionId)); - } - return ambientOcclusionId; - } else { - return (*found).second; - } -} - -AmbientOcclusionStage::AmbientOcclusionPointer AmbientOcclusionStage::removeAmbientOcclusion(Index index) { - AmbientOcclusionPointer removed = _ambientOcclusions.freeElement(index); - if (removed) { - _ambientOcclusionMap.erase(removed); - } - return removed; -} - -AmbientOcclusionStageSetup::AmbientOcclusionStageSetup() {} - -void AmbientOcclusionStageSetup::run(const render::RenderContextPointer& renderContext) { - auto stage = renderContext->_scene->getStage(AmbientOcclusionStage::getName()); - if (!stage) { - renderContext->_scene->resetStage(AmbientOcclusionStage::getName(), std::make_shared()); - } -} +template <> +std::string render::PointerStage::_name { "AMBIENT_OCCLUSION_STAGE" }; diff --git a/libraries/render-utils/src/AmbientOcclusionStage.h b/libraries/render-utils/src/AmbientOcclusionStage.h index d5dee344ba..1b54a0828e 100644 --- a/libraries/render-utils/src/AmbientOcclusionStage.h +++ b/libraries/render-utils/src/AmbientOcclusionStage.h @@ -11,74 +11,17 @@ #ifndef hifi_render_utils_AmbientOcclusionStage_h #define hifi_render_utils_AmbientOcclusionStage_h -#include -#include -#include -#include -#include - -#include -#include #include +#include +#include // AmbientOcclusion stage to set up ambientOcclusion-related rendering tasks -class AmbientOcclusionStage : public render::Stage { -public: - static std::string _stageName; - static const std::string& getName() { return _stageName; } - - using Index = render::indexed_container::Index; - static const Index INVALID_INDEX; - static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } - - using AmbientOcclusionPointer = graphics::AmbientOcclusionPointer; - using AmbientOcclusions = render::indexed_container::IndexedPointerVector; - using AmbientOcclusionMap = std::unordered_map; - - using AmbientOcclusionIndices = std::vector; - - Index findAmbientOcclusion(const AmbientOcclusionPointer& ambientOcclusion) const; - Index addAmbientOcclusion(const AmbientOcclusionPointer& ambientOcclusion); - - AmbientOcclusionPointer removeAmbientOcclusion(Index index); - - bool checkAmbientOcclusionId(Index index) const { return _ambientOcclusions.checkIndex(index); } - - Index getNumAmbientOcclusions() const { return _ambientOcclusions.getNumElements(); } - Index getNumFreeAmbientOcclusions() const { return _ambientOcclusions.getNumFreeIndices(); } - Index getNumAllocatedAmbientOcclusions() const { return _ambientOcclusions.getNumAllocatedIndices(); } - - AmbientOcclusionPointer getAmbientOcclusion(Index ambientOcclusionId) const { - return _ambientOcclusions.get(ambientOcclusionId); - } - - AmbientOcclusions _ambientOcclusions; - AmbientOcclusionMap _ambientOcclusionMap; - - class Frame { - public: - Frame() {} - - void clear() { _ambientOcclusions.clear(); } - - void pushAmbientOcclusion(AmbientOcclusionStage::Index index) { _ambientOcclusions.emplace_back(index); } - - AmbientOcclusionStage::AmbientOcclusionIndices _ambientOcclusions; - }; - using FramePointer = std::shared_ptr; - - Frame _currentFrame; -}; +class AmbientOcclusionStage : public render::PointerStage {}; using AmbientOcclusionStagePointer = std::shared_ptr; -class AmbientOcclusionStageSetup { +class AmbientOcclusionStageSetup : public render::StageSetup { public: using JobModel = render::Job::Model; - - AmbientOcclusionStageSetup(); - void run(const render::RenderContextPointer& renderContext); - -protected: }; #endif diff --git a/libraries/render-utils/src/AssembleLightingStageTask.cpp b/libraries/render-utils/src/AssembleLightingStageTask.cpp index bc040582bd..0646f77d51 100644 --- a/libraries/render-utils/src/AssembleLightingStageTask.cpp +++ b/libraries/render-utils/src/AssembleLightingStageTask.cpp @@ -1,6 +1,7 @@ // // Created by Samuel Gateau on 2018/12/06 // Copyright 2013-2018 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html diff --git a/libraries/render-utils/src/BackgroundStage.cpp b/libraries/render-utils/src/BackgroundStage.cpp index 455f356a45..f3f287bdac 100644 --- a/libraries/render-utils/src/BackgroundStage.cpp +++ b/libraries/render-utils/src/BackgroundStage.cpp @@ -3,58 +3,20 @@ // // Created by Sam Gateau on 5/9/2017. // Copyright 2015 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + #include "BackgroundStage.h" #include "DeferredLightingEffect.h" -#include - #include -std::string BackgroundStage::_stageName { "BACKGROUND_STAGE" }; -const BackgroundStage::Index BackgroundStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX }; - -BackgroundStage::Index BackgroundStage::findBackground(const BackgroundPointer& background) const { - auto found = _backgroundMap.find(background); - if (found != _backgroundMap.end()) { - return INVALID_INDEX; - } else { - return (*found).second; - } - -} - -BackgroundStage::Index BackgroundStage::addBackground(const BackgroundPointer& background) { - - auto found = _backgroundMap.find(background); - if (found == _backgroundMap.end()) { - auto backgroundId = _backgrounds.newElement(background); - // Avoid failing to allocate a background, just pass - if (backgroundId != INVALID_INDEX) { - - // Insert the background and its index in the reverse map - _backgroundMap.insert(BackgroundMap::value_type(background, backgroundId)); - } - return backgroundId; - } else { - return (*found).second; - } -} - - -BackgroundStage::BackgroundPointer BackgroundStage::removeBackground(Index index) { - BackgroundPointer removed = _backgrounds.freeElement(index); - - if (removed) { - _backgroundMap.erase(removed); - } - return removed; -} - +template <> +std::string render::PointerStage::_name { "BACKGROUND_STAGE" }; void DrawBackgroundStage::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { const auto& lightingModel = inputs.get0(); @@ -66,8 +28,8 @@ void DrawBackgroundStage::run(const render::RenderContextPointer& renderContext, const auto& backgroundStage = renderContext->_scene->getStage(); const auto& backgroundFrame = inputs.get1(); graphics::SkyboxPointer skybox; - if (backgroundStage && backgroundFrame->_backgrounds.size()) { - const auto& background = backgroundStage->getBackground(backgroundFrame->_backgrounds.front()); + if (backgroundStage && backgroundFrame->_elements.size()) { + const auto& background = backgroundStage->getElement(backgroundFrame->_elements.front()); if (background) { skybox = background->getSkybox(); } @@ -98,8 +60,8 @@ void DrawBackgroundStage::run(const render::RenderContextPointer& renderContext, // If we're using forward rendering, we need to calculate haze if (args->_renderMethod == render::Args::RenderMethod::FORWARD) { const auto& hazeStage = args->_scene->getStage(); - if (hazeStage && hazeFrame->_hazes.size() > 0) { - const auto& hazePointer = hazeStage->getHaze(hazeFrame->_hazes.front()); + if (hazeStage && hazeFrame->_elements.size() > 0) { + const auto& hazePointer = hazeStage->getElement(hazeFrame->_elements.front()); if (hazePointer) { batch.setUniformBuffer(graphics::slot::buffer::Buffer::HazeParams, hazePointer->getHazeParametersBuffer()); } @@ -111,14 +73,3 @@ void DrawBackgroundStage::run(const render::RenderContextPointer& renderContext, args->_batch = nullptr; } } - -BackgroundStageSetup::BackgroundStageSetup() { -} - -void BackgroundStageSetup::run(const render::RenderContextPointer& renderContext) { - auto stage = renderContext->_scene->getStage(BackgroundStage::getName()); - if (!stage) { - renderContext->_scene->resetStage(BackgroundStage::getName(), std::make_shared()); - } -} - diff --git a/libraries/render-utils/src/BackgroundStage.h b/libraries/render-utils/src/BackgroundStage.h index 3015b721b1..4da8fbf9fb 100644 --- a/libraries/render-utils/src/BackgroundStage.h +++ b/libraries/render-utils/src/BackgroundStage.h @@ -1,8 +1,9 @@ // // BackgroundStage.h - +// // Created by Sam Gateau on 5/9/2017. // Copyright 2015 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -12,72 +13,19 @@ #define hifi_render_utils_BackgroundStage_h #include -#include -#include -#include #include -#include "HazeStage.h" +#include +#include "HazeStage.h" #include "LightingModel.h" - // Background stage to set up background-related rendering tasks -class BackgroundStage : public render::Stage { -public: - static std::string _stageName; - static const std::string& getName() { return _stageName; } - - using Index = render::indexed_container::Index; - static const Index INVALID_INDEX; - static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } - - using BackgroundPointer = graphics::SunSkyStagePointer; - using Backgrounds = render::indexed_container::IndexedPointerVector; - using BackgroundMap = std::unordered_map; - - using BackgroundIndices = std::vector; - - - Index findBackground(const BackgroundPointer& background) const; - Index addBackground(const BackgroundPointer& background); - - BackgroundPointer removeBackground(Index index); - - bool checkBackgroundId(Index index) const { return _backgrounds.checkIndex(index); } - - Index getNumBackgrounds() const { return _backgrounds.getNumElements(); } - Index getNumFreeBackgrounds() const { return _backgrounds.getNumFreeIndices(); } - Index getNumAllocatedBackgrounds() const { return _backgrounds.getNumAllocatedIndices(); } - - BackgroundPointer getBackground(Index backgroundId) const { - return _backgrounds.get(backgroundId); - } - - Backgrounds _backgrounds; - BackgroundMap _backgroundMap; - - class Frame { - public: - Frame() {} - - void clear() { _backgrounds.clear(); } - - void pushBackground(BackgroundStage::Index index) { _backgrounds.emplace_back(index); } - - BackgroundStage::BackgroundIndices _backgrounds; - }; - using FramePointer = std::shared_ptr; - - Frame _currentFrame; -}; +class BackgroundStage : public render::PointerStage {}; using BackgroundStagePointer = std::shared_ptr; -class BackgroundStageSetup { +class BackgroundStageSetup : public render::StageSetup { public: using JobModel = render::Job::Model; - - BackgroundStageSetup(); - void run(const render::RenderContextPointer& renderContext); }; class DrawBackgroundStage { diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp index d27403440c..763f12cf0f 100644 --- a/libraries/render-utils/src/BloomEffect.cpp +++ b/libraries/render-utils/src/BloomEffect.cpp @@ -4,6 +4,7 @@ // // Created by Olivier Prat on 09/25/17. // Copyright 2017 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -43,8 +44,8 @@ void BloomThreshold::run(const render::RenderContextPointer& renderContext, cons const auto lightingModel = inputs.get3(); const auto& bloomStage = renderContext->_scene->getStage(); graphics::BloomPointer bloom; - if (bloomStage && bloomFrame->_blooms.size()) { - bloom = bloomStage->getBloom(bloomFrame->_blooms.front()); + if (bloomStage && bloomFrame->_elements.size()) { + bloom = bloomStage->getElement(bloomFrame->_elements.front()); } if (!bloom || (lightingModel && !lightingModel->isBloomEnabled())) { renderContext->taskFlow.abortTask(); diff --git a/libraries/render-utils/src/BloomStage.cpp b/libraries/render-utils/src/BloomStage.cpp index 2bedfeea96..23ec4596bd 100644 --- a/libraries/render-utils/src/BloomStage.cpp +++ b/libraries/render-utils/src/BloomStage.cpp @@ -3,56 +3,13 @@ // // Created by Sam Gondelman on 8/7/2018 // Copyright 2018 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + #include "BloomStage.h" -#include "DeferredLightingEffect.h" - -#include - -std::string BloomStage::_stageName { "BLOOM_STAGE" }; -const BloomStage::Index BloomStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX }; - -BloomStage::Index BloomStage::findBloom(const BloomPointer& bloom) const { - auto found = _bloomMap.find(bloom); - if (found != _bloomMap.end()) { - return INVALID_INDEX; - } else { - return (*found).second; - } -} - -BloomStage::Index BloomStage::addBloom(const BloomPointer& bloom) { - auto found = _bloomMap.find(bloom); - if (found == _bloomMap.end()) { - auto bloomId = _blooms.newElement(bloom); - // Avoid failing to allocate a bloom, just pass - if (bloomId != INVALID_INDEX) { - // Insert the bloom and its index in the reverse map - _bloomMap.insert(BloomMap::value_type(bloom, bloomId)); - } - return bloomId; - } else { - return (*found).second; - } -} - -BloomStage::BloomPointer BloomStage::removeBloom(Index index) { - BloomPointer removed = _blooms.freeElement(index); - if (removed) { - _bloomMap.erase(removed); - } - return removed; -} - -BloomStageSetup::BloomStageSetup() {} - -void BloomStageSetup::run(const render::RenderContextPointer& renderContext) { - auto stage = renderContext->_scene->getStage(BloomStage::getName()); - if (!stage) { - renderContext->_scene->resetStage(BloomStage::getName(), std::make_shared()); - } -} +template <> +std::string render::PointerStage::_name { "BLOOM_STAGE" }; diff --git a/libraries/render-utils/src/BloomStage.h b/libraries/render-utils/src/BloomStage.h index bb03e181af..37e72bacea 100644 --- a/libraries/render-utils/src/BloomStage.h +++ b/libraries/render-utils/src/BloomStage.h @@ -3,6 +3,7 @@ // Created by Sam Gondelman on 8/7/2018 // Copyright 2018 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -11,74 +12,17 @@ #ifndef hifi_render_utils_BloomStage_h #define hifi_render_utils_BloomStage_h -#include -#include -#include -#include -#include - -#include -#include #include +#include +#include // Bloom stage to set up bloom-related rendering tasks -class BloomStage : public render::Stage { -public: - static std::string _stageName; - static const std::string& getName() { return _stageName; } - - using Index = render::indexed_container::Index; - static const Index INVALID_INDEX; - static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } - - using BloomPointer = graphics::BloomPointer; - using Blooms = render::indexed_container::IndexedPointerVector; - using BloomMap = std::unordered_map; - - using BloomIndices = std::vector; - - Index findBloom(const BloomPointer& bloom) const; - Index addBloom(const BloomPointer& bloom); - - BloomPointer removeBloom(Index index); - - bool checkBloomId(Index index) const { return _blooms.checkIndex(index); } - - Index getNumBlooms() const { return _blooms.getNumElements(); } - Index getNumFreeBlooms() const { return _blooms.getNumFreeIndices(); } - Index getNumAllocatedBlooms() const { return _blooms.getNumAllocatedIndices(); } - - BloomPointer getBloom(Index bloomId) const { - return _blooms.get(bloomId); - } - - Blooms _blooms; - BloomMap _bloomMap; - - class Frame { - public: - Frame() {} - - void clear() { _blooms.clear(); } - - void pushBloom(BloomStage::Index index) { _blooms.emplace_back(index); } - - BloomStage::BloomIndices _blooms; - }; - using FramePointer = std::shared_ptr; - - Frame _currentFrame; -}; +class BloomStage : public render::PointerStage {}; using BloomStagePointer = std::shared_ptr; -class BloomStageSetup { +class BloomStageSetup : public render::StageSetup { public: using JobModel = render::Job::Model; - - BloomStageSetup(); - void run(const render::RenderContextPointer& renderContext); - -protected: }; #endif diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 0ff1c435e1..f2f6639f88 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -4,6 +4,7 @@ // // Created by Andrzej Kapolka on 9/11/14. // Copyright 2014 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -375,7 +376,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext, // Global directional light, maybe shadow and ambient pass auto lightStage = renderContext->_scene->getStage(); assert(lightStage); - assert(lightStage->getNumLights() > 0); + assert(lightStage->getNumElements() > 0); auto keyLight = lightStage->getCurrentKeyLight(*lightFrame); // Check if keylight casts shadows @@ -391,7 +392,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext, // Global Ambient light graphics::LightPointer ambientLight; if (lightStage && lightFrame->_ambientLights.size()) { - ambientLight = lightStage->getLight(lightFrame->_ambientLights.front()); + ambientLight = lightStage->getElement(lightFrame->_ambientLights.front()); } bool hasAmbientMap = (ambientLight != nullptr); @@ -430,8 +431,8 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext, // Haze const auto& hazeStage = args->_scene->getStage(); - if (hazeStage && hazeFrame->_hazes.size() > 0) { - const auto& hazePointer = hazeStage->getHaze(hazeFrame->_hazes.front()); + if (hazeStage && hazeFrame->_elements.size() > 0) { + const auto& hazePointer = hazeStage->getElement(hazeFrame->_elements.front()); if (hazePointer) { batch.setUniformBuffer(graphics::slot::buffer::Buffer::HazeParams, hazePointer->getHazeParametersBuffer()); } @@ -636,7 +637,7 @@ void DefaultLightingSetup::run(const RenderContextPointer& renderContext) { // Add the global light to the light stage (for later shadow rendering) // Set this light to be the default - _defaultLightID = lightStage->addLight(lp, true); + _defaultLightID = lightStage->addElement(lp, true); } auto backgroundStage = renderContext->_scene->getStage(); @@ -649,7 +650,7 @@ void DefaultLightingSetup::run(const RenderContextPointer& renderContext) { _defaultBackground = background; // Add the global light to the light stage (for later shadow rendering) - _defaultBackgroundID = backgroundStage->addBackground(_defaultBackground); + _defaultBackgroundID = backgroundStage->addElement(_defaultBackground); } } @@ -659,7 +660,7 @@ void DefaultLightingSetup::run(const RenderContextPointer& renderContext) { auto haze = std::make_shared(); _defaultHaze = haze; - _defaultHazeID = hazeStage->addHaze(_defaultHaze); + _defaultHazeID = hazeStage->addElement(_defaultHaze); } } @@ -669,7 +670,7 @@ void DefaultLightingSetup::run(const RenderContextPointer& renderContext) { auto tonemapping = std::make_shared(); _defaultTonemapping = tonemapping; - _defaultTonemappingID = tonemappingStage->addTonemapping(_defaultTonemapping); + _defaultTonemappingID = tonemappingStage->addElement(_defaultTonemapping); } } } diff --git a/libraries/render-utils/src/DrawHaze.cpp b/libraries/render-utils/src/DrawHaze.cpp index 71845be731..f7e62d75f4 100644 --- a/libraries/render-utils/src/DrawHaze.cpp +++ b/libraries/render-utils/src/DrawHaze.cpp @@ -4,6 +4,7 @@ // // Created by Nissim Hadar on 9/1/2017. // Copyright 2015 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -39,8 +40,8 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu const auto hazeFrame = inputs.get0(); const auto& hazeStage = renderContext->args->_scene->getStage(); graphics::HazePointer haze; - if (hazeStage && hazeFrame->_hazes.size() > 0) { - haze = hazeStage->getHaze(hazeFrame->_hazes.front()); + if (hazeStage && hazeFrame->_elements.size() > 0) { + haze = hazeStage->getElement(hazeFrame->_elements.front()); } if (!haze) { @@ -55,6 +56,10 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu auto depthBuffer = framebuffer->getLinearDepthTexture(); + if (!lightingModel->isHazeEnabled() || !haze->isActive()) { + return; + } + RenderArgs* args = renderContext->args; if (!_hazePipeline) { diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index 902b8fbab1..1d25c0a372 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -3,6 +3,7 @@ // Created by Olivier Prat on 17/07/2017. // Copyright 2017 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -28,10 +29,8 @@ FadeEffect::FadeEffect() { } void FadeEffect::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { - auto editedFadeCategory = task.addJob("Fade"); - - const auto fadeEditInput = FadeEditJob::Input(inputs, editedFadeCategory).asVarying(); - task.addJob("FadeEdit", fadeEditInput); + const auto editedFadeCategory = task.addJob("Fade"); + task.addJob("FadeEdit", editedFadeCategory); } render::ShapePipeline::BatchSetter FadeEffect::getBatchSetter() { @@ -47,7 +46,7 @@ render::ShapePipeline::ItemSetter FadeEffect::getItemUniformSetter() { const auto& scene = args->_scene; const auto& batch = args->_batch; auto transitionStage = scene->getStage(); - auto& transitionState = transitionStage->getTransition(item.getTransitionId()); + auto& transitionState = transitionStage->getElement(item.getTransitionId()); if (transitionState.paramsBuffer._size != sizeof(gpu::StructBuffer)) { static_assert(sizeof(transitionState.paramsBuffer) == sizeof(gpu::StructBuffer), "Assuming gpu::StructBuffer is a helper class for gpu::BufferView"); diff --git a/libraries/render-utils/src/FadeEffect.h b/libraries/render-utils/src/FadeEffect.h index d5aab4e1f5..17b5efd28f 100644 --- a/libraries/render-utils/src/FadeEffect.h +++ b/libraries/render-utils/src/FadeEffect.h @@ -15,8 +15,7 @@ class FadeEffect { public: - using Input = render::ItemBounds; - using JobModel = render::Task::ModelI; + using JobModel = render::Task::Model; FadeEffect(); diff --git a/libraries/render-utils/src/FadeEffectJobs.cpp b/libraries/render-utils/src/FadeEffectJobs.cpp index 23abc18683..72edbacbf0 100644 --- a/libraries/render-utils/src/FadeEffectJobs.cpp +++ b/libraries/render-utils/src/FadeEffectJobs.cpp @@ -3,6 +3,7 @@ // Created by Olivier Prat on 07/07/2017. // Copyright 2017 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -35,7 +36,7 @@ void FadeEditJob::configure(const Config& config) { _isEditEnabled = config.editFade; } -void FadeEditJob::run(const render::RenderContextPointer& renderContext, const FadeEditJob::Input& inputs) { +void FadeEditJob::run(const render::RenderContextPointer& renderContext, const FadeEditJob::Input& input) { auto scene = renderContext->_scene; if (_isEditEnabled) { @@ -63,7 +64,7 @@ void FadeEditJob::run(const render::RenderContextPointer& renderContext, const F render::Transition::AVATAR_CHANGE }; - auto transitionType = categoryToTransition[inputs.get1()]; + auto transitionType = categoryToTransition[input]; transaction.queryTransitionOnItem(_editedItem, [transitionType, scene](render::ItemID id, const render::Transition* transition) { if (transition == nullptr || transition->isFinished || transition->eventType != transitionType) { @@ -572,7 +573,7 @@ void FadeJob::run(const render::RenderContextPointer& renderContext, FadeJob::Ou // And now update fade effect for (auto transitionId : *transitionStage) { - auto& state = transitionStage->editTransition(transitionId); + auto& state = transitionStage->editElement(transitionId); #ifdef DEBUG auto& item = scene->getItem(state.itemId); assert(item.getTransitionId() == transitionId); diff --git a/libraries/render-utils/src/FadeEffectJobs.h b/libraries/render-utils/src/FadeEffectJobs.h index fcd55b76ac..4a567d84a5 100644 --- a/libraries/render-utils/src/FadeEffectJobs.h +++ b/libraries/render-utils/src/FadeEffectJobs.h @@ -177,13 +177,13 @@ class FadeEditJob { public: using Config = FadeEditConfig; - using Input = render::VaryingSet2; + using Input = FadeCategory; using JobModel = render::Job::ModelI; FadeEditJob() {} void configure(const Config& config); - void run(const render::RenderContextPointer& renderContext, const FadeEditJob::Input& inputs); + void run(const render::RenderContextPointer& renderContext, const FadeEditJob::Input& input); private: diff --git a/libraries/render-utils/src/Haze.slf b/libraries/render-utils/src/Haze.slf index 9be64e7695..e7c3459f4a 100644 --- a/libraries/render-utils/src/Haze.slf +++ b/libraries/render-utils/src/Haze.slf @@ -6,6 +6,7 @@ // // Created by Nissim Hadar on 9/5/2107. // Copyright 2016 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -45,10 +46,6 @@ layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; void main(void) { - if ((isHazeEnabled() == 0.0) || (hazeParams.hazeMode & HAZE_MODE_IS_ACTIVE) != HAZE_MODE_IS_ACTIVE) { - discard; - } - vec4 fragPositionES = unpackPositionFromZeye(varTexCoord0); mat4 viewInverse = getViewInverse(); diff --git a/libraries/render-utils/src/HazeStage.cpp b/libraries/render-utils/src/HazeStage.cpp index 9251e1e2f9..49ed7a1ea4 100644 --- a/libraries/render-utils/src/HazeStage.cpp +++ b/libraries/render-utils/src/HazeStage.cpp @@ -3,59 +3,13 @@ // // Created by Nissim Hadar on 9/26/2017. // Copyright 2015 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + #include "HazeStage.h" -#include "DeferredLightingEffect.h" - -#include - -std::string HazeStage::_stageName { "HAZE_STAGE" }; -const HazeStage::Index HazeStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX }; - -HazeStage::Index HazeStage::findHaze(const HazePointer& haze) const { - auto found = _hazeMap.find(haze); - if (found != _hazeMap.end()) { - return INVALID_INDEX; - } else { - return (*found).second; - } -} - -HazeStage::Index HazeStage::addHaze(const HazePointer& haze) { - auto found = _hazeMap.find(haze); - if (found == _hazeMap.end()) { - auto hazeId = _hazes.newElement(haze); - // Avoid failing to allocate a haze, just pass - if (hazeId != INVALID_INDEX) { - - // Insert the haze and its index in the reverse map - _hazeMap.insert(HazeMap::value_type(haze, hazeId)); - } - return hazeId; - } else { - return (*found).second; - } -} - -HazeStage::HazePointer HazeStage::removeHaze(Index index) { - HazePointer removed = _hazes.freeElement(index); - - if (removed) { - _hazeMap.erase(removed); - } - return removed; -} - -HazeStageSetup::HazeStageSetup() { -} - -void HazeStageSetup::run(const render::RenderContextPointer& renderContext) { - auto stage = renderContext->_scene->getStage(HazeStage::getName()); - if (!stage) { - renderContext->_scene->resetStage(HazeStage::getName(), std::make_shared()); - } -} \ No newline at end of file +template <> +std::string render::PointerStage::_name { "HAZE_STAGE" }; diff --git a/libraries/render-utils/src/HazeStage.h b/libraries/render-utils/src/HazeStage.h index b1c7d0384c..70a33b27eb 100644 --- a/libraries/render-utils/src/HazeStage.h +++ b/libraries/render-utils/src/HazeStage.h @@ -3,6 +3,7 @@ // Created by Nissim Hadar on 9/26/2017. // Copyright 2015 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -11,74 +12,17 @@ #ifndef hifi_render_utils_HazeStage_h #define hifi_render_utils_HazeStage_h -#include -#include -#include -#include -#include - -#include -#include #include +#include +#include // Haze stage to set up haze-related rendering tasks -class HazeStage : public render::Stage { -public: - static std::string _stageName; - static const std::string& getName() { return _stageName; } - - using Index = render::indexed_container::Index; - static const Index INVALID_INDEX; - static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } - - using HazePointer = graphics::HazePointer; - using Hazes = render::indexed_container::IndexedPointerVector; - using HazeMap = std::unordered_map; - - using HazeIndices = std::vector; - - Index findHaze(const HazePointer& haze) const; - Index addHaze(const HazePointer& haze); - - HazePointer removeHaze(Index index); - - bool checkHazeId(Index index) const { return _hazes.checkIndex(index); } - - Index getNumHazes() const { return _hazes.getNumElements(); } - Index getNumFreeHazes() const { return _hazes.getNumFreeIndices(); } - Index getNumAllocatedHazes() const { return _hazes.getNumAllocatedIndices(); } - - HazePointer getHaze(Index hazeId) const { - return _hazes.get(hazeId); - } - - Hazes _hazes; - HazeMap _hazeMap; - - class Frame { - public: - Frame() {} - - void clear() { _hazes.clear(); } - - void pushHaze(HazeStage::Index index) { _hazes.emplace_back(index); } - - HazeStage::HazeIndices _hazes; - }; - using FramePointer = std::shared_ptr; - - Frame _currentFrame; -}; +class HazeStage : public render::PointerStage {}; using HazeStagePointer = std::shared_ptr; -class HazeStageSetup { +class HazeStageSetup : public render::StageSetup { public: using JobModel = render::Job::Model; - - HazeStageSetup(); - void run(const render::RenderContextPointer& renderContext); - -protected: }; class FetchHazeConfig : public render::Job::Config { diff --git a/libraries/render-utils/src/HighlightEffect.cpp b/libraries/render-utils/src/HighlightEffect.cpp index 2525427b61..755d0a60be 100644 --- a/libraries/render-utils/src/HighlightEffect.cpp +++ b/libraries/render-utils/src/HighlightEffect.cpp @@ -161,7 +161,7 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c if (!inShapes.empty() && !render::HighlightStage::isIndexInvalid(highlightId)) { auto resources = inputs.get1(); - auto& highlight = highlightStage->getHighlight(highlightId); + auto& highlight = highlightStage->getElement(highlightId); RenderArgs* args = renderContext->args; @@ -247,7 +247,7 @@ void DrawHighlight::run(const render::RenderContextPointer& renderContext, const auto highlightStage = renderContext->_scene->getStage(); auto highlightId = _sharedParameters->_highlightIds[_highlightPassIndex]; if (!render::HighlightStage::isIndexInvalid(highlightId)) { - auto& highlight = highlightStage->getHighlight(highlightId); + auto& highlight = highlightStage->getElement(highlightId); auto pipeline = getPipeline(highlight._style); { auto& shaderParameters = _configuration.edit(); @@ -432,7 +432,7 @@ void SelectionToHighlight::run(const render::RenderContextPointer& renderContext auto highlightList = highlightStage->getActiveHighlightIds(); for (auto styleId : highlightList) { - auto highlight = highlightStage->getHighlight(styleId); + auto highlight = highlightStage->getElement(styleId); if (!scene->isSelectionEmpty(highlight._selectionName)) { auto highlightId = highlightStage->getHighlightIdBySelection(highlight._selectionName); @@ -572,8 +572,8 @@ void HighlightCleanup::run(const render::RenderContextPointer& renderContext, co auto highlightStage = scene->getStage(); for (auto index : inputs.get0()) { - std::string selectionName = highlightStage->getHighlight(index)._selectionName; - highlightStage->removeHighlight(index); + std::string selectionName = highlightStage->getElement(index)._selectionName; + highlightStage->removeElement(index); scene->removeSelection(selectionName); } diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index 3425e08783..f0ec35238f 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -348,7 +348,7 @@ glm::ivec3 LightClusters::updateClusters() { uint32_t numClusteredLights = 0; for (size_t lightNum = 1; lightNum < _visibleLightIndices.size(); ++lightNum) { auto lightId = _visibleLightIndices[lightNum]; - auto light = _lightStage->getLight(lightId); + auto light = _lightStage->getElement(lightId); if (!light) { continue; } @@ -567,9 +567,9 @@ void LightClusteringPass::run(const render::RenderContextPointer& renderContext, output = _lightClusters; auto config = std::static_pointer_cast(renderContext->jobConfig); - config->numSceneLights = lightStage->getNumLights(); - config->numFreeSceneLights = lightStage->getNumFreeLights(); - config->numAllocatedSceneLights = lightStage->getNumAllocatedLights(); + config->numSceneLights = lightStage->getNumElements(); + config->numFreeSceneLights = lightStage->getNumFreeElements(); + config->numAllocatedSceneLights = lightStage->getNumAllocatedElements(); config->setNumInputLights(clusteringStats.x); config->setNumClusteredLights(clusteringStats.y); config->setNumClusteredLightReferences(clusteringStats.z); diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index 6192105914..94e1e37ae3 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -95,7 +95,7 @@ public: FrustumGrid::Planes _gridPlanes[3]; - LightStage::LightIndices _visibleLightIndices; + render::ElementIndices _visibleLightIndices; gpu::BufferView _lightIndicesBuffer; const uint32_t EMPTY_CLUSTER { 0x0000FFFF }; diff --git a/libraries/render-utils/src/LightPayload.cpp b/libraries/render-utils/src/LightPayload.cpp index d1018982d0..43280c9a2a 100644 --- a/libraries/render-utils/src/LightPayload.cpp +++ b/libraries/render-utils/src/LightPayload.cpp @@ -52,7 +52,7 @@ LightPayload::LightPayload() : LightPayload::~LightPayload() { if (!LightStage::isIndexInvalid(_index)) { if (_stage) { - _stage->removeLight(_index); + _stage->removeElement(_index); } } } @@ -64,7 +64,7 @@ void LightPayload::render(RenderArgs* args) { } // Do we need to allocate the light in the stage ? if (LightStage::isIndexInvalid(_index)) { - _index = _stage->addLight(_light); + _index = _stage->addElement(_light); _needUpdate = false; } // Need an update ? @@ -122,7 +122,7 @@ _light(std::make_shared()) KeyLightPayload::~KeyLightPayload() { if (!LightStage::isIndexInvalid(_index)) { if (_stage) { - _stage->removeLight(_index); + _stage->removeElement(_index); } } } @@ -134,7 +134,7 @@ void KeyLightPayload::render(RenderArgs* args) { } // Do we need to allocate the light in the stage ? if (LightStage::isIndexInvalid(_index)) { - _index = _stage->addLight(_light); + _index = _stage->addElement(_light); _needUpdate = false; } // Need an update ? diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 58f32cdc4e..08e5e51459 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -4,6 +4,7 @@ // // Created by Zach Pomerantz on 1/14/2015. // Copyright 2015 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -15,7 +16,9 @@ #include "ViewFrustum.h" -std::string LightStage::_stageName { "LIGHT_STAGE" }; +template <> +std::string render::PointerStage::_name { "LIGHT_STAGE" }; + // The bias matrix goes from homogeneous coordinates to UV coords (see http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-16-shadow-mapping/#basic-shader) const glm::mat4 LightStage::Shadow::_biasMatrix { 0.5, 0.0, 0.0, 0.0, @@ -24,8 +27,6 @@ const glm::mat4 LightStage::Shadow::_biasMatrix { 0.5, 0.5, 0.5, 1.0 }; const int LightStage::Shadow::MAP_SIZE = 1024; -const LightStage::Index LightStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX }; - LightStage::LightStage() { // Add off lights const LightPointer ambientOffLight { std::make_shared() }; @@ -33,28 +34,28 @@ LightStage::LightStage() { ambientOffLight->setColor(graphics::Vec3(0.0)); ambientOffLight->setIntensity(0.0f); ambientOffLight->setType(graphics::Light::Type::AMBIENT); - _ambientOffLightId = addLight(ambientOffLight); + _ambientOffLightId = addElement(ambientOffLight); const LightPointer pointOffLight { std::make_shared() }; pointOffLight->setAmbientIntensity(0.0f); pointOffLight->setColor(graphics::Vec3(0.0)); pointOffLight->setIntensity(0.0f); pointOffLight->setType(graphics::Light::Type::POINT); - _pointOffLightId = addLight(pointOffLight); + _pointOffLightId = addElement(pointOffLight); const LightPointer spotOffLight { std::make_shared() }; spotOffLight->setAmbientIntensity(0.0f); spotOffLight->setColor(graphics::Vec3(0.0)); spotOffLight->setIntensity(0.0f); spotOffLight->setType(graphics::Light::Type::SPOT); - _spotOffLightId = addLight(spotOffLight); + _spotOffLightId = addElement(spotOffLight); const LightPointer sunOffLight { std::make_shared() }; sunOffLight->setAmbientIntensity(0.0f); sunOffLight->setColor(graphics::Vec3(0.0)); sunOffLight->setIntensity(0.0f); sunOffLight->setType(graphics::Light::Type::SUN); - _sunOffLightId = addLight(sunOffLight); + _sunOffLightId = addElement(sunOffLight); // Set default light to the off ambient light (until changed) _defaultLightId = _ambientOffLightId; @@ -72,7 +73,7 @@ LightStage::Shadow::Schema::Schema() { maxDistance = 20.0f; } -LightStage::Shadow::Cascade::Cascade() : +LightStage::Shadow::Cascade::Cascade() : _frustum{ std::make_shared() }, _minDistance{ 0.0f }, _maxDistance{ 20.0f } { @@ -88,7 +89,7 @@ const glm::mat4& LightStage::Shadow::Cascade::getProjection() const { float LightStage::Shadow::Cascade::computeFarDistance(const ViewFrustum& viewFrustum, const Transform& shadowViewInverse, float left, float right, float bottom, float top, float viewMaxShadowDistance) const { - // Far distance should be extended to the intersection of the infinitely extruded shadow frustum + // Far distance should be extended to the intersection of the infinitely extruded shadow frustum // with the view frustum side planes. To do so, we generate 10 triangles in shadow space which are the result of // tesselating the side and far faces of the view frustum and clip them with the 4 side planes of the // shadow frustum. The resulting clipped triangle vertices with the farthest Z gives the desired @@ -121,7 +122,7 @@ float LightStage::Shadow::Cascade::computeFarDistance(const ViewFrustum& viewFru return far; } -LightStage::Shadow::Shadow(graphics::LightPointer light, unsigned int cascadeCount) : +LightStage::Shadow::Shadow(graphics::LightPointer light, unsigned int cascadeCount) : _light{ light } { cascadeCount = std::min(cascadeCount, (unsigned int)SHADOW_CASCADE_MAX_COUNT); Schema schema; @@ -323,21 +324,12 @@ void LightStage::Shadow::setCascadeFrustum(unsigned int cascadeIndex, const View schemaCascade.reprojection = _biasMatrix * shadowFrustum.getProjection() * viewInverse.getMatrix(); } -LightStage::Index LightStage::findLight(const LightPointer& light) const { - auto found = _lightMap.find(light); - if (found != _lightMap.end()) { - return INVALID_INDEX; - } else { - return (*found).second; - } -} - -LightStage::Index LightStage::addLight(const LightPointer& light, const bool shouldSetAsDefault) { +LightStage::Index LightStage::addElement(const LightPointer& light, const bool shouldSetAsDefault) { Index lightId; - auto found = _lightMap.find(light); - if (found == _lightMap.end()) { - lightId = _lights.newElement(light); + auto found = _elementMap.find(light); + if (found == _elementMap.end()) { + lightId = _elements.newElement(light); // Avoid failing to allocate a light, just pass if (lightId != INVALID_INDEX) { @@ -349,8 +341,8 @@ LightStage::Index LightStage::addLight(const LightPointer& light, const bool sho _descs[lightId] = Desc(); } - // INsert the light and its index in the reverese map - _lightMap.insert(LightMap::value_type(light, lightId)); + // Insert the light and its index in the reverese map + _elementMap[light] = lightId; updateLightArrayBuffer(lightId); } @@ -365,30 +357,30 @@ LightStage::Index LightStage::addLight(const LightPointer& light, const bool sho return lightId; } -LightStage::LightPointer LightStage::removeLight(Index index) { - LightPointer removedLight = _lights.freeElement(index); +LightStage::LightPointer LightStage::removeElement(Index index) { + LightPointer removedLight = _elements.freeElement(index); if (removedLight) { - _lightMap.erase(removedLight); + _elementMap.erase(removedLight); _descs[index] = Desc(); } assert(_descs.size() <= (size_t)index || _descs[index].shadowId == INVALID_INDEX); return removedLight; } -LightStage::LightPointer LightStage::getCurrentKeyLight(const LightStage::Frame& frame) const { +LightStage::LightPointer LightStage::getCurrentKeyLight(const LightFrame& frame) const { Index keyLightId { _defaultLightId }; if (!frame._sunLights.empty()) { keyLightId = frame._sunLights.front(); } - return _lights.get(keyLightId); + return _elements.get(keyLightId); } -LightStage::LightPointer LightStage::getCurrentAmbientLight(const LightStage::Frame& frame) const { +LightStage::LightPointer LightStage::getCurrentAmbientLight(const LightFrame& frame) const { Index keyLightId { _defaultLightId }; if (!frame._ambientLights.empty()) { keyLightId = frame._ambientLights.front(); } - return _lights.get(keyLightId); + return _elements.get(keyLightId); } void LightStage::updateLightArrayBuffer(Index lightId) { @@ -397,14 +389,12 @@ void LightStage::updateLightArrayBuffer(Index lightId) { _lightArrayBuffer = std::make_shared(lightSize); } - assert(checkLightId(lightId)); - if (lightId > (Index)_lightArrayBuffer->getNumTypedElements()) { _lightArrayBuffer->resize(lightSize * (lightId + 10)); } // lightArray is big enough so we can remap - auto light = _lights._elements[lightId]; + auto light = _elements._elements[lightId]; if (light) { const auto& lightSchema = light->getLightSchemaBuffer().get(); _lightArrayBuffer->setSubData(lightId, lightSchema); @@ -412,17 +402,3 @@ void LightStage::updateLightArrayBuffer(Index lightId) { // this should not happen ? } } - -LightStageSetup::LightStageSetup() { -} - -void LightStageSetup::run(const render::RenderContextPointer& renderContext) { - if (renderContext->_scene) { - auto stage = renderContext->_scene->getStage(LightStage::getName()); - if (!stage) { - stage = std::make_shared(); - renderContext->_scene->resetStage(LightStage::getName(), stage); - } - } -} - diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index 36e62c614f..5b0a90ddb6 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -4,6 +4,7 @@ // // Created by Zach Pomerantz on 1/14/2015. // Copyright 2015 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -12,34 +13,44 @@ #ifndef hifi_render_utils_LightStage_h #define hifi_render_utils_LightStage_h -#include -#include - #include - #include - -#include #include -#include +#include class ViewFrustum; -// Light stage to set up light-related rendering tasks -class LightStage : public render::Stage { +class LightFrame { public: - static std::string _stageName; - static const std::string& getName() { return _stageName; } + LightFrame() {} using Index = render::indexed_container::Index; - static const Index INVALID_INDEX; - static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } - - using LightPointer = graphics::LightPointer; - using Lights = render::indexed_container::IndexedPointerVector; - using LightMap = std::unordered_map; - using LightIndices = std::vector; + void clear() { _pointLights.clear(); _spotLights.clear(); _sunLights.clear(); _ambientLights.clear(); } + void pushLight(Index index, graphics::Light::Type type) { + switch (type) { + case graphics::Light::POINT: { pushPointLight(index); break; } + case graphics::Light::SPOT: { pushSpotLight(index); break; } + case graphics::Light::SUN: { pushSunLight(index); break; } + case graphics::Light::AMBIENT: { pushAmbientLight(index); break; } + default: { break; } + } + } + void pushPointLight(Index index) { _pointLights.emplace_back(index); } + void pushSpotLight(Index index) { _spotLights.emplace_back(index); } + void pushSunLight(Index index) { _sunLights.emplace_back(index); } + void pushAmbientLight(Index index) { _ambientLights.emplace_back(index); } + + render::ElementIndices _pointLights; + render::ElementIndices _spotLights; + render::ElementIndices _sunLights; + render::ElementIndices _ambientLights; +}; + +// Light stage to set up light-related rendering tasks +class LightStage : public render::PointerStage { +public: + using LightPointer = graphics::LightPointer; class Shadow { public: @@ -74,9 +85,9 @@ public: float left, float right, float bottom, float top, float viewMaxShadowDistance) const; }; - Shadow(graphics::LightPointer light, unsigned int cascadeCount = 1); + Shadow(LightPointer light, unsigned int cascadeCount = 1); - void setLight(graphics::LightPointer light); + void setLight(LightPointer light); void setKeylightFrustum(const ViewFrustum& viewFrustum, float nearDepth = 1.0f, float farDepth = 1000.0f); @@ -93,83 +104,46 @@ public: float getMaxDistance() const { return _maxDistance; } void setMaxDistance(float value); - const graphics::LightPointer& getLight() const { return _light; } + const LightPointer& getLight() const { return _light; } gpu::TexturePointer map; #include "Shadows_shared.slh" class Schema : public ShadowParameters { public: - Schema(); - }; + protected: using Cascades = std::vector; static const glm::mat4 _biasMatrix; - graphics::LightPointer _light; + LightPointer _light; float _maxDistance{ 0.0f }; Cascades _cascades; UniformBufferView _schemaBuffer = nullptr; }; - using ShadowPointer = std::shared_ptr; - Index findLight(const LightPointer& light) const; - Index addLight(const LightPointer& light, const bool shouldSetAsDefault = false); - + Index addElement(const LightPointer& light) override { return addElement(light, false); } + Index addElement(const LightPointer& light, const bool shouldSetAsDefault); + LightPointer removeElement(Index index) override; + Index getDefaultLight() { return _defaultLightId; } - LightPointer removeLight(Index index); - - bool checkLightId(Index index) const { return _lights.checkIndex(index); } - - Index getNumLights() const { return _lights.getNumElements(); } - Index getNumFreeLights() const { return _lights.getNumFreeIndices(); } - Index getNumAllocatedLights() const { return _lights.getNumAllocatedIndices(); } - - LightPointer getLight(Index lightId) const { return _lights.get(lightId); } - LightStage(); gpu::BufferPointer getLightArrayBuffer() const { return _lightArrayBuffer; } void updateLightArrayBuffer(Index lightId); - class Frame { - public: - Frame() {} - - void clear() { _pointLights.clear(); _spotLights.clear(); _sunLights.clear(); _ambientLights.clear(); } - void pushLight(LightStage::Index index, graphics::Light::Type type) { - switch (type) { - case graphics::Light::POINT: { pushPointLight(index); break; } - case graphics::Light::SPOT: { pushSpotLight(index); break; } - case graphics::Light::SUN: { pushSunLight(index); break; } - case graphics::Light::AMBIENT: { pushAmbientLight(index); break; } - default: { break; } - } - } - void pushPointLight(LightStage::Index index) { _pointLights.emplace_back(index); } - void pushSpotLight(LightStage::Index index) { _spotLights.emplace_back(index); } - void pushSunLight(LightStage::Index index) { _sunLights.emplace_back(index); } - void pushAmbientLight(LightStage::Index index) { _ambientLights.emplace_back(index); } - - LightStage::LightIndices _pointLights; - LightStage::LightIndices _spotLights; - LightStage::LightIndices _sunLights; - LightStage::LightIndices _ambientLights; - }; - using FramePointer = std::shared_ptr; - class ShadowFrame { public: ShadowFrame() {} - + void clear() {} - + using Object = ShadowPointer; using Objects = std::vector; @@ -177,20 +151,17 @@ public: _objects.emplace_back(shadow); } - Objects _objects; }; using ShadowFramePointer = std::shared_ptr; - Frame _currentFrame; - Index getAmbientOffLight() { return _ambientOffLightId; } Index getPointOffLight() { return _pointOffLightId; } Index getSpotOffLight() { return _spotOffLightId; } Index getSunOffLight() { return _sunOffLightId; } - LightPointer getCurrentKeyLight(const LightStage::Frame& frame) const; - LightPointer getCurrentAmbientLight(const LightStage::Frame& frame) const; + LightPointer getCurrentKeyLight(const LightFrame& frame) const; + LightPointer getCurrentAmbientLight(const LightFrame& frame) const; protected: @@ -201,9 +172,7 @@ protected: gpu::BufferPointer _lightArrayBuffer; - Lights _lights; Descs _descs; - LightMap _lightMap; // define off lights Index _ambientOffLightId; @@ -216,16 +185,9 @@ protected: }; using LightStagePointer = std::shared_ptr; - -class LightStageSetup { +class LightStageSetup : public render::StageSetup { public: using JobModel = render::Job::Model; - - LightStageSetup(); - void run(const render::RenderContextPointer& renderContext); - -protected: }; - #endif diff --git a/libraries/render-utils/src/RenderCommonTask.cpp b/libraries/render-utils/src/RenderCommonTask.cpp index c79ac87551..ba0460417c 100644 --- a/libraries/render-utils/src/RenderCommonTask.cpp +++ b/libraries/render-utils/src/RenderCommonTask.cpp @@ -1,6 +1,9 @@ // +// RenderCommonTask.cpp +// // Created by Bradley Austin Davis on 2018/01/09 // Copyright 2013-2018 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -78,9 +81,9 @@ void DrawLayered3D::run(const RenderContextPointer& renderContext, const Inputs& graphics::HazePointer haze; const auto& hazeStage = renderContext->args->_scene->getStage(); - if (hazeStage && hazeFrame->_hazes.size() > 0) { + if (hazeStage && hazeFrame->_elements.size() > 0) { // We use _hazes.back() here because the last haze object will always have haze disabled. - haze = hazeStage->getHaze(hazeFrame->_hazes.back()); + haze = hazeStage->getElement(hazeFrame->_elements.back()); } // Clear the framebuffer without stereo diff --git a/libraries/render-utils/src/RenderCommonTask.h b/libraries/render-utils/src/RenderCommonTask.h index 255fcb6392..5d6395aceb 100644 --- a/libraries/render-utils/src/RenderCommonTask.h +++ b/libraries/render-utils/src/RenderCommonTask.h @@ -1,6 +1,9 @@ // +// RenderCommonTask.h +// // Created by Bradley Austin Davis on 2018/01/09 // Copyright 2013-2018 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 270bbb8549..261658039c 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -5,6 +5,7 @@ // // Created by Sam Gateau on 5/29/15. // Copyright 2016 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -145,10 +146,6 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Shadow Stage Frame const auto shadowFrame = shadowTaskOutputs[1]; - if (depth == 0) { - task.addJob("FadeEffect", opaques); - } - const auto jitter = task.addJob("JitterCam"); // GPU jobs: Start preparing the primary, deferred and lighting buffer @@ -515,8 +512,8 @@ void RenderTransparentDeferred::run(const RenderContextPointer& renderContext, c // Setup haze if current zone has haze const auto& hazeStage = args->_scene->getStage(); - if (hazeStage && hazeFrame->_hazes.size() > 0) { - const auto& hazePointer = hazeStage->getHaze(hazeFrame->_hazes.front()); + if (hazeStage && hazeFrame->_elements.size() > 0) { + const auto& hazePointer = hazeStage->getElement(hazeFrame->_elements.front()); if (hazePointer) { batch.setUniformBuffer(graphics::slot::buffer::Buffer::HazeParams, hazePointer->getHazeParametersBuffer()); } diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index 74cdf1b044..85ea0facbe 100644 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -5,6 +5,7 @@ // // Created by Zach Pomerantz on 12/13/2016. // Copyright 2016 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -271,8 +272,8 @@ void DrawForward::run(const RenderContextPointer& renderContext, const Inputs& i graphics::HazePointer haze; const auto& hazeStage = renderContext->args->_scene->getStage(); - if (hazeStage && hazeFrame->_hazes.size() > 0) { - haze = hazeStage->getHaze(hazeFrame->_hazes.front()); + if (hazeStage && hazeFrame->_elements.size() > 0) { + haze = hazeStage->getElement(hazeFrame->_elements.front()); } gpu::doInBatch("DrawForward::run", args->_context, [&](gpu::Batch& batch) { diff --git a/libraries/render-utils/src/RenderViewTask.cpp b/libraries/render-utils/src/RenderViewTask.cpp index b9320b6ad3..0748006fb6 100644 --- a/libraries/render-utils/src/RenderViewTask.cpp +++ b/libraries/render-utils/src/RenderViewTask.cpp @@ -10,6 +10,7 @@ // #include "RenderViewTask.h" +#include "FadeEffect.h" #include "RenderShadowTask.h" #include "RenderCommonTask.h" #include "RenderDeferredTask.h" @@ -40,6 +41,13 @@ void DeferredForwardSwitchJob::build(JobModel& task, const render::Varying& inpu void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask, size_t depth) { const auto items = task.addJob("FetchCullSort", cullFunctor, tagBits, tagMask); + if (depth == 0 && tagBits == render::ItemKey::TAG_BITS_0) { + // TODO: This doesn't actually do any rendering, it simply processes the fade transactions. Even though forward rendering + // doesn't support fading right now, we still need to do this once for both paths, otherwise we are left with orphaned objects + // after they fade out. In the future, we should refactor this to happen elsewhere. + task.addJob("FadeEffect"); + } + // Issue the lighting model, aka the big global settings for the view const auto lightingModel = task.addJob("LightingModel"); diff --git a/libraries/render-utils/src/SubsurfaceScattering.cpp b/libraries/render-utils/src/SubsurfaceScattering.cpp index 9f1cf8421a..5964a1737c 100644 --- a/libraries/render-utils/src/SubsurfaceScattering.cpp +++ b/libraries/render-utils/src/SubsurfaceScattering.cpp @@ -473,8 +473,8 @@ void DebugSubsurfaceScattering::run(const render::RenderContextPointer& renderCo auto lightStage = renderContext->_scene->getStage(); assert(lightStage); - // const auto light = DependencyManager::get()->getLightStage()->getLight(0); - const auto light = lightStage->getLight(0); + // const auto light = DependencyManager::get()->getLightStage()->getElement(0); + const auto light = lightStage->getElement(0); if (!_debugParams) { _debugParams = std::make_shared(sizeof(glm::vec4), nullptr); _debugParams->setSubData(0, _debugCursorTexcoord); diff --git a/libraries/render-utils/src/ToneMapAndResampleTask.cpp b/libraries/render-utils/src/ToneMapAndResampleTask.cpp index d906d82aa7..c72776f1b6 100644 --- a/libraries/render-utils/src/ToneMapAndResampleTask.cpp +++ b/libraries/render-utils/src/ToneMapAndResampleTask.cpp @@ -4,6 +4,7 @@ // // Created by Anna Brewer on 7/3/19. // Copyright 2019 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -74,8 +75,8 @@ void ToneMapAndResample::run(const RenderContextPointer& renderContext, const In const auto& tonemappingStage = renderContext->_scene->getStage(); graphics::TonemappingPointer tonemapping; - if (tonemappingStage && tonemappingFrame->_tonemappings.size()) { - tonemapping = tonemappingStage->getTonemapping(tonemappingFrame->_tonemappings.front()); + if (tonemappingStage && tonemappingFrame->_elements.size()) { + tonemapping = tonemappingStage->getElement(tonemappingFrame->_elements.front()); } if (_debug) { diff --git a/libraries/render-utils/src/TonemappingStage.cpp b/libraries/render-utils/src/TonemappingStage.cpp index 9b6029ca1b..1bb382b77d 100644 --- a/libraries/render-utils/src/TonemappingStage.cpp +++ b/libraries/render-utils/src/TonemappingStage.cpp @@ -7,50 +7,8 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + #include "TonemappingStage.h" -#include - -std::string TonemappingStage::_stageName { "TONEMAPPING_STAGE" }; -const TonemappingStage::Index TonemappingStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX }; - -TonemappingStage::Index TonemappingStage::findTonemapping(const TonemappingPointer& tonemapping) const { - auto found = _tonemappingMap.find(tonemapping); - if (found != _tonemappingMap.end()) { - return INVALID_INDEX; - } else { - return (*found).second; - } -} - -TonemappingStage::Index TonemappingStage::addTonemapping(const TonemappingPointer& tonemapping) { - auto found = _tonemappingMap.find(tonemapping); - if (found == _tonemappingMap.end()) { - auto tonemappingId = _tonemappings.newElement(tonemapping); - // Avoid failing to allocate a tonemapping, just pass - if (tonemappingId != INVALID_INDEX) { - // Insert the tonemapping and its index in the reverse map - _tonemappingMap.insert(TonemappingMap::value_type(tonemapping, tonemappingId)); - } - return tonemappingId; - } else { - return (*found).second; - } -} - -TonemappingStage::TonemappingPointer TonemappingStage::removeTonemapping(Index index) { - TonemappingPointer removed = _tonemappings.freeElement(index); - if (removed) { - _tonemappingMap.erase(removed); - } - return removed; -} - -TonemappingStageSetup::TonemappingStageSetup() {} - -void TonemappingStageSetup::run(const render::RenderContextPointer& renderContext) { - auto stage = renderContext->_scene->getStage(TonemappingStage::getName()); - if (!stage) { - renderContext->_scene->resetStage(TonemappingStage::getName(), std::make_shared()); - } -} +template <> +std::string render::PointerStage::_name { "TONEMAPPING_STAGE" }; diff --git a/libraries/render-utils/src/TonemappingStage.h b/libraries/render-utils/src/TonemappingStage.h index 15161094a2..ee05c0ace4 100644 --- a/libraries/render-utils/src/TonemappingStage.h +++ b/libraries/render-utils/src/TonemappingStage.h @@ -11,74 +11,17 @@ #ifndef hifi_render_utils_TonemappingStage_h #define hifi_render_utils_TonemappingStage_h -#include -#include -#include -#include -#include - -#include -#include #include +#include +#include // Tonemapping stage to set up tonemapping-related rendering tasks -class TonemappingStage : public render::Stage { -public: - static std::string _stageName; - static const std::string& getName() { return _stageName; } - - using Index = render::indexed_container::Index; - static const Index INVALID_INDEX; - static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } - - using TonemappingPointer = graphics::TonemappingPointer; - using Tonemappings = render::indexed_container::IndexedPointerVector; - using TonemappingMap = std::unordered_map; - - using TonemappingIndices = std::vector; - - Index findTonemapping(const TonemappingPointer& tonemapping) const; - Index addTonemapping(const TonemappingPointer& tonemapping); - - TonemappingPointer removeTonemapping(Index index); - - bool checkTonemappingId(Index index) const { return _tonemappings.checkIndex(index); } - - Index getNumTonemappings() const { return _tonemappings.getNumElements(); } - Index getNumFreeTonemappings() const { return _tonemappings.getNumFreeIndices(); } - Index getNumAllocatedTonemappings() const { return _tonemappings.getNumAllocatedIndices(); } - - TonemappingPointer getTonemapping(Index tonemappingId) const { - return _tonemappings.get(tonemappingId); - } - - Tonemappings _tonemappings; - TonemappingMap _tonemappingMap; - - class Frame { - public: - Frame() {} - - void clear() { _tonemappings.clear(); } - - void pushTonemapping(TonemappingStage::Index index) { _tonemappings.emplace_back(index); } - - TonemappingStage::TonemappingIndices _tonemappings; - }; - using FramePointer = std::shared_ptr; - - Frame _currentFrame; -}; +class TonemappingStage : public render::PointerStage {}; using TonemappingStagePointer = std::shared_ptr; -class TonemappingStageSetup { +class TonemappingStageSetup : public render::StageSetup { public: using JobModel = render::Job::Model; - - TonemappingStageSetup(); - void run(const render::RenderContextPointer& renderContext); - -protected: }; #endif diff --git a/libraries/render-utils/src/ZoneRenderer.cpp b/libraries/render-utils/src/ZoneRenderer.cpp index a8fb349e4d..5d958d8a84 100644 --- a/libraries/render-utils/src/ZoneRenderer.cpp +++ b/libraries/render-utils/src/ZoneRenderer.cpp @@ -4,6 +4,7 @@ // // Created by Sam Gateau on 4/4/2017. // Copyright 2017 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -86,11 +87,11 @@ void SetupZones::run(const RenderContextPointer& context, const Input& input) { // Finally add the default lights and background: lightStage->_currentFrame.pushSunLight(lightStage->getDefaultLight()); lightStage->_currentFrame.pushAmbientLight(lightStage->getDefaultLight()); - backgroundStage->_currentFrame.pushBackground(0); - hazeStage->_currentFrame.pushHaze(0); - bloomStage->_currentFrame.pushBloom(INVALID_INDEX); - tonemappingStage->_currentFrame.pushTonemapping(0); - ambientOcclusionStage->_currentFrame.pushAmbientOcclusion(INVALID_INDEX); + backgroundStage->_currentFrame.pushElement(0); + hazeStage->_currentFrame.pushElement(0); + bloomStage->_currentFrame.pushElement(INVALID_INDEX); + tonemappingStage->_currentFrame.pushElement(0); + ambientOcclusionStage->_currentFrame.pushElement(INVALID_INDEX); } gpu::PipelinePointer DebugZoneLighting::_keyLightPipeline; @@ -144,22 +145,22 @@ void DebugZoneLighting::run(const render::RenderContextPointer& context, const I std::vector keyLightStack; if (lightStage && lightFrame->_sunLights.size()) { for (auto index : lightFrame->_sunLights) { - keyLightStack.push_back(lightStage->getLight(index)); + keyLightStack.push_back(lightStage->getElement(index)); } } std::vector ambientLightStack; if (lightStage && lightFrame->_ambientLights.size()) { for (auto index : lightFrame->_ambientLights) { - ambientLightStack.push_back(lightStage->getLight(index)); + ambientLightStack.push_back(lightStage->getElement(index)); } } auto backgroundStage = context->_scene->getStage(BackgroundStage::getName()); std::vector skyboxStack; - if (backgroundStage && backgroundFrame->_backgrounds.size()) { - for (auto index : backgroundFrame->_backgrounds) { - auto background = backgroundStage->getBackground(index); + if (backgroundStage && backgroundFrame->_elements.size()) { + for (auto index : backgroundFrame->_elements) { + auto background = backgroundStage->getElement(index); if (background) { skyboxStack.push_back(background->getSkybox()); } diff --git a/libraries/render-utils/src/sdf_text3D.slh b/libraries/render-utils/src/sdf_text3D.slh index c927070a4d..5471415e1c 100644 --- a/libraries/render-utils/src/sdf_text3D.slh +++ b/libraries/render-utils/src/sdf_text3D.slh @@ -95,8 +95,8 @@ vec4 evalSDFColor(vec2 texCoord, vec4 glyphBounds) { vec4 evalSDFSuperSampled(vec2 texCoord, vec2 positionMS, vec4 glyphBounds) { // Clip to edges. Note: We don't need to check the top edge. - if (positionMS.x < params.bounds.x || positionMS.x > (params.bounds.x + params.bounds.z) || - positionMS.y < params.bounds.y - params.bounds.w) { + if ((params.bounds.z > 0.0 && (positionMS.x < params.bounds.x || positionMS.x > (params.bounds.x + params.bounds.z))) || + (params.bounds.w > 0.0 && (positionMS.y < params.bounds.y - params.bounds.w))) { return vec4(0.0); } diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp index 81badb8440..23699de69a 100644 --- a/libraries/render-utils/src/text/Font.cpp +++ b/libraries/render-utils/src/text/Font.cpp @@ -438,7 +438,7 @@ void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm // Draw the token for (const QChar& c : token) { - if (advance.x > rightEdge) { + if (bounds.x != -1 && advance.x > rightEdge) { break; } const Glyph& glyph = _glyphs[c]; diff --git a/libraries/render-utils/src/text/Font.h b/libraries/render-utils/src/text/Font.h index 8112e279e5..730f6db758 100644 --- a/libraries/render-utils/src/text/Font.h +++ b/libraries/render-utils/src/text/Font.h @@ -71,8 +71,8 @@ public: bool forward, bool mirror) : str(str), color(color), effectColor(effectColor), origin(origin), bounds(bounds), scale(scale), effectThickness(effectThickness), effect(effect), alignment(alignment), verticalAlignment(verticalAlignment), unlit(unlit), forward(forward), mirror(mirror) {} - DrawProps(const QString& str, const glm::vec4& color, const glm::vec2& origin, const glm::vec2& bounds, bool forward) : - str(str), color(color), origin(origin), bounds(bounds), forward(forward) {} + DrawProps(const QString& str, const glm::vec4& color, const glm::vec2& origin, const glm::vec2& bounds, TextAlignment alignment, bool forward) : + str(str), color(color), origin(origin), bounds(bounds), alignment(alignment), forward(forward) {} const QString& str; const glm::vec4& color; diff --git a/libraries/render/src/render/DrawStatus.cpp b/libraries/render/src/render/DrawStatus.cpp index 925cffdae1..d722197205 100644 --- a/libraries/render/src/render/DrawStatus.cpp +++ b/libraries/render/src/render/DrawStatus.cpp @@ -4,6 +4,7 @@ // // Created by Niraj Venkat on 6/29/15. // Copyright 2015 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -163,7 +164,7 @@ void DrawStatus::run(const RenderContextPointer& renderContext, const Input& inp status.setColor(Item::Status::Value::RED); } // Set icon based on transition type - auto& transition = transitionStage->getTransition(transitionID); + auto& transition = transitionStage->getElement(transitionID); switch (transition.eventType) { case Transition::Type::USER_ENTER_DOMAIN: status.setIcon((unsigned char)Item::Status::Icon::USER_TRANSITION_IN); diff --git a/libraries/render/src/render/HighlightStage.cpp b/libraries/render/src/render/HighlightStage.cpp index c9f097b387..07fb5b5635 100644 --- a/libraries/render/src/render/HighlightStage.cpp +++ b/libraries/render/src/render/HighlightStage.cpp @@ -1,33 +1,31 @@ +// +// HighlightStage.cpp +// +// Created by Olivier Prat on 07/07/2017. +// Copyright 2017 High Fidelity, Inc. +// Copyright 2024 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + #include "HighlightStage.h" +#include "Engine.h" + using namespace render; -std::string HighlightStage::_name("Highlight"); -const HighlightStage::Index HighlightStage::INVALID_INDEX{ render::indexed_container::INVALID_INDEX }; +template <> +std::string TypedStage::_name { "HIGHLIGHT_STAGE" }; HighlightStage::Index HighlightStage::addHighlight(const std::string& selectionName, const HighlightStyle& style) { - Highlight outline{ selectionName, style }; - Index id; - - id = _highlights.newElement(outline); - _activeHighlightIds.push_back(id); - - return id; + Highlight outline { selectionName, style }; + return addElement(outline); } -void HighlightStage::removeHighlight(Index index) { - HighlightIdList::iterator idIterator = std::find(_activeHighlightIds.begin(), _activeHighlightIds.end(), index); - if (idIterator != _activeHighlightIds.end()) { - _activeHighlightIds.erase(idIterator); - } - if (!_highlights.isElementFreed(index)) { - _highlights.freeElement(index); - } -} - -Index HighlightStage::getHighlightIdBySelection(const std::string& selectionName) const { - for (auto outlineId : _activeHighlightIds) { - const auto& outline = _highlights.get(outlineId); +HighlightStage::Index HighlightStage::getHighlightIdBySelection(const std::string& selectionName) const { + for (auto outlineId : _activeElementIDs) { + const auto& outline = _elements.get(outlineId); if (outline._selectionName == selectionName) { return outlineId; } @@ -100,9 +98,6 @@ void HighlightStageConfig::setOccludedFillOpacity(float value) { emit dirty(); } -HighlightStageSetup::HighlightStageSetup() { -} - void HighlightStageSetup::configure(const Config& config) { // Copy the styles here but update the stage with the new styles in run to be sure everything is // thread safe... @@ -112,8 +107,7 @@ void HighlightStageSetup::configure(const Config& config) { void HighlightStageSetup::run(const render::RenderContextPointer& renderContext) { auto stage = renderContext->_scene->getStage(HighlightStage::getName()); if (!stage) { - stage = std::make_shared(); - renderContext->_scene->resetStage(HighlightStage::getName(), stage); + renderContext->_scene->resetStage(HighlightStage::getName(), std::make_shared()); } if (!_styles.empty()) { @@ -127,4 +121,3 @@ void HighlightStageSetup::run(const render::RenderContextPointer& renderContext) _styles.clear(); } } - diff --git a/libraries/render/src/render/HighlightStage.h b/libraries/render/src/render/HighlightStage.h index 91d8cc3f81..d675ed9f6b 100644 --- a/libraries/render/src/render/HighlightStage.h +++ b/libraries/render/src/render/HighlightStage.h @@ -3,6 +3,7 @@ // Created by Olivier Prat on 07/07/2017. // Copyright 2017 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -11,56 +12,27 @@ #ifndef hifi_render_utils_HighlightStage_h #define hifi_render_utils_HighlightStage_h -#include "Stage.h" #include "Engine.h" -#include "IndexedContainer.h" #include "HighlightStyle.h" +#include "Stage.h" namespace render { - // Highlight stage to set up HighlightStyle-related effects - class HighlightStage : public Stage { + class Highlight { public: + Highlight(const std::string& selectionName, const HighlightStyle& style) : _selectionName{ selectionName }, _style{ style } { } - class Highlight { - public: - - Highlight(const std::string& selectionName, const HighlightStyle& style) : _selectionName{ selectionName }, _style{ style } { } - - std::string _selectionName; - HighlightStyle _style; - - }; - - static const std::string& getName() { return _name; } - - using Index = render::indexed_container::Index; - static const Index INVALID_INDEX; - using HighlightIdList = render::indexed_container::Indices; - - static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } - - bool checkHighlightId(Index index) const { return _highlights.checkIndex(index); } - - const Highlight& getHighlight(Index index) const { return _highlights.get(index); } - Highlight& editHighlight(Index index) { return _highlights.edit(index); } + std::string _selectionName; + HighlightStyle _style; + }; + // Highlight stage to set up HighlightStyle-related effects + class HighlightStage : public TypedStage { + public: Index addHighlight(const std::string& selectionName, const HighlightStyle& style = HighlightStyle()); Index getHighlightIdBySelection(const std::string& selectionName) const; - void removeHighlight(Index index); - HighlightIdList::iterator begin() { return _activeHighlightIds.begin(); } - HighlightIdList::iterator end() { return _activeHighlightIds.end(); } - const HighlightIdList& getActiveHighlightIds() const { return _activeHighlightIds; } - - private: - - using Highlights = render::indexed_container::IndexedVector; - - static std::string _name; - - Highlights _highlights; - HighlightIdList _activeHighlightIds; + const IDList& getActiveHighlightIds() const { return _activeElementIDs; } }; using HighlightStagePointer = std::shared_ptr; @@ -122,7 +94,7 @@ namespace render { using Config = HighlightStageConfig; using JobModel = render::Job::Model; - HighlightStageSetup(); + HighlightStageSetup() {} void configure(const Config& config); void run(const RenderContextPointer& renderContext); diff --git a/libraries/render/src/render/HighlightStyle.h b/libraries/render/src/render/HighlightStyle.h index 138674ffbb..266ce71262 100644 --- a/libraries/render/src/render/HighlightStyle.h +++ b/libraries/render/src/render/HighlightStyle.h @@ -17,6 +17,8 @@ #include +#include + namespace render { // This holds the configuration for a particular outline style diff --git a/libraries/render/src/render/Scene.cpp b/libraries/render/src/render/Scene.cpp index a9bb2a5856..3776caef0d 100644 --- a/libraries/render/src/render/Scene.cpp +++ b/libraries/render/src/render/Scene.cpp @@ -440,7 +440,7 @@ void Scene::queryTransitionItems(const Transaction::TransitionQueries& transacti auto transitionId = item.getTransitionId(); if (!TransitionStage::isIndexInvalid(transitionId)) { - auto& transition = transitionStage->getTransition(transitionId); + auto& transition = transitionStage->getElement(transitionId); func(itemId, &transition); } else { func(itemId, nullptr); @@ -477,7 +477,7 @@ void Scene::resetHighlights(const Transaction::HighlightResets& transactions) { if (HighlightStage::isIndexInvalid(outlineId)) { outlineStage->addHighlight(selectionName, newStyle); } else { - outlineStage->editHighlight(outlineId)._style = newStyle; + outlineStage->editElement(outlineId)._style = newStyle; } } } @@ -490,7 +490,7 @@ void Scene::removeHighlights(const Transaction::HighlightRemoves& transactions) auto outlineId = outlineStage->getHighlightIdBySelection(selectionName); if (!HighlightStage::isIndexInvalid(outlineId)) { - outlineStage->removeHighlight(outlineId); + outlineStage->removeElement(outlineId); } } } @@ -505,7 +505,7 @@ void Scene::queryHighlights(const Transaction::HighlightQueries& transactions) { auto outlineId = outlineStage->getHighlightIdBySelection(selectionName); if (!HighlightStage::isIndexInvalid(outlineId)) { - func(&outlineStage->editHighlight(outlineId)._style); + func(&outlineStage->editElement(outlineId)._style); } else { func(nullptr); } @@ -559,7 +559,7 @@ void Scene::removeItemTransition(ItemID itemId) { auto& item = _items[itemId]; TransitionStage::Index transitionId = item.getTransitionId(); if (!render::TransitionStage::isIndexInvalid(transitionId)) { - const auto& transition = transitionStage->getTransition(transitionId); + const auto& transition = transitionStage->getElement(transitionId); const auto transitionOwner = transition.itemId; if (transitionOwner == itemId) { // No more items will be using this transition. Clean it up. @@ -570,7 +570,7 @@ void Scene::removeItemTransition(ItemID itemId) { } } _transitionFinishedOperatorMap.erase(transitionId); - transitionStage->removeTransition(transitionId); + transitionStage->removeElement(transitionId); } setItemTransition(itemId, render::TransitionStage::INVALID_INDEX); diff --git a/libraries/render/src/render/Stage.cpp b/libraries/render/src/render/Stage.cpp index 1ee9b1d6ff..d5335f07ed 100644 --- a/libraries/render/src/render/Stage.cpp +++ b/libraries/render/src/render/Stage.cpp @@ -4,23 +4,13 @@ // // Created by Sam Gateau on 6/14/2017. // Copyright 2017 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "Stage.h" - using namespace render; - - -Stage::~Stage() { - -} - -Stage::Stage() : - _name() -{ -} - +const Stage::Index Stage::INVALID_INDEX { render::indexed_container::INVALID_INDEX }; diff --git a/libraries/render/src/render/Stage.h b/libraries/render/src/render/Stage.h index 5145810671..2bb81771e5 100644 --- a/libraries/render/src/render/Stage.h +++ b/libraries/render/src/render/Stage.h @@ -4,6 +4,7 @@ // // Created by Sam Gateau on 6/14/2017. // Copyright 2017 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -12,27 +13,141 @@ #ifndef hifi_render_Stage_h #define hifi_render_Stage_h -#include #include +#include +#include #include +#include "IndexedContainer.h" + namespace render { + using ElementIndices = std::vector; + class Stage { public: + Stage() {} + virtual ~Stage() {} + using Name = std::string; + using Index = indexed_container::Index; + static const Index INVALID_INDEX; + using IDList = indexed_container::Indices; - Stage(); - virtual ~Stage(); - - protected: - Name _name; + static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } }; using StagePointer = std::shared_ptr; - using StageMap = std::map; + template + class TypedStage : public Stage { + public: + TypedStage() {} + virtual ~TypedStage() {} + + static const Name& getName() { return _name; } + + bool checkId(Index index) const { return _elements.checkIndex(index); } + + const T& getElement(Index id) const { return _elements.get(id); } + T& editElement(Index id) { return _elements.edit(id); } + Index addElement(const T& element) { + Index id = _elements.newElement(element); + _activeElementIDs.push_back(id); + return id; + } + + void removeElement(Index index) { + IDList::iterator idIterator = std::find(_activeElementIDs.begin(), _activeElementIDs.end(), index); + if (idIterator != _activeElementIDs.end()) { + _activeElementIDs.erase(idIterator); + } + if (!_elements.isElementFreed(index)) { + _elements.freeElement(index); + } + } + + IDList::iterator begin() { return _activeElementIDs.begin(); } + IDList::iterator end() { return _activeElementIDs.end(); } + protected: + static Name _name; + + indexed_container::IndexedVector _elements; + IDList _activeElementIDs; + }; + + class Frame { + public: + Frame() {} + + using Index = indexed_container::Index; + + void clear() { _elements.clear(); } + void pushElement(Index index) { _elements.emplace_back(index); } + + ElementIndices _elements; + }; + + template + class PointerStage : public Stage { + public: + PointerStage() {} + virtual ~PointerStage() {} + + static const Name& getName() { return _name; } + + bool checkId(Index index) const { return _elements.checkIndex(index); } + + Index getNumElements() const { return _elements.getNumElements(); } + Index getNumFreeElements() const { return _elements.getNumFreeIndices(); } + Index getNumAllocatedElements() const { return _elements.getNumAllocatedIndices(); } + + P getElement(Index id) const { return _elements.get(id); } + + Index findElement(const P& element) const { + auto found = _elementMap.find(element); + if (found != _elementMap.end()) { + return INVALID_INDEX; + } else { + return (*found).second; + } + } + + virtual Index addElement(const P& element) { + auto found = _elementMap.find(element); + if (found == _elementMap.end()) { + auto id = _elements.newElement(element); + // Avoid failing to allocate an element, just pass + if (id != INVALID_INDEX) { + // Insert the element and its index in the reverse map + _elementMap[element] = id; + } + return id; + } else { + return (*found).second; + } + } + + virtual P removeElement(Index index) { + P removed = _elements.freeElement(index); + + if (removed) { + _elementMap.erase(removed); + } + return removed; + } + + using Frame = F; + using FramePointer = std::shared_ptr; + F _currentFrame; + + protected: + static Name _name; + + indexed_container::IndexedPointerVector _elements; + std::unordered_map _elementMap; + }; } #endif // hifi_render_Stage_h diff --git a/libraries/render/src/render/StageSetup.h b/libraries/render/src/render/StageSetup.h new file mode 100644 index 0000000000..5691bca207 --- /dev/null +++ b/libraries/render/src/render/StageSetup.h @@ -0,0 +1,35 @@ +// +// StageSetup.h +// render/src/render +// +// Created by HifiExperiments on 10/16/24 +// Copyright 2024 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_render_StageSetup_h +#define hifi_render_StageSetup_h + +#include "Engine.h" + +namespace render { + + template + class StageSetup { + public: + StageSetup() {} + + void run(const RenderContextPointer& renderContext) { + if (renderContext->_scene) { + auto stage = renderContext->_scene->getStage(T::getName()); + if (!stage) { + renderContext->_scene->resetStage(T::getName(), std::make_shared()); + } + } + } + }; +} + +#endif // hifi_render_StageSetup_h diff --git a/libraries/render/src/render/TransitionStage.cpp b/libraries/render/src/render/TransitionStage.cpp index 9ddc72f4db..72637cc3d9 100644 --- a/libraries/render/src/render/TransitionStage.cpp +++ b/libraries/render/src/render/TransitionStage.cpp @@ -1,43 +1,25 @@ -#include "TransitionStage.h" +// +// TransitionStage.cpp +// +// Created by Olivier Prat on 07/07/2017. +// Copyright 2017 High Fidelity, Inc. +// Copyright 2024 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// -#include +#include "TransitionStage.h" using namespace render; -std::string TransitionStage::_name("Transition"); -const TransitionStage::Index TransitionStage::INVALID_INDEX{ indexed_container::INVALID_INDEX }; +template <> +std::string TypedStage::_name { "TRANSITION_STAGE" }; TransitionStage::Index TransitionStage::addTransition(ItemID itemId, Transition::Type type, ItemID boundId) { Transition transition; - Index id; - transition.eventType = type; transition.itemId = itemId; transition.boundItemId = boundId; - id = _transitions.newElement(transition); - _activeTransitionIds.push_back(id); - - return id; + return addElement(transition); } - -void TransitionStage::removeTransition(Index index) { - TransitionIdList::iterator idIterator = std::find(_activeTransitionIds.begin(), _activeTransitionIds.end(), index); - if (idIterator != _activeTransitionIds.end()) { - _activeTransitionIds.erase(idIterator); - } - if (!_transitions.isElementFreed(index)) { - _transitions.freeElement(index); - } -} - -TransitionStageSetup::TransitionStageSetup() { -} - -void TransitionStageSetup::run(const RenderContextPointer& renderContext) { - auto stage = renderContext->_scene->getStage(TransitionStage::getName()); - if (!stage) { - stage = std::make_shared(); - renderContext->_scene->resetStage(TransitionStage::getName(), stage); - } -} - diff --git a/libraries/render/src/render/TransitionStage.h b/libraries/render/src/render/TransitionStage.h index abfdca9a06..11256fb346 100644 --- a/libraries/render/src/render/TransitionStage.h +++ b/libraries/render/src/render/TransitionStage.h @@ -1,8 +1,9 @@ // // TransitionStage.h - +// // Created by Olivier Prat on 07/07/2017. // Copyright 2017 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -12,55 +13,22 @@ #define hifi_render_TransitionStage_h #include "Stage.h" -#include "IndexedContainer.h" -#include "Engine.h" +#include "StageSetup.h" #include "Transition.h" namespace render { // Transition stage to set up Transition-related effects - class TransitionStage : public render::Stage { + class TransitionStage : public TypedStage { public: - - static const std::string& getName() { return _name; } - - using Index = indexed_container::Index; - static const Index INVALID_INDEX; - using TransitionIdList = indexed_container::Indices; - - static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } - - bool isTransitionUsed(Index index) const { return _transitions.checkIndex(index) && !_transitions.isElementFreed(index); } - - const Transition& getTransition(Index TransitionId) const { return _transitions.get(TransitionId); } - - Transition& editTransition(Index TransitionId) { return _transitions.edit(TransitionId); } - + bool isTransitionUsed(Index index) const { return _elements.checkIndex(index) && !_elements.isElementFreed(index); } Index addTransition(ItemID itemId, Transition::Type type, ItemID boundId); - void removeTransition(Index index); - - TransitionIdList::iterator begin() { return _activeTransitionIds.begin(); } - TransitionIdList::iterator end() { return _activeTransitionIds.end(); } - - private: - - using Transitions = indexed_container::IndexedVector; - - static std::string _name; - - Transitions _transitions; - TransitionIdList _activeTransitionIds; }; using TransitionStagePointer = std::shared_ptr; - class TransitionStageSetup { + class TransitionStageSetup : public StageSetup { public: - using JobModel = render::Job::Model; - - TransitionStageSetup(); - void run(const RenderContextPointer& renderContext); - - protected: + using JobModel = Job::Model; }; } diff --git a/libraries/script-engine/src/ScriptManager.cpp b/libraries/script-engine/src/ScriptManager.cpp index 23122cc302..58fee1f06d 100644 --- a/libraries/script-engine/src/ScriptManager.cpp +++ b/libraries/script-engine/src/ScriptManager.cpp @@ -381,6 +381,7 @@ ScriptManager::~ScriptManager() { if (_type == ScriptManager::Type::ENTITY_CLIENT) { printf("ScriptManager::~ScriptManager"); } + _isDeleted = true; } void ScriptManager::disconnectNonEssentialSignals() { @@ -426,7 +427,10 @@ void ScriptManager::runInThread() { void ScriptManager::executeOnScriptThread(std::function function, const Qt::ConnectionType& type ) { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "executeOnScriptThread", type, Q_ARG(std::function, function)); + // Lambda is necessary there to keep shared_ptr counter above zero + QMetaObject::invokeMethod(this, [=, manager = shared_from_this()]{ + manager->executeOnScriptThread(function, type); + }); return; } @@ -858,10 +862,10 @@ void ScriptManager::removeEventHandler(const EntityItemID& entityID, const QStri qCDebug(scriptengine) << "*** WARNING *** ScriptManager::removeEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " "entityID:" << entityID << " eventName:" << eventName; #endif - QMetaObject::invokeMethod(this, "removeEventHandler", - Q_ARG(const EntityItemID&, entityID), - Q_ARG(const QString&, eventName), - Q_ARG(const ScriptValue&, handler)); + // Lambda is necessary there to keep shared_ptr counter above zero + QMetaObject::invokeMethod(this, [=, manager = shared_from_this()]{ + manager->removeEventHandler(entityID, eventName, handler); + }); return; } #ifdef THREAD_DEBUGGING @@ -905,10 +909,10 @@ void ScriptManager::addEventHandler(const EntityItemID& entityID, const QString& "entityID:" << entityID << " eventName:" << eventName; #endif - QMetaObject::invokeMethod(this, "addEventHandler", - Q_ARG(const EntityItemID&, entityID), - Q_ARG(const QString&, eventName), - Q_ARG(const ScriptValue&, handler)); + // Lambda is necessary there to keep shared_ptr counter above zero + QMetaObject::invokeMethod(this, [=, manager = shared_from_this()]{ + manager->addEventHandler(entityID, eventName, handler); + }); return; } #ifdef THREAD_DEBUGGING @@ -1167,7 +1171,10 @@ void ScriptManager::stop(bool marshal) { _isStopping = true; // this can be done on any thread if (marshal) { - QMetaObject::invokeMethod(this, "stop"); + // Lambda is necessary there to keep shared_ptr counter above zero if this gets called from different thread + QMetaObject::invokeMethod(this, [=, manager = shared_from_this()]{ + manager->stop(false); + }); return; } @@ -2011,11 +2018,10 @@ bool ScriptManager::hasEntityScriptDetails(const EntityItemID& entityID) const { void ScriptManager::loadEntityScript(const EntityItemID& entityID, const QString& entityScript, bool forceRedownload) { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "loadEntityScript", - Q_ARG(const EntityItemID&, entityID), - Q_ARG(const QString&, entityScript), - Q_ARG(bool, forceRedownload) - ); + // Lambda is necessary there to keep shared_ptr counter above zero + QMetaObject::invokeMethod(this, [=, manager = shared_from_this()]{ + manager->loadEntityScript(entityID, entityScript, forceRedownload); + }); return; } PROFILE_RANGE(script, __FUNCTION__); @@ -2092,13 +2098,10 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c << contents << "isURL:" << isURL << "success:" << success; #endif - QMetaObject::invokeMethod(this, "entityScriptContentAvailable", - Q_ARG(const EntityItemID&, entityID), - Q_ARG(const QString&, scriptOrURL), - Q_ARG(const QString&, contents), - Q_ARG(bool, isURL), - Q_ARG(bool, success), - Q_ARG(const QString&, status)); + // Lambda is necessary there to keep shared_ptr counter above zero + QMetaObject::invokeMethod(this, [=, manager = shared_from_this()]{ + manager->entityScriptContentAvailable(entityID, scriptOrURL, contents, isURL, success, status); + }); return; } @@ -2442,9 +2445,10 @@ void ScriptManager::unloadEntityScript(const EntityItemID& entityID, bool should "entityID:" << entityID; #endif - QMetaObject::invokeMethod(this, "unloadEntityScript", - Q_ARG(const EntityItemID&, entityID), - Q_ARG(bool, shouldRemoveFromMap)); + // Lambda is necessary there to keep shared_ptr counter above zero + QMetaObject::invokeMethod(this, [=, manager = shared_from_this()]{ + manager->unloadEntityScript(entityID, shouldRemoveFromMap); + }); return; } #ifdef THREAD_DEBUGGING @@ -2494,9 +2498,10 @@ void ScriptManager::unloadAllEntityScripts(bool blockingCall) { #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptManager::unloadAllEntityScripts() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; #endif - - QMetaObject::invokeMethod(this, "unloadAllEntityScripts", - blockingCall ? Qt::BlockingQueuedConnection : Qt::QueuedConnection); + // Lambda is necessary there to keep shared_ptr counter above zero + QMetaObject::invokeMethod(this, [=, manager = shared_from_this()] { + manager->unloadAllEntityScripts(blockingCall); + }, blockingCall ? Qt::BlockingQueuedConnection : Qt::QueuedConnection); return; } #ifdef THREAD_DEBUGGING @@ -2589,12 +2594,10 @@ void ScriptManager::callEntityScriptMethod(const EntityItemID& entityID, const Q qCDebug(scriptengine) << "*** WARNING *** ScriptManager::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " "entityID:" << entityID << "methodName:" << methodName; #endif - - QMetaObject::invokeMethod(this, "callEntityScriptMethod", - Q_ARG(const EntityItemID&, entityID), - Q_ARG(const QString&, methodName), - Q_ARG(const QStringList&, params), - Q_ARG(const QUuid&, remoteCallerID)); + // Lambda is necessary there to keep shared_ptr counter above zero + QMetaObject::invokeMethod(this, [=, manager = shared_from_this()]{ + manager->callEntityScriptMethod(entityID, methodName, params, remoteCallerID); + }); return; } #ifdef THREAD_DEBUGGING @@ -2659,10 +2662,10 @@ void ScriptManager::callEntityScriptMethod(const EntityItemID& entityID, const Q "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent"; #endif - QMetaObject::invokeMethod(this, "callEntityScriptMethod", - Q_ARG(const EntityItemID&, entityID), - Q_ARG(const QString&, methodName), - Q_ARG(const PointerEvent&, event)); + // Lambda is necessary there to keep shared_ptr counter above zero + QMetaObject::invokeMethod(this, [=, manager = shared_from_this()]{ + manager->callEntityScriptMethod(entityID, methodName, event); + }); return; } #ifdef THREAD_DEBUGGING @@ -2698,11 +2701,10 @@ void ScriptManager::callEntityScriptMethod(const EntityItemID& entityID, const Q "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision"; #endif - QMetaObject::invokeMethod(this, "callEntityScriptMethod", - Q_ARG(const EntityItemID&, entityID), - Q_ARG(const QString&, methodName), - Q_ARG(const EntityItemID&, otherID), - Q_ARG(const Collision&, collision)); + // Lambda is necessary there to keep shared_ptr counter above zero + QMetaObject::invokeMethod(this, [=, manager = shared_from_this()]{ + manager->callEntityScriptMethod(entityID, methodName, otherID, collision); + }); return; } #ifdef THREAD_DEBUGGING diff --git a/libraries/script-engine/src/ScriptManager.h b/libraries/script-engine/src/ScriptManager.h index 8197f26285..7185d3e615 100644 --- a/libraries/script-engine/src/ScriptManager.h +++ b/libraries/script-engine/src/ScriptManager.h @@ -280,9 +280,6 @@ public: */ class ScriptManager : public QObject, public EntitiesScriptEngineProvider, public std::enable_shared_from_this { Q_OBJECT - Q_PROPERTY(QString context READ getContext) - Q_PROPERTY(QString type READ getTypeAsString) - Q_PROPERTY(QString fileName MEMBER _fileNameString CONSTANT) public: static const QString SCRIPT_EXCEPTION_FORMAT; static const QString SCRIPT_BACKTRACE_SEP; @@ -381,8 +378,11 @@ public: Q_ENUM(Type); static int processLevelMaxRetries; - ScriptManager(Context context, const QString& scriptContents = NO_SCRIPT, const QString& fileNameString = QString("about:ScriptEngine")); - ~ScriptManager(); +private: + // Constructor is private so that only properly generated shared pointer can be used + explicit ScriptManager(Context context, const QString& scriptContents = NO_SCRIPT, const QString& fileNameString = QString("about:ScriptEngine")); +public: + ~ScriptManager() override; // static initialization support typedef void (*ScriptManagerInitializer)(ScriptManager*); @@ -390,7 +390,7 @@ public: public: ScriptManagerInitializer init; StaticInitializerNode* prev; - inline StaticInitializerNode(ScriptManagerInitializer&& pInit) : init(std::move(pInit)),prev(nullptr) { registerNewStaticInitializer(this); } + inline explicit StaticInitializerNode(ScriptManagerInitializer&& pInit) : init(std::move(pInit)),prev(nullptr) { registerNewStaticInitializer(this); } }; static void registerNewStaticInitializer(StaticInitializerNode* dest); @@ -398,7 +398,7 @@ public: public: ScriptManagerInitializer init; StaticTypesInitializerNode* prev; - inline StaticTypesInitializerNode(ScriptManagerInitializer&& pInit) : init(std::move(pInit)),prev(nullptr) { registerNewStaticTypesInitializer(this); } + inline explicit StaticTypesInitializerNode(ScriptManagerInitializer&& pInit) : init(std::move(pInit)),prev(nullptr) { registerNewStaticTypesInitializer(this); } }; static void registerNewStaticTypesInitializer(StaticTypesInitializerNode* dest); @@ -1668,6 +1668,7 @@ protected: friend ScriptManagerPointer newScriptManager(Context context, const QString& scriptContents, const QString& fileNameString); friend class ScriptManagerScriptingInterface; + std::atomic _isDeleted {false}; // This is used for debugging use-after-delete. It happens quite often, so I'm keeping it here for now. }; /** diff --git a/libraries/script-engine/src/ScriptManagerScriptingInterface.h b/libraries/script-engine/src/ScriptManagerScriptingInterface.h index 9fc23de283..0a2ccb66e3 100644 --- a/libraries/script-engine/src/ScriptManagerScriptingInterface.h +++ b/libraries/script-engine/src/ScriptManagerScriptingInterface.h @@ -58,6 +58,9 @@ public: class ScriptManagerScriptingInterface : public QObject { Q_OBJECT + Q_PROPERTY(QString context READ getContext) + Q_PROPERTY(QString type READ getTypeAsString) + Q_PROPERTY(QString fileName READ getAbsoluteFilename CONSTANT) public: ScriptManagerScriptingInterface(ScriptManager *parent); @@ -96,6 +99,26 @@ public: */ Q_INVOKABLE QString getContext() const { return _manager->getContext(); } + /*@jsdoc + * Gets the type of script that is running: Interface, avatar, client entity, server entity, or assignment client. + * @function Script.getTypeAsString + * @returns {string} The type of script that is running: + *
    + *
  • "client": An Interface script.
  • + *
  • "entity_client": A client entity script.
  • + *
  • "avatar": An avatar script.
  • + *
  • "entity_server": A server entity script.
  • + *
  • "agent": An assignment client script.
  • + *
+ */ + Q_INVOKABLE QString getTypeAsString() const { return _manager->getTypeAsString(); } + + /*@jsdoc + * Gets the filename of the script file. + * @function Script.getAbsoluteFilename + * @returns {string} The filename of the script file. + */ + Q_INVOKABLE QString getAbsoluteFilename() const { return _manager->getAbsoluteFilename(); } /*@jsdoc * Checks whether the script is running as an Interface or avatar script. diff --git a/libraries/script-engine/src/v8/ScriptEngineDebugFlags.h b/libraries/script-engine/src/v8/ScriptEngineDebugFlags.h new file mode 100644 index 0000000000..bdecb3f6a2 --- /dev/null +++ b/libraries/script-engine/src/v8/ScriptEngineDebugFlags.h @@ -0,0 +1,18 @@ +// +// ScriptEngineDebugFlags.h +// libraries/script-engine/src/v8/ScriptEngineDebugFlags.h +// +// Created by dr Karol Suprynowicz on 2024/11/14. +// Copyright 2024 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef overte_ScriptEngineDebugFlags_h +#define overte_ScriptEngineDebugFlags_h + +#define OVERTE_SCRIPT_USE_AFTER_DELETE_GUARD + +#endif diff --git a/libraries/script-engine/src/v8/ScriptEngineV8.cpp b/libraries/script-engine/src/v8/ScriptEngineV8.cpp index 5a9dead93f..5e233d3a90 100644 --- a/libraries/script-engine/src/v8/ScriptEngineV8.cpp +++ b/libraries/script-engine/src/v8/ScriptEngineV8.cpp @@ -258,6 +258,13 @@ ScriptEngineV8::ScriptEngineV8(ScriptManager *manager) : ScriptEngine(manager), } ScriptEngineV8::~ScriptEngineV8() { + // Process remaining events to avoid problems with `deleteLater` calling destructor of script proxies after script engine has been deleted: + { + QEventLoop loop; + loop.processEvents(); + } + // This is necessary for script engines that don't run in ScriptManager::run(), for example entity scripts: + disconnectSignalProxies(); deleteUnusedValueWrappers(); #ifdef OVERTE_SCRIPT_USE_AFTER_DELETE_GUARD _wasDestroyed = true; @@ -272,14 +279,14 @@ void ScriptEngineV8::perManagerLoopIterationCleanup() { void ScriptEngineV8::disconnectSignalProxies() { _signalProxySetLock.lockForRead(); while (!_signalProxySet.empty()) { + auto proxy = *_signalProxySet.begin(); _signalProxySetLock.unlock(); - delete *_signalProxySet.begin(); + delete proxy; _signalProxySetLock.lockForRead(); } _signalProxySetLock.unlock(); } - void ScriptEngineV8::deleteUnusedValueWrappers() { while (!_scriptValueWrappersToDelete.empty()) { auto wrapper = _scriptValueWrappersToDelete.dequeue(); diff --git a/libraries/script-engine/src/v8/ScriptEngineV8.h b/libraries/script-engine/src/v8/ScriptEngineV8.h index 02352c9ed7..dd2edca41b 100644 --- a/libraries/script-engine/src/v8/ScriptEngineV8.h +++ b/libraries/script-engine/src/v8/ScriptEngineV8.h @@ -35,6 +35,7 @@ #include "libplatform/libplatform.h" #include "v8.h" +#include "ScriptEngineDebugFlags.h" #include "../ScriptEngine.h" #include "../ScriptManager.h" #include "../ScriptException.h" @@ -58,8 +59,6 @@ using ScriptContextV8Pointer = std::shared_ptr; const double GARBAGE_COLLECTION_TIME_LIMIT_S = 1.0; -#define OVERTE_SCRIPT_USE_AFTER_DELETE_GUARD - Q_DECLARE_METATYPE(ScriptEngine::FunctionSignature) /// [V8] Implements ScriptEngine for V8 and translates calls for QScriptEngine diff --git a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp index 7c3fd07e9b..eeae1e2e94 100644 --- a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp +++ b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp @@ -1217,7 +1217,9 @@ ScriptSignalV8Proxy::~ScriptSignalV8Proxy() { _objectLifetime.Reset(); _v8Context.Reset(); #ifdef OVERTE_SCRIPT_USE_AFTER_DELETE_GUARD + Q_ASSERT(!_wasDeleted); Q_ASSERT(!_engine->_wasDestroyed); + _wasDeleted = true; #endif _engine->_signalProxySetLock.lockForWrite(); _engine->_signalProxySet.remove(this); diff --git a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.h b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.h index 9e3445ca98..14b8f1900e 100644 --- a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.h +++ b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.h @@ -23,6 +23,7 @@ #include #include +#include "ScriptEngineDebugFlags.h" #include "../ScriptEngine.h" #include "../Scriptable.h" #include "ScriptEngineV8.h" @@ -295,6 +296,9 @@ private: // storage // Call counter for debugging purposes. It can be used to determine which signals are overwhelming script engine. int _callCounter{0}; float _totalCallTime_s{ 0.0 }; +#ifdef OVERTE_SCRIPT_USE_AFTER_DELETE_GUARD + std::atomic _wasDeleted{false}; +#endif Q_DISABLE_COPY(ScriptSignalV8Proxy) }; diff --git a/scripts/communityScripts/armored-chat/armored_chat.js b/scripts/communityScripts/armored-chat/armored_chat.js index fe66da7a54..779dc3ff54 100644 --- a/scripts/communityScripts/armored-chat/armored_chat.js +++ b/scripts/communityScripts/armored-chat/armored_chat.js @@ -14,6 +14,7 @@ var settings = { external_window: false, maximum_messages: 200, + join_notification: true }; // Global vars @@ -97,24 +98,31 @@ if (channel !== "chat") return; message = JSON.parse(message); + // Get the message data + const currentTimestamp = _getTimestamp(); + const timeArray = _formatTimestamp(currentTimestamp); + if (!message.channel) message.channel = "domain"; // We don't know where to put this message. Assume it is a domain wide message. if (message.forApp) return; // Floofchat // Floofchat compatibility hook message = floofChatCompatibilityConversion(message); - message.channel = message.channel.toLowerCase(); // Make sure the "local", "domain", etc. is formatted consistently + message.channel = message.channel.toLowerCase(); - if (!channels.includes(message.channel)) return; // Check the channel - if ( - message.channel == "local" && - Vec3.distance(MyAvatar.position, message.position) > - maxLocalDistance - ) - return; // If message is local, and if player is too far away from location, don't do anything + // Check the channel. If the channel is not one we have, do nothing. + if (!channels.includes(message.channel)) return; + + // If message is local, and if player is too far away from location, do nothing. + if (message.channel == "local" && isTooFar(message.position)) return; + + // Format the timestamp + message.timeString = timeArray[0]; + message.dateString = timeArray[1]; // Update qml view of to new message _emitEvent({ type: "show_message", ...message }); + // Show new message on screen Messages.sendLocalMessage( "Floof-Notif", JSON.stringify({ @@ -125,20 +133,25 @@ // Save message to history let savedMessage = message; + + // Remove unnecessary data. delete savedMessage.position; - savedMessage.timeString = new Date().toLocaleTimeString(undefined, { - hour12: false, - }); - savedMessage.dateString = new Date().toLocaleDateString(undefined, { - year: "numeric", - month: "long", - day: "numeric", - }); + delete savedMessage.timeString; + delete savedMessage.dateString; + delete savedMessage.action; + + savedMessage.timestamp = currentTimestamp; + messageHistory.push(savedMessage); while (messageHistory.length > settings.maximum_messages) { messageHistory.shift(); } Settings.setValue("ArmoredChat-Messages", messageHistory); + + // Check to see if the message is close enough to the user + function isTooFar(messagePosition) { + return Vec3.distance(MyAvatar.position, messagePosition) > maxLocalDistance; + } } function fromQML(event) { switch (event.type) { @@ -146,25 +159,25 @@ _sendMessage(event.message, event.channel); break; case "setting_change": + // Set the setting value, and save the config settings[event.setting] = event.value; // Update local settings _saveSettings(); // Save local settings + // Extra actions to preform. switch (event.setting) { case "external_window": chatOverlayWindow.presentationMode = event.value ? Desktop.PresentationMode.NATIVE : Desktop.PresentationMode.VIRTUAL; break; - case "maximum_messages": - // Do nothing - break; } break; case "action": switch (event.action) { case "erase_history": - Settings.setValue("ArmoredChat-Messages", []); + Settings.setValue("ArmoredChat-Messages", null); + messageHistory = []; _emitEvent({ type: "clear_messages", }); @@ -213,9 +226,7 @@ // Get the display name of the user let displayName = ""; - displayName = - AvatarManager.getPalData([sessionId])?.data[0] - ?.sessionDisplayName || null; + displayName = AvatarManager.getPalData([sessionId])?.data[0]?.sessionDisplayName || null; if (displayName == null) { for (let i = 0; i < palData.length; i++) { if (palData[i].sessionUUID == sessionId) { @@ -226,8 +237,22 @@ // Format the packet let message = {}; + const timeArray = _formatTimestamp(_getTimestamp()); + message.timeString = timeArray[0]; + message.dateString = timeArray[1]; message.message = `${displayName} ${type}`; + // Show new message on screen + if (settings.join_notification){ + Messages.sendLocalMessage( + "Floof-Notif", + JSON.stringify({ + sender: displayName, + text: type, + }) + ); + } + _emitEvent({ type: "notification", ...message }); }, 1500); } @@ -237,7 +262,9 @@ if (messageHistory) { // Load message history messageHistory.forEach((message) => { - delete message.action; + const timeArray = _formatTimestamp(_getTimestamp()); + message.timeString = timeArray[0]; + message.dateString = timeArray[1]; _emitEvent({ type: "show_message", ...message }); }); } @@ -249,6 +276,24 @@ console.log("Saving config"); Settings.setValue("ArmoredChat-Config", settings); } + function _getTimestamp(){ + return Date.now(); + } + function _formatTimestamp(timestamp){ + let timeArray = []; + + timeArray.push(new Date().toLocaleTimeString(undefined, { + hour12: false, + })); + + timeArray.push(new Date(timestamp).toLocaleDateString(undefined, { + year: "numeric", + month: "long", + day: "numeric", + })); + + return timeArray; + } /** * Emit a packet to the HTML front end. Easy communication! diff --git a/scripts/communityScripts/armored-chat/armored_chat.qml b/scripts/communityScripts/armored-chat/armored_chat.qml index d1e46f57a6..07eb75c626 100644 --- a/scripts/communityScripts/armored-chat/armored_chat.qml +++ b/scripts/communityScripts/armored-chat/armored_chat.qml @@ -1,5 +1,5 @@ import QtQuick 2.7 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.15 import QtQuick.Layouts 1.3 import controlsUit 1.0 as HifiControlsUit @@ -30,7 +30,7 @@ Rectangle { running: false repeat: false onTriggered: { - scrollToBottom(); + scrollToBottom(true); } } @@ -145,49 +145,60 @@ Rectangle { anchors.top: navigation_bar.bottom visible: ["local", "domain"].includes(pageVal) ? true : false - // Chat Message History - ListView { + Flickable { width: parent.width height: parent.height - 40 + contentWidth: parent.width + contentHeight: listview.height clip: true - interactive: true - spacing: 5 - id: listview + id: messageViewFlickable - delegate: Loader { - property int delegateIndex: index - property string delegateText: model.text - property string delegateUsername: model.username - property string delegateDate: model.date - width: listview.width + ColumnLayout { + id: listview + Layout.fillWidth: true - sourceComponent: { - if (model.type === "chat") { - return template_chat_message; - } else if (model.type === "notification") { - return template_notification; + Repeater { + model: getChannel(pageVal) + delegate: Loader { + property int delegateIndex: model.index + property string delegateText: model.text + property string delegateUsername: model.username + property string delegateDate: model.date + + sourceComponent: { + if (model.type === "chat") { + return template_chat_message; + } else if (model.type === "notification") { + return template_notification; + } + } + } } } - ScrollBar.vertical: ScrollBar { - id: chat_scrollbar - height: 100 - size: 0.05 + ScrollBar.vertical: ScrollBar { + size: 100 + minimumSize: 0.1 } - model: getChannel(pageVal) - + rebound: Transition { + NumberAnimation { + properties: "x,y" + duration: 1 + } + } } + ListModel { id: local } ListModel { id: domain - } + } // Chat Entry Rectangle { @@ -205,6 +216,8 @@ Rectangle { height: parent.height placeholderText: pageVal.charAt(0).toUpperCase() + pageVal.slice(1) + " chat message..." clip: false + font.italic: text == "" + Keys.onPressed: { if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && !(event.modifiers & Qt.ShiftModifier)) { event.accepted = true; @@ -335,6 +348,31 @@ Rectangle { } } } + + + // Join notification + Rectangle { + width: parent.width + height: 40 + color: "transparent" + + Text{ + text: "Join notification" + color: "white" + font.pointSize: 12 + anchors.verticalCenter: parent.verticalCenter + } + + CheckBox{ + id: s_join_notification + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + onCheckedChanged: { + toScript({type: 'setting_change', setting: 'join_notification', value: checked}) + } + } + } } } @@ -344,7 +382,7 @@ Rectangle { Component { id: template_chat_message - Rectangle{ + Rectangle { property int index: delegateIndex property string texttest: delegateText property string username: delegateUsername @@ -352,6 +390,8 @@ Rectangle { height: Math.max(65, children[1].height + 30) color: index % 2 === 0 ? "transparent" : Qt.rgba(0.15,0.15,0.15,1) + width: listview.parent.parent.width + Layout.fillWidth: true Item { width: parent.width - 10 @@ -370,7 +410,7 @@ Rectangle { } } - TextEdit{ + TextEdit { anchors.top: parent.children[0].bottom x: 5 text: texttest @@ -451,16 +491,25 @@ Rectangle { } - - property var channels: { "local": local, "domain": domain, } - function scrollToBottom() { - if (listview.count == 0) return; - listview.positionViewAtEnd(); + function scrollToBottom(bypassDistanceCheck = false, extraMoveDistance = 0) { + const totalHeight = listview.height; // Total height of the content + const currentPosition = messageViewFlickable.contentY; // Current position of the view + const windowHeight = listview.parent.parent.height; // Total height of the window + const bottomPosition = currentPosition + windowHeight; + + // Check if the view is within 300 units from the bottom + const closeEnoughToBottom = totalHeight - bottomPosition <= 300; + if (!bypassDistanceCheck && !closeEnoughToBottom) return; + if (totalHeight < windowHeight) return; // No reason to scroll, we don't have an overflow. + if (bottomPosition == totalHeight) return; // At the bottom, do nothing. + + messageViewFlickable.contentY = listview.height - listview.parent.parent.height; + messageViewFlickable.returnToBounds(); } @@ -469,13 +518,13 @@ Rectangle { // Format content message = formatContent(message); - message = embedImages(message); if (type === "notification"){ channel.append({ text: message, date: date, type: "notification" }); last_message_user = ""; - scrollToBottom(); + scrollToBottom(null, 30); + last_message_time = new Date(); return; } @@ -487,22 +536,18 @@ Rectangle { var last_item_index = channel.count - 1; var last_item = channel.get(last_item_index); - // FIXME: When adding a new message this would check to see if we could append the incoming message - // to the bottom of the last message. This current implimentation causes issues with scrollToBottom() - // Specifically, scrolling to the bottom does not like image embeds. - // This needs to be reworked entirely before it can be reimplimented - // if (last_message_user === username && elapsed_minutes < 1 && last_item){ - // message = "
" + message - // last_item.text = last_item.text += "\n" + message; - // scrollToBottom() - // last_message_time = new Date(); - // return; - // } + if (last_message_user === username && elapsed_minutes < 1 && last_item){ + message = "
" + message + last_item.text = last_item.text += "\n" + message; + load_scroll_timer.running = true; + last_message_time = new Date(); + return; + } last_message_user = username; last_message_time = new Date(); channel.append({ text: message, username: username, date: date, type: type }); - scrollToBottom(); + load_scroll_timer.running = true; } function getChannel(id) { @@ -542,15 +587,13 @@ Rectangle { // Messages from script function fromScript(message) { - let time = new Date().toLocaleTimeString(undefined, { hour12: false }); - let date = new Date().toLocaleDateString(undefined, { year: "numeric", month: "long", day: "numeric", }); switch (message.type){ case "show_message": - addMessage(message.displayName, message.message, `[ ${message.timeString || time} - ${message.dateString || date} ]`, message.channel, "chat"); + addMessage(message.displayName, message.message, `[ ${message.timeString} - ${message.dateString} ]`, message.channel, "chat"); break; case "notification": - addMessage("SYSTEM", message.message, `[ ${time} - ${date} ]`, "domain", "notification"); + addMessage("SYSTEM", message.message, `[ ${message.timeString} - ${message.dateString} ]`, "domain", "notification"); break; case "clear_messages": local.clear(); @@ -559,6 +602,7 @@ Rectangle { case "initial_settings": if (message.settings.external_window) s_external_window.checked = true; if (message.settings.maximum_messages) s_maximum_messages.value = message.settings.maximum_messages; + if (message.settings.join_notification) s_join_notification.checked = true; break; } } diff --git a/scripts/communityScripts/armored-chat/armored_chat_quick_message.qml b/scripts/communityScripts/armored-chat/armored_chat_quick_message.qml index ae110db379..b14fd0a811 100644 --- a/scripts/communityScripts/armored-chat/armored_chat_quick_message.qml +++ b/scripts/communityScripts/armored-chat/armored_chat_quick_message.qml @@ -1,7 +1,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 -Rectangle { +Item { id: root property var window @@ -21,15 +21,22 @@ Rectangle { z: 99 visible: false - TextArea { - id: textArea - x: 0 + Rectangle { width: parent.width height: parent.height - text:"" - textColor: "#ffffff" + color: Qt.rgba(0.95,0.95,0.95,1) + } + + TextInput { + id: textArea + x: 5 + width: parent.width + height: parent.height + text: "" + color: "#000" clip: false font.pointSize: 18 + verticalAlignment: Text.AlignVCenter Keys.onReturnPressed: { _onEnterPressed(); } Keys.onEnterPressed: { _onEnterPressed(); } @@ -52,33 +59,36 @@ Rectangle { text: "Local message..." font.pointSize: 16 color: "gray" - x: 0 + x: 5 width: parent.width anchors.verticalCenter: parent.verticalCenter visible: textArea.text == "" + font.italic: true } - Button { + Rectangle { id: button x: parent.width - width y: 0 width: 64 height: parent.height clip: false - visible: true - + color: "#262626" + Image { id: image width: 30 height: 30 fillMode: Image.PreserveAspectFit - visible: true anchors.centerIn: parent source: "./img/ui/send_white.png" } - onClicked: { - _onEnterPressed(); + MouseArea { + anchors.fill: parent + onClicked: { + _onEnterPressed(); + } } } diff --git a/scripts/communityScripts/notificationCore/notificationCore.js b/scripts/communityScripts/notificationCore/notificationCore.js index f7ab6e73cd..a085e3b15b 100644 --- a/scripts/communityScripts/notificationCore/notificationCore.js +++ b/scripts/communityScripts/notificationCore/notificationCore.js @@ -22,7 +22,12 @@ var DEFAULT_OFFSET = 10; var FLOOF_NOTIFICATION_CHANNEL = "Floof-Notif"; var MAIN_CHAT_APP_CHANNEL = "Chat"; var ARROW_REGEX = /\   ") color: "#ffffff" font.pixelSize: 12 } + Button { + id: pasteBtn + text: "Paste" + font.pixelSize: 11 + height: 16 + width: 40 + radius: 4 + anchors.top: text1.top + anchors.left: text1.right + anchors.bottom: text1.bottom + onClicked: { + soundURL.paste() + } + } + TextInput { id: soundURL height: 20 text: qsTr("") color: "white" - anchors.top: text1.bottom + anchors.top: pasteBtn.bottom anchors.topMargin: 5 anchors.left: parent.left anchors.leftMargin: 0 diff --git a/scripts/system/graphicsSettings.js b/scripts/system/graphicsSettings.js index df556a91b1..748eafca24 100644 --- a/scripts/system/graphicsSettings.js +++ b/scripts/system/graphicsSettings.js @@ -1,15 +1,20 @@ // // graphicsSettings.js // -// Created by Kalila L. on 8/5/2020 +// Created by Kalila L. on August 5th, 2020 // Copyright 2020 Vircadia contributors. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // (function() { // BEGIN LOCAL_SCOPE - + var channelComm = "Overte-ShowGraphicsIconChanged"; + var appStatus = false; + var GRAPHICS_HIDE_AND_SHOW_SETTING_KEY = "showGraphicsIcon"; + var GRAPHICS_HIDE_AND_SHOW_DEFAULT_VALUE = true; + var AppUi = Script.require('appUi'); // cellphone-cog MDI @@ -49,22 +54,49 @@ } function startup() { - ui = new AppUi({ - buttonName: BUTTON_NAME, - sortOrder: 8, - normalButton: getIcon(), - activeButton: getIcon().replace('white', 'black'), - home: GRAPHICS_QML_SOURCE - }); + if (!appStatus) { + ui = new AppUi({ + buttonName: BUTTON_NAME, + sortOrder: 8, + normalButton: getIcon(), + activeButton: getIcon().replace('white', 'black'), + home: GRAPHICS_QML_SOURCE + }); + } + appStatus = true; } function shutdown() { + if (appStatus) { + ui.onScriptEnding(); + appStatus = false; + } + } + + function cleanup() { + Messages.messageReceived.disconnect(onMessageReceived); + Messages.unsubscribe(channelComm); + } + + function onMessageReceived(channel, message, sender, localOnly) { + if (channel === channelComm && localOnly) { + if (Settings.getValue(GRAPHICS_HIDE_AND_SHOW_SETTING_KEY, GRAPHICS_HIDE_AND_SHOW_DEFAULT_VALUE)) { + startup(); + } else { + shutdown(); + } + } } // // Run the functions. // - startup(); - Script.scriptEnding.connect(shutdown); + if (Settings.getValue(GRAPHICS_HIDE_AND_SHOW_SETTING_KEY, GRAPHICS_HIDE_AND_SHOW_DEFAULT_VALUE)) { + startup(); + } + Messages.subscribe(channelComm); + Messages.messageReceived.connect(onMessageReceived); + + Script.scriptEnding.connect(cleanup); }()); // END LOCAL_SCOPE diff --git a/server-console/src/main.js b/server-console/src/main.js index 496ee099dc..3f5783e21f 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -56,7 +56,7 @@ const menuNotificationIcon = path.join(__dirname, '../resources/tray-menu-notifi const DELETE_LOG_FILES_OLDER_THAN_X_SECONDS = 60 * 60 * 24 * 7; // 7 Days const LOG_FILE_REGEX = /(domain-server|ac-monitor|ac)-.*-std(out|err).txt/; -const HOME_CONTENT_URL = "http://cdn-1.vircadia.com/us-e-1/DomainContent/Sandbox/Rearranged_Basic_Sandbox.tar.gz"; +const HOME_CONTENT_URL = "https://content.overte.org/DomainContent/Sandbox/Rearranged_Basic_Sandbox.tar.gz"; const buildInfo = GetBuildInfo(); diff --git a/tools/ci-scripts/linux-ci/Dockerfile_build_ubuntu-20.04 b/tools/ci-scripts/linux-ci/Dockerfile_build_ubuntu-20.04 index 12a56ced03..eb26d1b426 100644 --- a/tools/ci-scripts/linux-ci/Dockerfile_build_ubuntu-20.04 +++ b/tools/ci-scripts/linux-ci/Dockerfile_build_ubuntu-20.04 @@ -1,8 +1,8 @@ -# Copyright 2022-2023 Overte e.V. +# Copyright 2022-2024 Overte e.V. # SPDX-License-Identifier: Apache-2.0 # Docker file for building Overte -# Example build: docker build -t overte/overte-full-build:0.1.1-ubuntu-20.04 -f Dockerfile_build_ubuntu-20.04 . +# Example build: docker build -t overte/overte-full-build:0.1.2-ubuntu-20.04 -f Dockerfile_build_ubuntu-20.04 . FROM ubuntu:20.04 LABEL maintainer="Julian Groß (julian.gro@overte.org)" LABEL description="Development image for full Overte builds" @@ -18,6 +18,8 @@ RUN apt-get update && apt-get -y install tzdata RUN apt-get -y install curl ninja-build git cmake g++ libssl-dev python3-distutils python3-distro mesa-common-dev libgl1-mesa-dev libsystemd-dev # Install server-console build dependencies RUN apt-get -y install npm +# Install Interface dependencies +RUN apt-get -y install pkg-config libxext-dev libdouble-conversion-dev libpcre2-16-0 libpulse0 libharfbuzz-dev libnss3 libnspr4 libxdamage1 libasound2 vulkan-validationlayers libvulkan-dev libvulkan1 # Install tools for package creation RUN apt-get -y install sudo chrpath binutils dh-make diff --git a/tools/ci-scripts/linux-ci/Dockerfile_build_ubuntu-22.04 b/tools/ci-scripts/linux-ci/Dockerfile_build_ubuntu-22.04 index a80207471e..a4da419e87 100644 --- a/tools/ci-scripts/linux-ci/Dockerfile_build_ubuntu-22.04 +++ b/tools/ci-scripts/linux-ci/Dockerfile_build_ubuntu-22.04 @@ -1,8 +1,8 @@ -# Copyright 2022-2023 Overte e.V. +# Copyright 2022-2024 Overte e.V. # SPDX-License-Identifier: Apache-2.0 # Docker file for building Overte -# Example build: docker build -t overte/overte-full-build:0.1.1-ubuntu-22.04 -f Dockerfile_build_ubuntu-22.04 . +# Example build: docker build -t overte/overte-full-build:0.1.2-ubuntu-22.04 -f Dockerfile_build_ubuntu-22.04 . FROM ubuntu:22.04 LABEL maintainer="Julian Groß (julian.gro@overte.org)" LABEL description="Development image for full Overte builds" @@ -19,7 +19,7 @@ RUN apt-get -y install curl ninja-build git cmake g++ libssl-dev libqt5websocket # Install Overte tools build dependencies RUN apt-get -y install libqt5webchannel5-dev qtwebengine5-dev libqt5xmlpatterns5-dev # Install Overte Interface build dependencies -RUN apt-get -y install libqt5svg5-dev qttools5-dev +RUN apt-get -y install libqt5svg5-dev qttools5-dev vulkan-validationlayers libvulkan-dev libvulkan1 libqt5x11extras5-dev qtbase5-private-dev # Install server-console build dependencies RUN apt-get -y install npm diff --git a/tools/ci-scripts/rpm_package/Dockerfile_build_fedora-39 b/tools/ci-scripts/rpm_package/Dockerfile_build_fedora-39 deleted file mode 100644 index ef5ef24819..0000000000 --- a/tools/ci-scripts/rpm_package/Dockerfile_build_fedora-39 +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2022-2024 Overte e.V. -# SPDX-License-Identifier: Apache-2.0 - -# Docker file for building Overte Server -# Example build: docker build -t overte/overte-server-build:0.1.4-fedora-39 -f Dockerfile_build_fedora-39 . -FROM fedora:39 -LABEL maintainer="Julian Groß (julian.gro@overte.org)" -LABEL description="Development image for Overte Domain server and assignment clients." - -# Install Overte domain-server and assignment-client build dependencies -RUN dnf -y install curl ninja-build git cmake gcc gcc-c++ openssl-devel qt5-qtwebsockets-devel qt5-qtmultimedia-devel unzip libXext-devel qt5-qtwebchannel-devel qt5-qtwebengine-devel qt5-qtxmlpatterns-devel systemd-devel python3.11 - -# Install additional build tools -RUN dnf -y install zip unzip - -# Install tools for package creation -RUN dnf -y install chrpath rpmdevtools - -# Install tools needed for our Github Actions Workflow -Run dnf -y install python3-boto3 python3-pygithub diff --git a/tools/jsdoc/plugins/hifi.js b/tools/jsdoc/plugins/hifi.js index 7a789e39ee..595d0bc9c4 100644 --- a/tools/jsdoc/plugins/hifi.js +++ b/tools/jsdoc/plugins/hifi.js @@ -71,7 +71,7 @@ exports.handlers = { ]; // only files with this extension will be searched for jsdoc comments. - var exts = ['.h', '.cpp']; + var exts = ['.h', '.h.in', '.cpp', '.cpp.in']; var fs = require('fs'); dirList.forEach(function (dir) { @@ -123,9 +123,9 @@ exports.handlers = { // Append an Available In: sentence at the beginning of the namespace description. if (rows.length > 0) { var availableIn = "

Supported Script Types: " + rows.join(" • ") + "

"; - + e.doclet.description = availableIn + (e.doclet.description ? e.doclet.description : ""); - } + } } if (e.doclet.kind === "function" && e.doclet.returns && e.doclet.returns[0].type diff --git a/tools/qt-builder/Dockerfile_Ubuntu_20.04_Qt5 b/tools/qt-builder/Dockerfile_Ubuntu_20.04_Qt5 index 8c7e32f360..5639d662b6 100644 --- a/tools/qt-builder/Dockerfile_Ubuntu_20.04_Qt5 +++ b/tools/qt-builder/Dockerfile_Ubuntu_20.04_Qt5 @@ -4,11 +4,11 @@ # - Check which commit you are building https://invent.kde.org/qt/qt/qt5/-/tree/kde/5.15 # - Adjust this file to include the commit hash you are building, the date, the number of threads you want to use (-j10), the platform, and the Qt and QtWebEngine versions. # Keep in mind that building Qt requires a lot of memory. You should have over 1.2GiB of system memory available per thread. -# - Run the build process with something like `PROGRESS_NO_TRUNC=1 DOCKER_BUILDKIT=1 BUILDKIT_STEP_LOG_MAX_SIZE=-1 docker build --progress plain -t overte-qt5:5.15.14-2024.06.17-kde_570f5b2105df1ea052bec0d6dbf8a00137274371 -f Dockerfile_Ubuntu_20.04_Qt5 .` +# - Run the build process with something like `PROGRESS_NO_TRUNC=1 DOCKER_BUILDKIT=1 BUILDKIT_STEP_LOG_MAX_SIZE=-1 docker build --progress plain -t overte-qt5:5.15.16-2024.12.14-kde_32be154325bfba3ad2ba8bf75dad702f3588e8d3 -f Dockerfile_Ubuntu_20.04_Qt5 .` # Buildkit is used to cache intermittent steps in case you need to modify something afterwards. # - Once the build has completed, create a container from the image and export the created Qt package. -# `docker create --name extract overte-qt5:5.15.14-2024.06.17-kde_570f5b2105df1ea052bec0d6dbf8a00137274371` -# `docker cp extract:qt5-install-5.15.14-2024.06.17-kde_570f5b2105df1ea052bec0d6dbf8a00137274371-ubuntu-20.04-amd64.tar.xz /path/on/host` +# `docker create --name extract overte-qt5:5.15.16-2024.12.14-kde_32be154325bfba3ad2ba8bf75dad702f3588e8d3` +# `docker cp extract:qt5-install-5.15.16-2024.12.14-kde_32be154325bfba3ad2ba8bf75dad702f3588e8d3-ubuntu-20.04-amd64.tar.xz /path/on/host` # `docker rm extract` FROM ubuntu:20.04 @@ -47,7 +47,7 @@ RUN apt-get -y install git python gperf flex bison pkg-config mesa-utils libgl1- RUN mkdir qt5-install && mkdir qt5-build WORKDIR qt5-build -RUN ../qt5/configure -force-debug-info -release -opensource -confirm-license -platform linux-g++ -recheck-all -nomake tests -nomake examples -skip qttranslations -skip qtserialport -skip qt3d -skip qtlocation -skip qtwayland -skip qtsensors -skip qtgamepad -skip qtcharts -skip qtx11extras -skip qtmacextras -skip qtvirtualkeyboard -skip qtpurchasing -skip qtdatavis3d -skip qtlottie -skip qtquick3d -skip qtpim -skip qtdocgallery -no-warnings-are-errors -no-pch -no-icu -prefix ../qt5-install +RUN ../qt5/configure -force-debug-info -release -opensource -confirm-license -platform linux-g++ -recheck-all -nomake tests -nomake examples -skip qttranslations -skip qtserialport -skip qt3d -skip qtlocation -skip qtwayland -skip qtsensors -skip qtgamepad -skip qtcharts -skip qtmacextras -skip qtvirtualkeyboard -skip qtpurchasing -skip qtdatavis3d -skip qtlottie -skip qtquick3d -skip qtpim -skip qtdocgallery -no-warnings-are-errors -no-pch -no-icu -prefix ../qt5-install RUN NINJAFLAGS='-j6' make -j6 @@ -58,12 +58,12 @@ WORKDIR ../../qt5-install RUN find . -name \*.prl -exec sed -i -e '/^QMAKE_PRL_BUILD_DIR/d' {} \; # Overwrite QtWebengine version to work around version conflicts -RUN find . -name \Qt5WebEngine*Config.cmake -exec sed -i '' -e 's/5\.15\.17/5\.15\.14/g' {} \; -RUN cp lib/libQt5WebEngine.so.5.15.17 lib/libQt5WebEngine.so.5.15.14 -RUN cp lib/libQt5WebEngineCore.so.5.15.17 lib/libQt5WebEngineCore.so.5.15.14 -RUN cp lib/libQt5WebEngineWidgets.so.5.15.17 lib/libQt5WebEngineWidgets.so.5.15.14 -RUN cp lib/libQt5Pdf.so.5.15.17 lib/libQt5Pdf.so.5.15.14 -RUN cp lib/libQt5PdfWidgets.so.5.15.17 lib/libQt5PdfWidgets.so.5.15.14 +RUN find . -name \Qt5WebEngine*Config.cmake -exec sed -i '' -e 's/5\.15\.19/5\.15\.16/g' {} \; +RUN cp lib/libQt5WebEngine.so.5.15.19 lib/libQt5WebEngine.so.5.15.16 +RUN cp lib/libQt5WebEngineCore.so.5.15.19 lib/libQt5WebEngineCore.so.5.15.16 +RUN cp lib/libQt5WebEngineWidgets.so.5.15.19 lib/libQt5WebEngineWidgets.so.5.15.16 +RUN cp lib/libQt5Pdf.so.5.15.19 lib/libQt5Pdf.so.5.15.16 +RUN cp lib/libQt5PdfWidgets.so.5.15.19 lib/libQt5PdfWidgets.so.5.15.16 COPY ./qt.conf ./bin/ @@ -71,4 +71,4 @@ COPY ./qt.conf ./bin/ RUN cp ../qt5-build/config.summary ./ WORKDIR .. -RUN XZ_OPT='-T0' tar -Jcvf qt5-install-5.15.14-2024.06.17-kde_570f5b2105df1ea052bec0d6dbf8a00137274371-ubuntu-20.04-amd64.tar.xz qt5-install +RUN XZ_OPT='-T0' tar -Jcvf qt5-install-5.15.16-2024.12.14-kde_32be154325bfba3ad2ba8bf75dad702f3588e8d3-ubuntu-20.04-amd64.tar.xz qt5-install