Merge branch 'release/materials_featurette' of https://github.com/secondlife/viewer

# Conflicts:
#	indra/fix-incredibuild.py
#	indra/newview/CMakeLists.txt
#	indra/newview/llagentbenefits.cpp
#	indra/newview/llgltfmateriallist.cpp
#	indra/newview/llspatialpartition.cpp
#	indra/newview/llviewermenu.cpp
#	indra/newview/llviewerregion.cpp
#	indra/newview/llvocache.cpp
#	indra/newview/llvocache.h
#	indra/newview/llvovolume.cpp
#	indra/newview/pipeline.cpp
#	indra/newview/skins/default/xui/en/notifications.xml
#	indra/newview/viewer_manifest.py
master
Ansariel 2024-04-17 10:57:12 +02:00
commit 3b902c9f36
52 changed files with 2756 additions and 777 deletions

View File

@ -12,14 +12,10 @@ jobs:
strategy:
matrix:
runner: [windows-large, macos-12-xl]
configuration: [Release, ReleaseOS]
python-version: ["3.11"]
configuration: [Release]
include:
- runner: macos-12-xl
developer_dir: "/Applications/Xcode_14.0.1.app/Contents/Developer"
exclude:
- runner: macos-12-xl
configuration: ReleaseOS
runs-on: ${{ matrix.runner }}
outputs:
viewer_channel: ${{ steps.build.outputs.viewer_channel }}
@ -67,7 +63,7 @@ jobs:
- name: Setup python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
python-version: "3.11"
- name: Checkout build variables
uses: actions/checkout@v4
@ -101,7 +97,7 @@ jobs:
- name: Determine source branch
id: which-branch
uses: secondlife/viewer-build-util/which-branch@v1
uses: secondlife/viewer-build-util/which-branch@v2
with:
token: ${{ github.token }}
@ -271,7 +267,7 @@ jobs:
steps:
- name: Sign and package Windows viewer
if: env.AZURE_KEY_VAULT_URI && env.AZURE_CERT_NAME && env.AZURE_CLIENT_ID && env.AZURE_CLIENT_SECRET && env.AZURE_TENANT_ID
uses: secondlife/viewer-build-util/sign-pkg-windows@v1
uses: secondlife/viewer-build-util/sign-pkg-windows@v2
with:
vault_uri: "${{ env.AZURE_KEY_VAULT_URI }}"
cert_name: "${{ env.AZURE_CERT_NAME }}"
@ -310,7 +306,7 @@ jobs:
- name: Sign and package Mac viewer
if: env.SIGNING_CERT_MACOS && env.SIGNING_CERT_MACOS_IDENTITY && env.SIGNING_CERT_MACOS_PASSWORD && steps.note-creds.outputs.note_user && steps.note-creds.outputs.note_pass && steps.note-creds.outputs.note_team
uses: secondlife/viewer-build-util/sign-pkg-mac@v1
uses: secondlife/viewer-build-util/sign-pkg-mac@v2
with:
channel: ${{ needs.build.outputs.viewer_channel }}
imagename: ${{ needs.build.outputs.imagename }}
@ -330,7 +326,7 @@ jobs:
steps:
- name: Post Windows symbols
if: env.BUGSPLAT_USER && env.BUGSPLAT_PASS
uses: secondlife/viewer-build-util/post-bugsplat-windows@v1
uses: secondlife/viewer-build-util/post-bugsplat-windows@v2
with:
username: ${{ env.BUGSPLAT_USER }}
password: ${{ env.BUGSPLAT_PASS }}
@ -347,7 +343,7 @@ jobs:
steps:
- name: Post Mac symbols
if: env.BUGSPLAT_USER && env.BUGSPLAT_PASS
uses: secondlife/viewer-build-util/post-bugsplat-mac@v1
uses: secondlife/viewer-build-util/post-bugsplat-mac@v2
with:
username: ${{ env.BUGSPLAT_USER }}
password: ${{ env.BUGSPLAT_PASS }}
@ -360,31 +356,20 @@ jobs:
runs-on: ubuntu-latest
if: github.ref_type == 'tag' && startsWith(github.ref_name, 'Second_Life_')
steps:
- uses: actions/download-artifact@v3
- uses: actions/download-artifact@v4
with:
name: Windows-installer
pattern: "*-installer"
- uses: actions/download-artifact@v3
- uses: actions/download-artifact@v4
with:
name: macOS-installer
- uses: actions/download-artifact@v3
with:
name: Windows-metadata
- name: Rename windows metadata
pattern: "*-metadata"
- name: Rename metadata
run: |
mv autobuild-package.xml Windows-autobuild-package.xml
mv newview/viewer_version.txt Windows-viewer_version.txt
- uses: actions/download-artifact@v3
with:
name: macOS-metadata
- name: Rename macOS metadata
run: |
mv autobuild-package.xml macOS-autobuild-package.xml
mv newview/viewer_version.txt macOS-viewer_version.txt
cp Windows-metadata/autobuild-package.xml Windows-autobuild-package.xml
cp Windows-metadata/newview/viewer_version.txt Windows-viewer_version.txt
cp macOS-metadata/autobuild-package.xml macOS-autobuild-package.xml
cp macOS-metadata/newview/viewer_version.txt macOS-viewer_version.txt
# forked from softprops/action-gh-release
- name: Create GitHub release
@ -407,8 +392,8 @@ jobs:
append_body: true
fail_on_unmatched_files: true
files: |
*.dmg
*.exe
macOS-installer/*.dmg
Windows-installer/*.exe
*-autobuild-package.xml
*-viewer_version.txt

View File

@ -19,7 +19,7 @@ jobs:
PERSONAL_ACCESS_TOKEN: ${{ secrets.SHARED_CLA_TOKEN }}
with:
branch: main
path-to-document: https://github.com/secondlife/cla/blob/master/CLA.md
path-to-document: https://github.com/secondlife/cla/blob/main/CLA.md
path-to-signatures: signatures.json
remote-organization-name: secondlife
remote-repository-name: cla-signatures

View File

@ -1,73 +0,0 @@
# BuildParams
#
# Please refer to:
# https://wiki.secondlife.com/wiki/Automated_Build_System
# Variants (NOTE: 'Release' must be last for uploads to work correctly)
variants = "RelWithDebInfo Release"
# Use Public Upload Locations
public_build = true
build_docs = true
# enable Doxygen building on Linux for TeamCity (it can be done manually on any platform)
build_Linux_Doxygen = true
# Need viewer-build-variables as well as other shared repositories
buildscripts_shared_more_NAMEs="build_secrets build_variables git_hooks"
# Python 3 / SL-15742
BUILDSCRIPTS_PY3 = "true"
################################################################
#### Examples of how to set the viewer_channel ####
#
# To build a Release or Release candidate in build bingo:
# bingo.viewer_channel = "Second Life Release"
#
# To build a Beta for the 'Bingo' project in build bingo:
# bingo.viewer_channel = "Second Life Beta Bingo"
#
# To build a Project viewer for the 'Bingo' project in build bingo:
# bingo.viewer_channel = "Second Life Project Bingo"
#
# If left unset, viewer_channel defaults to 'Second Life Test',
# which is appropriate for individual developer builds.
#
# All Linden Lab builds (and only Linden Lab builds)
# should use a viewer_channel that begins with "Second Life"
################################################################
viewer_channel = "Second Life Test"
################################################################
# Special packaging parameters.
# These parameters can be used to create additional packages
# which identify themselves in a distinct way with either
# a sourceid (sent to web services) or a channel name (sent to login)
# the default sourceid should always be a null string:
sourceid = ""
# the additional_packages variable is a blank separated list of package prefixes:
# additional_packages = ""
# to set the special values for a package, create variables using each prefix:
# additional_packages = "Foo Bar"
# Foo_sourceid = "bingo"
# Foo_viewer_channel_suffix = "Foo"
# Bar_sourceid = "bongo"
# Bar_viewer_channel_suffix = "Bar"
# the viewer_channel_suffix is prefixed by a blank and then appended to the viewer_channel
# for the package in a setting that overrides the compiled-in value
################################################################
additional_packages = "EDU"
Linux.additional_packages = ""
# The EDU package allows us to create a separate release channel whose expirations
# are synchronized as much as possible with the academic year
EDU_sourceid = ""
EDU_viewer_channel_suffix = "edu"
# Notifications - to configure email notices use the TeamCity parameter
# setting screen for your project or build configuration to set the
# environment variable 'email' to a space-separated list of email addresses
email=""

View File

@ -6,9 +6,6 @@
# it relies on the environment that sets up, functions it provides, and
# the build result post-processing it does.
#
# The shared buildscript build.sh invokes this because it is named 'build.sh',
# which is the default custom build script name in buildscripts/hg/BuildParams
#
# PLEASE NOTE:
#
# * This script is interpreted on three platforms, including windows and cygwin
@ -85,7 +82,7 @@ installer_Linux()
{
local package_name="$1"
local package_dir="$(build_dir_Linux)/newview/"
local pattern=".*$(viewer_channel_suffix ${package_name})_[0-9]+_[0-9]+_[0-9]+_[0-9]+_i686\\.tar\\.bz2\$"
local pattern=".*$(viewer_channel_suffix ${package_name})_[0-9]+_[0-9]+_[0-9]+_[0-9]+_i686\\.tar\\.xz\$"
# since the additional packages are built after the base package,
# sorting oldest first ensures that the unqualified package is returned
# even if someone makes a qualified name that duplicates the last word of the base name
@ -173,7 +170,7 @@ pre_build()
# This name is consumed by indra/newview/CMakeLists.txt. Make it
# absolute because we've had troubles with relative pathnames.
abs_build_dir="$(cd "$build_dir"; pwd)"
VIEWER_SYMBOL_FILE="$(native_path "$abs_build_dir/newview/$variant/secondlife-symbols-$symplat-${AUTOBUILD_ADDRSIZE}.tar.bz2")"
VIEWER_SYMBOL_FILE="$(native_path "$abs_build_dir/newview/$variant/secondlife-symbols-$symplat-${AUTOBUILD_ADDRSIZE}.tar.xz")"
fi
# honor autobuild_configure_parameters same as sling-buildscripts
@ -417,10 +414,10 @@ do
fi
if [ -d "$build_dir/doxygen/html" ]
then
tar -c -f "$build_dir/viewer-doxygen.tar.bz2" --strip-components 3 "$build_dir/doxygen/html"
python_cmd "$helpers/codeticket.py" addoutput "Doxygen Tarball" "$build_dir/viewer-doxygen.tar.bz2" \
tar -cJf "$build_dir/viewer-doxygen.tar.xz" --strip-components 3 "$build_dir/doxygen/html"
python_cmd "$helpers/codeticket.py" addoutput "Doxygen Tarball" "$build_dir/viewer-doxygen.tar.xz" \
|| fatal "Upload of doxygen tarball failed"
metadata+=("$build_dir/viewer-doxygen.tar.bz2")
metadata+=("$build_dir/viewer-doxygen.tar.xz")
fi
;;
*)

View File

@ -1,61 +0,0 @@
#!/usr/bin/env python3
##
## $LicenseInfo:firstyear=2011&license=viewerlgpl$
## Second Life Viewer Source Code
## Copyright (C) 2011, Linden Research, Inc.
##
## This library is free software; you can redistribute it and/or
## modify it under the terms of the GNU Lesser General Public
## License as published by the Free Software Foundation;
## version 2.1 of the License only.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public
## License along with this library; if not, write to the Free Software
## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
##
## Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
## $/LicenseInfo$
import sys
import os
import glob
def delete_file_types(path, filetypes):
if os.path.exists(path):
print('Cleaning: ' + path)
orig_dir = os.getcwd();
os.chdir(path)
filelist = []
for type in filetypes:
filelist.extend(glob.glob(type))
for file in filelist:
os.remove(file)
os.chdir(orig_dir)
def main():
build_types = ['*.exp','*.exe','*.pdb','*.idb',
'*.ilk','*.lib','*.obj','*.ib_pdb_index']
pch_types = ['*.pch']
delete_file_types("build-vc80/newview/Release", build_types)
delete_file_types("build-vc80/newview/firestorm-bin.dir/Release/",
pch_types)
delete_file_types("build-vc80/newview/RelWithDebInfo", build_types)
delete_file_types("build-vc80/newview/firestorm-bin.dir/RelWithDebInfo/",
pch_types)
delete_file_types("build-vc80/newview/Debug", build_types)
delete_file_types("build-vc80/newview/firestorm-bin.dir/Debug/",
pch_types)
delete_file_types("build-vc80/test/RelWithDebInfo", build_types)
delete_file_types("build-vc80/test/test.dir/RelWithDebInfo/",
pch_types)
if __name__ == "__main__":
main()

View File

@ -45,13 +45,13 @@
#include "llmatrix3a.h"
#include "lloctree.h"
#include "llvolume.h"
#include "llvolumeoctree.h"
#include "llstl.h"
#include "llsdserialize.h"
#include "llvector4a.h"
#include "llmatrix4a.h"
#include "llmeshoptimizer.h"
#include "lltimer.h"
#include "llvolumeoctree.h"
#include "mikktspace/mikktspace.h"
#include "mikktspace/mikktspace.c" // insert mikktspace implementation into llvolume object file
@ -394,77 +394,6 @@ BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, cons
}
}
class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle, LLVolumeTriangle*>
{
public:
const LLVolumeFace* mFace;
LLVolumeOctreeRebound(const LLVolumeFace* face)
{
mFace = face;
}
virtual void visit(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* branch)
{ //this is a depth first traversal, so it's safe to assum all children have complete
//bounding data
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0);
LLVector4a& min = node->mExtents[0];
LLVector4a& max = node->mExtents[1];
if (!branch->isEmpty())
{ //node has data, find AABB that binds data set
const LLVolumeTriangle* tri = *(branch->getDataBegin());
//initialize min/max to first available vertex
min = *(tri->mV[0]);
max = *(tri->mV[0]);
for (LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>::const_element_iter iter = branch->getDataBegin(); iter != branch->getDataEnd(); ++iter)
{ //for each triangle in node
//stretch by triangles in node
tri = *iter;
min.setMin(min, *tri->mV[0]);
min.setMin(min, *tri->mV[1]);
min.setMin(min, *tri->mV[2]);
max.setMax(max, *tri->mV[0]);
max.setMax(max, *tri->mV[1]);
max.setMax(max, *tri->mV[2]);
}
}
else if (branch->getChildCount() > 0)
{ //no data, but child nodes exist
LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(0)->getListener(0);
//initialize min/max to extents of first child
min = child->mExtents[0];
max = child->mExtents[1];
}
else
{
llassert(!branch->isLeaf()); // Empty leaf
}
for (S32 i = 0; i < branch->getChildCount(); ++i)
{ //stretch by child extents
LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0);
min.setMin(min, child->mExtents[0]);
max.setMax(max, child->mExtents[1]);
}
node->mBounds[0].setAdd(min, max);
node->mBounds[0].mul(0.5f);
node->mBounds[1].setSub(max,min);
node->mBounds[1].mul(0.5f);
}
};
//-------------------------------------------------------------------
// statics
//-------------------------------------------------------------------
@ -5547,7 +5476,6 @@ struct MikktData
}
};
bool LLVolumeFace::cacheOptimize(bool gen_tangents)
{ //optimize for vertex cache according to Forsyth method:
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
@ -5726,8 +5654,7 @@ void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVe
ND_OCTREE_LOG << "Creating octree with scale " << scaler << " mNumIndices " << mNumIndices << ND_OCTREE_LOG_END;
llassert(mNumIndices % 3 == 0);
mOctree = new LLOctreeRoot<LLVolumeTriangle, LLVolumeTriangle*>(center, size, NULL);
new LLVolumeOctreeListener(mOctree);
mOctree = new LLVolumeOctree(center, size);
const U32 num_triangles = mNumIndices / 3;
// Initialize all the triangles we need
mOctreeTriangles = new LLVolumeTriangle[num_triangles];
@ -5790,7 +5717,7 @@ void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVe
while (!mOctree->balance()) { }
//calculate AABB for each node
LLVolumeOctreeRebound rebound(this);
LLVolumeOctreeRebound rebound;
rebound.traverse(mOctree);
if (gDebugGL)
@ -5803,12 +5730,12 @@ void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVe
void LLVolumeFace::destroyOctree()
{
delete mOctree;
mOctree = NULL;
mOctree = nullptr;
delete[] mOctreeTriangles;
mOctreeTriangles = NULL;
mOctreeTriangles = nullptr;
}
const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* LLVolumeFace::getOctree() const
const LLVolumeOctree* LLVolumeFace::getOctree() const
{
return mOctree;
}

View File

@ -41,6 +41,7 @@ template <class T, typename T_PTR> class LLOctreeNode;
class LLVolumeFace;
class LLVolume;
class LLVolumeTriangle;
class LLVolumeOctree;
#include "lluuid.h"
#include "v4color.h"
@ -916,7 +917,7 @@ public:
void createOctree(F32 scaler = 0.25f, const LLVector4a& center = LLVector4a(0,0,0), const LLVector4a& size = LLVector4a(0.5f,0.5f,0.5f));
void destroyOctree();
// Get a reference to the octree, which may be null
const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* getOctree() const;
const LLVolumeOctree* getOctree() const;
enum
{
@ -990,7 +991,7 @@ public:
LLVector3 mNormalizedScale = LLVector3(1,1,1);
private:
LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* mOctree;
LLVolumeOctree* mOctree;
LLVolumeTriangle* mOctreeTriangles;
BOOL createUnCutCubeCap(LLVolume* volume, BOOL partial_build = FALSE);

View File

@ -92,15 +92,15 @@ void LLVolumeOctreeListener::handleChildAddition(const LLOctreeNode<LLVolumeTria
}
LLOctreeTriangleRayIntersect::LLOctreeTriangleRayIntersect(const LLVector4a& start, const LLVector4a& dir,
const LLVolumeFace* face, F32* closest_t,
LLVolumeFace* face, F32* closest_t,
LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent)
: mFace(face),
mStart(start),
: mStart(start),
mDir(dir),
mIntersection(intersection),
mTexCoord(tex_coord),
mNormal(normal),
mTangent(tangent),
mFace(face),
mClosestT(closest_t),
mHitFace(false)
{
@ -139,7 +139,7 @@ void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode<LLVolumeTriangle, LL
{
*mClosestT = t;
mHitFace = true;
mHitTriangle = tri;
if (mIntersection != NULL)
{
LLVector4a intersect = mDir;

View File

@ -112,7 +112,6 @@ public:
class LLOctreeTriangleRayIntersect : public LLOctreeTraveler<LLVolumeTriangle, LLVolumeTriangle*>
{
public:
const LLVolumeFace* mFace;
LLVector4a mStart;
LLVector4a mDir;
LLVector4a mEnd;
@ -121,10 +120,13 @@ public:
LLVector4a* mNormal;
LLVector4a* mTangent;
F32* mClosestT;
LLVolumeFace* mFace;
bool mHitFace;
const LLVolumeTriangle* mHitTriangle = nullptr;
LLOctreeTriangleRayIntersect(const LLVector4a& start, const LLVector4a& dir,
const LLVolumeFace* face, F32* closest_t,
LLOctreeTriangleRayIntersect(const LLVector4a& start, const LLVector4a& dir,
LLVolumeFace* face,
F32* closest_t,
LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent);
void traverse(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* node);
@ -137,4 +139,91 @@ class LLVolumeOctreeValidate : public LLOctreeTraveler<LLVolumeTriangle, LLVolum
virtual void visit(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* branch);
};
class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle, LLVolumeTriangle*>
{
public:
LLVolumeOctreeRebound()
{
}
virtual void visit(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* branch)
{ //this is a depth first traversal, so it's safe to assum all children have complete
//bounding data
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
LLVolumeOctreeListener* node = (LLVolumeOctreeListener*)branch->getListener(0);
LLVector4a& min = node->mExtents[0];
LLVector4a& max = node->mExtents[1];
if (!branch->isEmpty())
{ //node has data, find AABB that binds data set
const LLVolumeTriangle* tri = *(branch->getDataBegin());
//initialize min/max to first available vertex
min = *(tri->mV[0]);
max = *(tri->mV[0]);
for (LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>::const_element_iter iter = branch->getDataBegin(); iter != branch->getDataEnd(); ++iter)
{ //for each triangle in node
//stretch by triangles in node
tri = *iter;
min.setMin(min, *tri->mV[0]);
min.setMin(min, *tri->mV[1]);
min.setMin(min, *tri->mV[2]);
max.setMax(max, *tri->mV[0]);
max.setMax(max, *tri->mV[1]);
max.setMax(max, *tri->mV[2]);
}
}
else if (branch->getChildCount() > 0)
{ //no data, but child nodes exist
LLVolumeOctreeListener* child = (LLVolumeOctreeListener*)branch->getChild(0)->getListener(0);
//initialize min/max to extents of first child
min = child->mExtents[0];
max = child->mExtents[1];
}
else
{
llassert(!branch->isLeaf()); // Empty leaf
}
for (S32 i = 0; i < branch->getChildCount(); ++i)
{ //stretch by child extents
LLVolumeOctreeListener* child = (LLVolumeOctreeListener*)branch->getChild(i)->getListener(0);
min.setMin(min, child->mExtents[0]);
max.setMax(max, child->mExtents[1]);
}
node->mBounds[0].setAdd(min, max);
node->mBounds[0].mul(0.5f);
node->mBounds[1].setSub(max, min);
node->mBounds[1].mul(0.5f);
}
};
class LLVolumeOctree : public LLOctreeRoot<LLVolumeTriangle, LLVolumeTriangle*>, public LLRefCount
{
public:
LLVolumeOctree(const LLVector4a& center, const LLVector4a& size)
:
LLOctreeRoot<LLVolumeTriangle, LLVolumeTriangle*>(center, size, nullptr),
LLRefCount()
{
new LLVolumeOctreeListener(this);
}
LLVolumeOctree()
: LLOctreeRoot<LLVolumeTriangle, LLVolumeTriangle*>(LLVector4a::getZero(), LLVector4a(1.f,1.f,1.f), nullptr),
LLRefCount()
{
new LLVolumeOctreeListener(this);
}
};
#endif

View File

@ -673,7 +673,7 @@ void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVecto
U16 idx = indicesp[i];
gGL.vertex3fv(pos[idx].getF32ptr());
}
}
}
gGL.end();
gGL.flush();
}

View File

@ -168,7 +168,6 @@ set(viewer_SOURCE_FILES
fsscriptlibrary.cpp
fsscrolllistctrl.cpp
fsslurlcommand.cpp
groupchatlistener.cpp
lggbeamcolormapfloater.cpp
lggbeammapfloater.cpp
lggbeammaps.cpp
@ -186,6 +185,10 @@ set(viewer_SOURCE_FILES
vjfloaterlocalmesh.cpp
vjlocalmeshimportdae.cpp
gltfscenemanager.cpp
gltf/asset.cpp
gltf/primitive.cpp
groupchatlistener.cpp
llaccountingcostmanager.cpp
llaisapi.cpp
llagent.cpp
@ -963,8 +966,6 @@ set(viewer_HEADER_FILES
fsscrolllistctrl.h
fsslurl.h
fsslurlcommand.h
groupchatlistener.h
llaccountingcost.h
lggbeamcolormapfloater.h
lggbeammapfloater.h
lggbeammaps.h
@ -981,6 +982,11 @@ set(viewer_HEADER_FILES
vjfloaterlocalmesh.h
vjlocalmeshimportdae.h
gltfscenemanager.h
groupchatlistener.h
gltf/asset.h
gltf/primitive.h
llaccountingcost.h
llaccountingcostmanager.h
llaisapi.h
llagent.h
@ -2307,7 +2313,7 @@ if (WINDOWS)
if (PACKAGE)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.bz2
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.xz
COMMAND ${PYTHON_EXECUTABLE}
ARGS
${CMAKE_CURRENT_SOURCE_DIR}/event_host_manifest.py
@ -2352,7 +2358,7 @@ if (WINDOWS)
)
# temporarily disable packaging of event_host until hg subrepos get
# sorted out on the parabuild cluster...
#${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.bz2)
#${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.xz)
endif (PACKAGE)
elseif (DARWIN)
@ -2506,7 +2512,7 @@ if (LINUX)
add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_gstreamer10 media_plugin_cef linux-crash-logger)
add_custom_command(
OUTPUT ${product}.tar.bz2
OUTPUT ${product}.tar.xz
COMMAND ${PYTHON_EXECUTABLE}
ARGS
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
@ -2559,7 +2565,7 @@ if (LINUX)
add_custom_target(copy_l_viewer_manifest ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched)
if (PACKAGE)
add_custom_target(llpackage ALL DEPENDS ${product}.tar.bz2)
add_custom_target(llpackage ALL DEPENDS ${product}.tar.xz)
# Make sure we don't run two instances of viewer_manifest.py at the same time.
add_dependencies(llpackage copy_l_viewer_manifest)
check_message_template(llpackage)
@ -2708,7 +2714,7 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE
# OUTPUT_VARIABLE PARENT_DIRECTORY_CYGWIN
# OUTPUT_STRIP_TRAILING_WHITESPACE)
# add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}"
# # Use of 'tar ...j' here assumes VIEWER_SYMBOL_FILE endswith .tar.bz2;
# # Use of 'tar ...j' here assumes VIEWER_SYMBOL_FILE endswith .tar.xz;
# # testing a string suffix is painful enough in CMake language that
# # we'll continue assuming it until forced to generalize.
# COMMAND "tar"

View File

@ -717,7 +717,7 @@ void tapHeroProbe(inout vec3 glossenv, vec3 pos, vec3 norm, float glossiness)
clipDist = clipDist * 0.95 + 0.05;
clipDist = clamp(clipDist * falloffMult, 0, 1);
w = clamp(w * falloffMult * clipDist, 0, 1);
w = mix(0, w, clamp(glossiness - 0.75, 0, 1) * 4); // We only generate a quarter of the mips for the hero probes. Linearly interpolate between normal probes and hero probes based upon glossiness.
glossenv = mix(glossenv, textureLod(heroProbes, vec4(env_mat * refnormpersp, 0), (1.0-glossiness)*heroMipCount).xyz, w);
}

View File

@ -107,6 +107,11 @@ WLSkyDetail 1 96
RenderFSAASamples 1 0
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 0
RenderMirrors 1 0
RenderHeroProbeResolution 1 256
RenderHeroProbeDistance 1 4
RenderHeroProbeUpdateRate 1 4
RenderHeroProbeConservativeUpdateMultiplier 1 16
//
// Medium Low Graphics Settings
@ -138,6 +143,11 @@ WLSkyDetail 1 96
RenderFSAASamples 1 0
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 0
RenderMirrors 1 0
RenderHeroProbeResolution 1 256
RenderHeroProbeDistance 1 6
RenderHeroProbeUpdateRate 1 3
RenderHeroProbeConservativeUpdateMultiplier 1 16
//
// Medium Graphics Settings (standard)
@ -169,6 +179,11 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 0
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 1
RenderMirrors 1 0
RenderHeroProbeResolution 1 512
RenderHeroProbeDistance 1 6
RenderHeroProbeUpdateRate 1 3
RenderHeroProbeConservativeUpdateMultiplier 1 16
//
// Medium High Graphics Settings
@ -200,6 +215,11 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 2
RenderMirrors 1 0
RenderHeroProbeResolution 1 512
RenderHeroProbeDistance 1 6
RenderHeroProbeUpdateRate 1 2
RenderHeroProbeConservativeUpdateMultiplier 1 8
//
// High Graphics Settings (SSAO + sun shadows)
@ -231,6 +251,11 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 3
RenderMirrors 1 0
RenderHeroProbeResolution 1 1024
RenderHeroProbeDistance 1 8
RenderHeroProbeUpdateRate 1 2
RenderHeroProbeConservativeUpdateMultiplier 1 8
//
// High Ultra Graphics Settings (deferred + SSAO + all shadows)
@ -262,6 +287,11 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 3
RenderMirrors 1 0
RenderHeroProbeResolution 1 1024
RenderHeroProbeDistance 1 16
RenderHeroProbeUpdateRate 1 1
RenderHeroProbeConservativeUpdateMultiplier 1 4
//
// Ultra graphics (REALLY PURTY!)
@ -293,6 +323,11 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 3
RenderMirrors 1 1
RenderHeroProbeResolution 1 2048
RenderHeroProbeDistance 1 16
RenderHeroProbeUpdateRate 1 1
RenderHeroProbeConservativeUpdateMultiplier 1 4
//
// Class Unknown Hardware (unknown)
@ -301,6 +336,7 @@ list Unknown
RenderShadowDetail 1 0
RenderDeferredSSAO 1 0
RenderUseAdvancedAtmospherics 1 0
RenderMirrors 1 0
//
// VRAM > 512MB
@ -322,6 +358,7 @@ RenderTransparentWater 1 0
RenderDeferredSSAO 0 0
RenderShadowDetail 0 0
RenderReflectionProbeDetail 0 -1
RenderMirrors 0 0
list Intel
RenderAnisotropic 1 0
@ -336,6 +373,7 @@ list GL3
RenderFSAASamples 0 0
RenderReflectionsEnabled 0 0
RenderReflectionProbeDetail 0 0
RenderMirrors 0 0
list TexUnit16orLess
RenderTerrainPBRDetail 1 -1

View File

@ -107,6 +107,11 @@ WLSkyDetail 1 96
RenderFSAASamples 1 0
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 0
RenderMirrors 1 0
RenderHeroProbeResolution 1 256
RenderHeroProbeDistance 1 4
RenderHeroProbeUpdateRate 1 4
RenderHeroProbeConservativeUpdateMultiplier 1 16
//
// Medium Low Graphics Settings
@ -138,6 +143,11 @@ WLSkyDetail 1 96
RenderFSAASamples 1 0
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 0
RenderMirrors 1 0
RenderHeroProbeResolution 1 256
RenderHeroProbeDistance 1 6
RenderHeroProbeUpdateRate 1 3
RenderHeroProbeConservativeUpdateMultiplier 1 16
//
// Medium Graphics Settings (standard)
@ -169,6 +179,11 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 0
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 1
RenderMirrors 1 0
RenderHeroProbeResolution 1 512
RenderHeroProbeDistance 1 6
RenderHeroProbeUpdateRate 1 3
RenderHeroProbeConservativeUpdateMultiplier 1 16
//
// Medium High Graphics Settings
@ -200,6 +215,11 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 2
RenderMirrors 1 0
RenderHeroProbeResolution 1 512
RenderHeroProbeDistance 1 6
RenderHeroProbeUpdateRate 1 2
RenderHeroProbeConservativeUpdateMultiplier 1 8
//
// High Graphics Settings (SSAO + sun shadows)
@ -231,6 +251,11 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 3
RenderMirrors 1 0
RenderHeroProbeResolution 1 1024
RenderHeroProbeDistance 1 8
RenderHeroProbeUpdateRate 1 2
RenderHeroProbeConservativeUpdateMultiplier 1 8
//
// High Ultra Graphics Settings (deferred + SSAO + all shadows)
@ -262,6 +287,11 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 3
RenderMirrors 1 0
RenderHeroProbeResolution 1 1024
RenderHeroProbeDistance 1 16
RenderHeroProbeUpdateRate 1 1
RenderHeroProbeConservativeUpdateMultiplier 1 4
//
// Ultra graphics (REALLY PURTY!)
@ -293,6 +323,11 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 3
RenderMirrors 1 1
RenderHeroProbeResolution 1 2048
RenderHeroProbeDistance 1 16
RenderHeroProbeUpdateRate 1 1
RenderHeroProbeConservativeUpdateMultiplier 1 4
//
// Class Unknown Hardware (unknown)
@ -301,6 +336,7 @@ list Unknown
RenderShadowDetail 1 0
RenderDeferredSSAO 1 0
RenderUseAdvancedAtmospherics 1 0
RenderMirrors 1 0
//
// VRAM > 512MB
@ -322,6 +358,7 @@ RenderTransparentWater 1 0
RenderDeferredSSAO 0 0
RenderShadowDetail 0 0
RenderReflectionProbeDetail 0 -1
RenderMirrors 0 0
list Intel
RenderAnisotropic 1 0
@ -342,6 +379,7 @@ list GL3
RenderFSAASamples 0 0
RenderReflectionsEnabled 0 0
RenderReflectionProbeDetail 0 0
RenderMirrors 0 0
RenderGLMultiThreadedTextures 0 0
list TexUnit16orLess

View File

@ -105,6 +105,11 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 0
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 0
RenderMirrors 1 0
RenderHeroProbeResolution 1 256
RenderHeroProbeDistance 1 4
RenderHeroProbeUpdateRate 1 4
RenderHeroProbeConservativeUpdateMultiplier 1 16
//
// Medium Low Graphics Settings
@ -136,6 +141,11 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 0
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 0
RenderMirrors 1 0
RenderHeroProbeResolution 1 256
RenderHeroProbeDistance 1 6
RenderHeroProbeUpdateRate 1 3
RenderHeroProbeConservativeUpdateMultiplier 1 16
//
// Medium Graphics Settings (standard)
@ -167,6 +177,11 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 0
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 0
RenderMirrors 1 0
RenderHeroProbeResolution 1 512
RenderHeroProbeDistance 1 6
RenderHeroProbeUpdateRate 1 3
RenderHeroProbeConservativeUpdateMultiplier 1 16
//
// Medium High Graphics Settings
@ -198,6 +213,11 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 0
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 0
RenderMirrors 1 0
RenderHeroProbeResolution 1 512
RenderHeroProbeDistance 1 6
RenderHeroProbeUpdateRate 1 2
RenderHeroProbeConservativeUpdateMultiplier 1 8
//
// High Graphics Settings (SSAO + sun shadows)
@ -229,6 +249,11 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 1
RenderMirrors 1 0
RenderHeroProbeResolution 1 1024
RenderHeroProbeDistance 1 8
RenderHeroProbeUpdateRate 1 2
RenderHeroProbeConservativeUpdateMultiplier 1 8
//
// High Ultra Graphics Settings (SSAO + all shadows)
@ -260,6 +285,11 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 2
RenderMirrors 1 0
RenderHeroProbeResolution 1 1024
RenderHeroProbeDistance 1 16
RenderHeroProbeUpdateRate 1 1
RenderHeroProbeConservativeUpdateMultiplier 1 4
//
// Ultra graphics (REALLY PURTY!)
@ -291,6 +321,11 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 3
RenderMirrors 1 1
RenderHeroProbeResolution 1 2048
RenderHeroProbeDistance 1 16
RenderHeroProbeUpdateRate 1 1
RenderHeroProbeConservativeUpdateMultiplier 1 4
//
// Class Unknown Hardware (unknown)
@ -299,6 +334,7 @@ list Unknown
RenderShadowDetail 1 0
RenderDeferredSSAO 1 0
RenderUseAdvancedAtmospherics 1 0
RenderMirrors 1 0
//
@ -320,6 +356,7 @@ RenderTerrainDetail 1 0
RenderDeferredSSAO 0 0
RenderUseAdvancedAtmospherics 0 0
RenderShadowDetail 0 0
RenderMirrors 0 0
list TexUnit8orLess
RenderDeferredSSAO 0 0
@ -338,3 +375,4 @@ list GL3
RenderFSAASamples 0 0
RenderReflectionProbeDetail 0 0
RenderReflectionsEnabled 0 0
RenderMirrors 0 0

View File

@ -792,7 +792,7 @@ BOOL FSPanelFace::postBuild()
// PBR Base Material swatch
// mMaterialCtrlPBR->setDefaultImageAssetID(LLUUID::null); // we have no default material, and null is standard for LLUUID -Zi
mMaterialCtrlPBR->setBlankImageAssetID(LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID);
mMaterialCtrlPBR->setBlankImageAssetID(BLANK_MATERIAL_ASSET_ID);
mMaterialCtrlPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this));
mMaterialCtrlPBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this));
mMaterialCtrlPBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this));
@ -2406,7 +2406,7 @@ void FSPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material,
{
mVOInventoryListener = nullptr;
}
if (!func.mIdenticalMaterial || func.mMaterialId.isNull() || func.mMaterialId == LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID)
if (!func.mIdenticalMaterial || func.mMaterialId.isNull() || func.mMaterialId == BLANK_MATERIAL_ASSET_ID)
{
mAgentInventoryListener = nullptr;
}

View File

@ -0,0 +1,211 @@
/**
* @file asset.cpp
* @brief LL GLTF Implementation
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2024, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "../llviewerprecompiledheaders.h"
#include "asset.h"
#include "llvolumeoctree.h"
using namespace LL::GLTF;
void Scene::updateTransforms(Asset& asset)
{
LLMatrix4a identity;
identity.setIdentity();
for (auto& nodeIndex : mNodes)
{
Node& node = asset.mNodes[nodeIndex];
node.updateTransforms(asset, identity);
}
}
void Scene::updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview)
{
for (auto& nodeIndex : mNodes)
{
Node& node = asset.mNodes[nodeIndex];
node.updateRenderTransforms(asset, modelview);
}
}
void Node::updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview)
{
matMul(mMatrix, modelview, mRenderMatrix);
for (auto& childIndex : mChildren)
{
Node& child = asset.mNodes[childIndex];
child.updateRenderTransforms(asset, mRenderMatrix);
}
}
LLMatrix4a inverse(const LLMatrix4a& mat);
void Node::updateTransforms(Asset& asset, const LLMatrix4a& parentMatrix)
{
matMul(mMatrix, parentMatrix, mAssetMatrix);
mAssetMatrixInv = inverse(mAssetMatrix);
for (auto& childIndex : mChildren)
{
Node& child = asset.mNodes[childIndex];
child.updateTransforms(asset, mAssetMatrix);
}
}
void Asset::updateTransforms()
{
for (auto& scene : mScenes)
{
scene.updateTransforms(*this);
}
}
void Asset::updateRenderTransforms(const LLMatrix4a& modelview)
{
#if 0
// traverse hierarchy and update render transforms from scratch
for (auto& scene : mScenes)
{
scene.updateRenderTransforms(*this, modelview);
}
#else
// use mAssetMatrix to update render transforms from node list
for (auto& node : mNodes)
{
if (node.mMesh != INVALID_INDEX)
{
matMul(node.mAssetMatrix, modelview, node.mRenderMatrix);
}
}
#endif
}
S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
LLVector4a* intersection, // return the intersection point
LLVector2* tex_coord, // return the texture coordinates of the intersection point
LLVector4a* normal, // return the surface normal at the intersection point
LLVector4a* tangent, // return the surface tangent at the intersection point
S32* primitive_hitp
)
{
S32 node_hit = -1;
S32 primitive_hit = -1;
LLVector4a local_start;
LLVector4a asset_end = end;
LLVector4a local_end;
LLVector4a p;
for (auto& node : mNodes)
{
if (node.mMesh != INVALID_INDEX)
{
bool newHit = false;
// transform start and end to this node's local space
node.mAssetMatrixInv.affineTransform(start, local_start);
node.mAssetMatrixInv.affineTransform(asset_end, local_end);
Mesh& mesh = mMeshes[node.mMesh];
for (auto& primitive : mesh.mPrimitives)
{
const LLVolumeTriangle* tri = primitive.lineSegmentIntersect(local_start, local_end, &p, tex_coord, normal, tangent);
if (tri)
{
newHit = true;
local_end = p;
// pointer math to get the node index
node_hit = &node - &mNodes[0];
llassert(&mNodes[node_hit] == &node);
//pointer math to get the primitive index
primitive_hit = &primitive - &mesh.mPrimitives[0];
llassert(&mesh.mPrimitives[primitive_hit] == &primitive);
}
}
if (newHit)
{
// shorten line segment on hit
node.mAssetMatrix.affineTransform(p, asset_end);
// transform results back to asset space
if (intersection)
{
*intersection = asset_end;
}
if (normal || tangent)
{
LLMatrix4 normalMatrix(node.mAssetMatrixInv.getF32ptr());
normalMatrix.transpose();
LLMatrix4a norm_mat;
norm_mat.loadu((F32*)normalMatrix.mMatrix);
if (normal)
{
LLVector4a n = *normal;
F32 w = n.getF32ptr()[3];
n.getF32ptr()[3] = 0.0f;
norm_mat.affineTransform(n, *normal);
normal->getF32ptr()[3] = w;
}
if (tangent)
{
LLVector4a t = *tangent;
F32 w = t.getF32ptr()[3];
t.getF32ptr()[3] = 0.0f;
norm_mat.affineTransform(t, *tangent);
tangent->getF32ptr()[3] = w;
}
}
}
}
}
if (node_hit != -1)
{
if (primitive_hitp)
{
*primitive_hitp = primitive_hit;
}
}
return node_hit;
}

445
indra/newview/gltf/asset.h Normal file
View File

@ -0,0 +1,445 @@
#pragma once
/**
* @file asset.h
* @brief LL GLTF Implementation
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2024, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llvertexbuffer.h"
#include "llvolumeoctree.h"
#include "../lltinygltfhelper.h"
#include "primitive.h"
// LL GLTF Implementation
namespace LL
{
namespace GLTF
{
constexpr S32 INVALID_INDEX = -1;
class Asset;
class Buffer
{
public:
std::vector<U8> mData;
std::string mName;
std::string mUri;
const Buffer& operator=(const tinygltf::Buffer& src)
{
mData = src.data;
mName = src.name;
mUri = src.uri;
return *this;
}
};
class BufferView
{
public:
S32 mBuffer = INVALID_INDEX;
S32 mByteLength;
S32 mByteOffset;
S32 mByteStride;
S32 mTarget;
S32 mComponentType;
std::string mName;
const BufferView& operator=(const tinygltf::BufferView& src)
{
mBuffer = src.buffer;
mByteLength = src.byteLength;
mByteOffset = src.byteOffset;
mByteStride = src.byteStride;
mTarget = src.target;
mName = src.name;
return *this;
}
};
class Accessor
{
public:
S32 mBufferView = INVALID_INDEX;
S32 mByteOffset;
S32 mComponentType;
S32 mCount;
std::vector<double> mMax;
std::vector<double> mMin;
S32 mType;
bool mNormalized;
std::string mName;
const Accessor& operator=(const tinygltf::Accessor& src)
{
mBufferView = src.bufferView;
mByteOffset = src.byteOffset;
mComponentType = src.componentType;
mCount = src.count;
mType = src.type;
mNormalized = src.normalized;
mName = src.name;
mMax = src.maxValues;
mMin = src.maxValues;
return *this;
}
};
class Material
{
public:
// use LLFetchedGLTFMaterial for now, but eventually we'll want to use
// a more flexible GLTF material implementation instead of the fixed packing
// version we use for sharable GLTF material assets
LLPointer<LLFetchedGLTFMaterial> mMaterial;
std::string mName;
const Material& operator=(const tinygltf::Material& src)
{
mName = src.name;
return *this;
}
void allocateGLResources(Asset& asset)
{
// allocate material
mMaterial = new LLFetchedGLTFMaterial();
}
};
class Mesh
{
public:
std::vector<Primitive> mPrimitives;
std::vector<double> mWeights;
std::string mName;
const Mesh& operator=(const tinygltf::Mesh& src)
{
mPrimitives.resize(src.primitives.size());
for (U32 i = 0; i < src.primitives.size(); ++i)
{
mPrimitives[i] = src.primitives[i];
}
mWeights = src.weights;
mName = src.name;
return *this;
}
void allocateGLResources(Asset& asset)
{
for (auto& primitive : mPrimitives)
{
primitive.allocateGLResources(asset);
}
}
};
class Node
{
public:
LLMatrix4a mMatrix; //local transform
LLMatrix4a mRenderMatrix; //transform for rendering
LLMatrix4a mAssetMatrix; //transform from local to asset space
LLMatrix4a mAssetMatrixInv; //transform from asset to local space
std::vector<S32> mChildren;
S32 mMesh = INVALID_INDEX;
std::string mName;
const Node& operator=(const tinygltf::Node& src)
{
F32* dstMatrix = mMatrix.getF32ptr();
if (src.matrix.size() != 16)
{
mMatrix.setIdentity();
}
else
{
for (U32 i = 0; i < 16; ++i)
{
dstMatrix[i] = (F32)src.matrix[i];
}
}
mChildren = src.children;
mMesh = src.mesh;
mName = src.name;
return *this;
}
// Set mRenderMatrix to a transform that can be used for the current render pass
// modelview -- parent's render matrix
void updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview);
// update mAssetMatrix and mAssetMatrixInv
void updateTransforms(Asset& asset, const LLMatrix4a& parentMatrix);
};
class Scene
{
public:
std::vector<S32> mNodes;
std::string mName;
const Scene& operator=(const tinygltf::Scene& src)
{
mNodes = src.nodes;
mName = src.name;
return *this;
}
void updateTransforms(Asset& asset);
void updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview);
};
class Texture
{
public:
S32 mSampler = INVALID_INDEX;
S32 mSource = INVALID_INDEX;
std::string mName;
const Texture& operator=(const tinygltf::Texture& src)
{
mSampler = src.sampler;
mSource = src.source;
mName = src.name;
return *this;
}
};
class Sampler
{
public:
S32 mMagFilter;
S32 mMinFilter;
S32 mWrapS;
S32 mWrapT;
std::string mName;
const Sampler& operator=(const tinygltf::Sampler& src)
{
mMagFilter = src.magFilter;
mMinFilter = src.minFilter;
mWrapS = src.wrapS;
mWrapT = src.wrapT;
mName = src.name;
return *this;
}
};
class Image
{
public:
std::string mName;
std::string mUri;
std::string mMimeType;
std::vector<U8> mData;
S32 mWidth;
S32 mHeight;
S32 mComponent;
S32 mBits;
LLPointer<LLViewerFetchedTexture> mTexture;
const Image& operator=(const tinygltf::Image& src)
{
mName = src.name;
mUri = src.uri;
mMimeType = src.mimeType;
mData = src.image;
mWidth = src.width;
mHeight = src.height;
mComponent = src.component;
mBits = src.bits;
return *this;
}
void allocateGLResources()
{
// allocate texture
}
};
// C++ representation of a GLTF Asset
class Asset : public LLRefCount
{
public:
std::vector<Scene> mScenes;
std::vector<Node> mNodes;
std::vector<Mesh> mMeshes;
std::vector<Material> mMaterials;
std::vector<Buffer> mBuffers;
std::vector<BufferView> mBufferViews;
std::vector<Texture> mTextures;
std::vector<Sampler> mSamplers;
std::vector<Image> mImages;
std::vector<Accessor> mAccessors;
void allocateGLResources(const std::string& filename, const tinygltf::Model& model)
{
for (auto& mesh : mMeshes)
{
mesh.allocateGLResources(*this);
}
for (auto& image : mImages)
{
image.allocateGLResources();
}
for (U32 i = 0; i < mMaterials.size(); ++i)
{
mMaterials[i].allocateGLResources(*this);
LLTinyGLTFHelper::getMaterialFromModel(filename, model, i, mMaterials[i].mMaterial, mMaterials[i].mName, true);
}
}
// update asset-to-node and node-to-asset transforms
void updateTransforms();
// update node render transforms
void updateRenderTransforms(const LLMatrix4a& modelview);
void renderOpaque()
{
for (auto& node : mNodes)
{
if (node.mMesh != INVALID_INDEX)
{
Mesh& mesh = mMeshes[node.mMesh];
for (auto& primitive : mesh.mPrimitives)
{
gGL.loadMatrix((F32*)node.mRenderMatrix.mMatrix);
if (primitive.mMaterial != INVALID_INDEX)
{
Material& material = mMaterials[primitive.mMaterial];
material.mMaterial->bind();
}
primitive.mVertexBuffer->setBuffer();
if (primitive.mVertexBuffer->getNumIndices() > 0)
{
primitive.mVertexBuffer->draw(primitive.mGLMode, primitive.mVertexBuffer->getNumIndices(), 0);
}
else
{
primitive.mVertexBuffer->drawArrays(primitive.mGLMode, 0, primitive.mVertexBuffer->getNumVerts());
}
}
}
}
}
// return the index of the node that the line segment intersects with, or -1 if no hit
// input and output values must be in this asset's local coordinate frame
S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
LLVector4a* intersection = nullptr, // return the intersection point
LLVector2* tex_coord = nullptr, // return the texture coordinates of the intersection point
LLVector4a* normal = nullptr, // return the surface normal at the intersection point
LLVector4a* tangent = nullptr, // return the surface tangent at the intersection point
S32* primitive_hitp = nullptr // return the index of the primitive that was hit
);
const Asset& operator=(const tinygltf::Model& src)
{
mScenes.resize(src.scenes.size());
for (U32 i = 0; i < src.scenes.size(); ++i)
{
mScenes[i] = src.scenes[i];
}
mNodes.resize(src.nodes.size());
for (U32 i = 0; i < src.nodes.size(); ++i)
{
mNodes[i] = src.nodes[i];
}
mMeshes.resize(src.meshes.size());
for (U32 i = 0; i < src.meshes.size(); ++i)
{
mMeshes[i] = src.meshes[i];
}
mMaterials.resize(src.materials.size());
for (U32 i = 0; i < src.materials.size(); ++i)
{
mMaterials[i] = src.materials[i];
}
mBuffers.resize(src.buffers.size());
for (U32 i = 0; i < src.buffers.size(); ++i)
{
mBuffers[i] = src.buffers[i];
}
mBufferViews.resize(src.bufferViews.size());
for (U32 i = 0; i < src.bufferViews.size(); ++i)
{
mBufferViews[i] = src.bufferViews[i];
}
mTextures.resize(src.textures.size());
for (U32 i = 0; i < src.textures.size(); ++i)
{
mTextures[i] = src.textures[i];
}
mSamplers.resize(src.samplers.size());
for (U32 i = 0; i < src.samplers.size(); ++i)
{
mSamplers[i] = src.samplers[i];
}
mImages.resize(src.images.size());
for (U32 i = 0; i < src.images.size(); ++i)
{
mImages[i] = src.images[i];
}
mAccessors.resize(src.accessors.size());
for (U32 i = 0; i < src.accessors.size(); ++i)
{
mAccessors[i] = src.accessors[i];
}
return *this;
}
};
}
}

View File

@ -0,0 +1,484 @@
/**
* @file primitive.cpp
* @brief LL GLTF Implementation
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2024, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "../llviewerprecompiledheaders.h"
#include "asset.h"
#include "../lltinygltfhelper.h"
using namespace LL::GLTF;
#ifdef _MSC_VER
#define LL_FUNCSIG __FUNCSIG__
#else
#define LL_FUNCSIG __PRETTY_FUNCTION__
#endif
// copy one vec3 from src to dst
template<class S, class T>
void copyVec2(S* src, T& dst)
{
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
}
// copy one vec3 from src to dst
template<class S, class T>
void copyVec3(S* src, T& dst)
{
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
}
// copy one vec4 from src to dst
template<class S, class T>
void copyVec4(S* src, T& dst)
{
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
}
template<>
void copyVec2<F32, LLVector2>(F32* src, LLVector2& dst)
{
dst.set(src[0], src[1]);
}
template<>
void copyVec3<F32, LLVector4a>(F32* src, LLVector4a& dst)
{
dst.load3(src);
}
template<>
void copyVec3<U16, LLColor4U>(U16* src, LLColor4U& dst)
{
dst.set(src[0], src[1], src[2], 255);
}
template<>
void copyVec4<F32, LLVector4a>(F32* src, LLVector4a& dst)
{
dst.loadua(src);
}
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
template<class S, class T>
void copyVec2(S* src, LLStrider<T> dst, S32 stride, S32 count)
{
for (S32 i = 0; i < count; ++i)
{
copyVec2(src, *dst);
dst++;
src = (S*)((U8*)src + stride);
}
}
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
template<class S, class T>
void copyVec3(S* src, LLStrider<T> dst, S32 stride, S32 count)
{
for (S32 i = 0; i < count; ++i)
{
copyVec3(src, *dst);
dst++;
src = (S*)((U8*)src + stride);
}
}
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
template<class S, class T>
void copyVec4(S* src, LLStrider<T> dst, S32 stride, S32 count)
{
for (S32 i = 0; i < count; ++i)
{
copyVec3(src, *dst);
dst++;
src = (S*)((U8*)src + stride);
}
}
template<class S, class T>
void copyAttributeArray(Asset& asset, const Accessor& accessor, const S* src, LLStrider<T>& dst, S32 byteStride)
{
if (accessor.mType == TINYGLTF_TYPE_VEC2)
{
S32 stride = byteStride == 0 ? sizeof(S) * 2 : byteStride;
copyVec2((S*)src, dst, stride, accessor.mCount);
}
else if (accessor.mType == TINYGLTF_TYPE_VEC3)
{
S32 stride = byteStride == 0 ? sizeof(S) * 3 : byteStride;
copyVec3((S*)src, dst, stride, accessor.mCount);
}
else if (accessor.mType == TINYGLTF_TYPE_VEC4)
{
S32 stride = byteStride == 0 ? sizeof(S) * 4 : byteStride;
copyVec4((S*)src, dst, stride, accessor.mCount);
}
else
{
LL_ERRS("GLTF") << "Unsupported accessor type" << LL_ENDL;
}
}
template <class T>
void Primitive::copyAttribute(Asset& asset, S32 accessorIdx, LLStrider<T>& dst)
{
const Accessor& accessor = asset.mAccessors[accessorIdx];
const BufferView& bufferView = asset.mBufferViews[accessor.mBufferView];
const Buffer& buffer = asset.mBuffers[bufferView.mBuffer];
const U8* src = buffer.mData.data() + bufferView.mByteOffset + accessor.mByteOffset;
if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_FLOAT)
{
copyAttributeArray(asset, accessor, (const F32*)src, dst, bufferView.mByteStride);
}
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT)
{
copyAttributeArray(asset, accessor, (const U16*)src, dst, bufferView.mByteStride);
}
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT)
{
copyAttributeArray(asset, accessor, (const U32*)src, dst, bufferView.mByteStride);
}
else
{
LL_ERRS() << "Unsupported component type" << LL_ENDL;
}
}
void Primitive::allocateGLResources(Asset& asset)
{
// allocate vertex buffer
// We diverge from the intent of the GLTF format here to work with our existing render pipeline
// GLTF wants us to copy the buffer views into GPU storage as is and build render commands that source that data.
// For our engine, though, it's better to rearrange the buffers at load time into a layout that's more consistent.
// The GLTF native approach undoubtedly works well if you can count on VAOs, but VAOs perform much worse with our scenes.
// get the number of vertices
U32 numVertices = 0;
for (auto& it : mAttributes)
{
const Accessor& accessor = asset.mAccessors[it.second];
numVertices = accessor.mCount;
break;
}
// get the number of indices
U32 numIndices = 0;
if (mIndices != INVALID_INDEX)
{
const Accessor& accessor = asset.mAccessors[mIndices];
numIndices = accessor.mCount;
}
// create vertex buffer
mVertexBuffer = new LLVertexBuffer(ATTRIBUTE_MASK);
mVertexBuffer->allocateBuffer(numVertices, numIndices);
bool needs_color = true;
bool needs_texcoord = true;
bool needs_normal = true;
bool needs_tangent = true;
// load vertex data
for (auto& it : mAttributes)
{
const std::string& attribName = it.first;
// load vertex data
if (attribName == "POSITION")
{
// load position data
LLStrider<LLVector4a> dst;
mVertexBuffer->getVertexStrider(dst);
copyAttribute(asset, it.second, dst);
}
else if (attribName == "NORMAL")
{
needs_normal = false;
// load normal data
LLStrider<LLVector4a> dst;
mVertexBuffer->getNormalStrider(dst);
copyAttribute(asset, it.second, dst);
}
else if (attribName == "TANGENT")
{
needs_tangent = false;
// load tangent data
LLStrider<LLVector4a> dst;
mVertexBuffer->getTangentStrider(dst);
copyAttribute(asset, it.second, dst);
}
else if (attribName == "COLOR_0")
{
needs_color = false;
// load color data
LLStrider<LLColor4U> dst;
mVertexBuffer->getColorStrider(dst);
copyAttribute(asset, it.second, dst);
}
else if (attribName == "TEXCOORD_0")
{
needs_texcoord = false;
// load texcoord data
LLStrider<LLVector2> dst;
mVertexBuffer->getTexCoord0Strider(dst);
LLStrider<LLVector2> tc = dst;
copyAttribute(asset, it.second, dst);
// convert to OpenGL coordinate space
for (U32 i = 0; i < numVertices; ++i)
{
tc->mV[1] = 1.0f - tc->mV[1];;
tc++;
}
}
}
// copy index buffer
if (mIndices != INVALID_INDEX)
{
const Accessor& accessor = asset.mAccessors[mIndices];
const BufferView& bufferView = asset.mBufferViews[accessor.mBufferView];
const Buffer& buffer = asset.mBuffers[bufferView.mBuffer];
const U8* src = buffer.mData.data() + bufferView.mByteOffset + accessor.mByteOffset;
LLStrider<U16> dst;
mVertexBuffer->getIndexStrider(dst);
mIndexArray.resize(numIndices);
if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT)
{
for (U32 i = 0; i < numIndices; ++i)
{
*(dst++) = (U16) * (U32*)src;
src += sizeof(U32);
}
}
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT)
{
for (U32 i = 0; i < numIndices; ++i)
{
*(dst++) = *(U16*)src;
src += sizeof(U16);
}
}
else
{
LL_ERRS("GLTF") << "Unsupported component type for indices" << LL_ENDL;
}
U16* idx = (U16*)mVertexBuffer->getMappedIndices();
for (U32 i = 0; i < numIndices; ++i)
{
mIndexArray[i] = idx[i];
}
}
// fill in default values for missing attributes
if (needs_color)
{ // set default color
LLStrider<LLColor4U> dst;
mVertexBuffer->getColorStrider(dst);
for (U32 i = 0; i < numVertices; ++i)
{
*(dst++) = LLColor4U(255, 255, 255, 255);
}
}
if (needs_texcoord)
{ // set default texcoord
LLStrider<LLVector2> dst;
mVertexBuffer->getTexCoord0Strider(dst);
for (U32 i = 0; i < numVertices; ++i)
{
*(dst++) = LLVector2(0.0f, 0.0f);
}
}
if (needs_normal)
{ // set default normal
LLStrider<LLVector4a> dst;
mVertexBuffer->getNormalStrider(dst);
for (U32 i = 0; i < numVertices; ++i)
{
*(dst++) = LLVector4a(0.0f, 0.0f, 1.0f, 0.0f);
}
}
if (needs_tangent)
{ // TODO: generate tangents if needed
LLStrider<LLVector4a> dst;
mVertexBuffer->getTangentStrider(dst);
for (U32 i = 0; i < numVertices; ++i)
{
*(dst++) = LLVector4a(1.0f, 0.0f, 0.0f, 1.0f);
}
}
mPositions.resize(numVertices);
mTexCoords.resize(numVertices);
mNormals.resize(numVertices);
mTangents.resize(numVertices);
LLVector4a* pos = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_VERTEX));
LLVector2* tc = (LLVector2*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_TEXCOORD0));
LLVector4a* norm = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_NORMAL));
LLVector4a* tangent = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_TANGENT));
for (U32 i = 0; i < numVertices; ++i)
{
mPositions[i] = pos[i];
mTexCoords[i] = tc[i];
mNormals[i] = norm[i];
mTangents[i] = tangent[i];
}
createOctree();
mVertexBuffer->unmapBuffer();
}
void Primitive::createOctree()
{
// create octree
mOctree = new LLVolumeOctree();
if (mMode == TINYGLTF_MODE_TRIANGLES)
{
F32 scaler = 0.25f;
const U32 num_triangles = mVertexBuffer->getNumIndices() / 3;
// Initialize all the triangles we need
mOctreeTriangles.resize(num_triangles);
LLVector4a* pos = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_VERTEX));
U16* indices = (U16*)mVertexBuffer->getMappedIndices();
for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index)
{ //for each triangle
const U32 index = triangle_index * 3;
LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index];
const LLVector4a& v0 = pos[indices[index]];
const LLVector4a& v1 = pos[indices[index + 1]];
const LLVector4a& v2 = pos[indices[index + 2]];
//store pointers to vertex data
tri->mV[0] = &v0;
tri->mV[1] = &v1;
tri->mV[2] = &v2;
//store indices
tri->mIndex[0] = indices[index];
tri->mIndex[1] = indices[index + 1];
tri->mIndex[2] = indices[index + 2];
//get minimum point
LLVector4a min = v0;
min.setMin(min, v1);
min.setMin(min, v2);
//get maximum point
LLVector4a max = v0;
max.setMax(max, v1);
max.setMax(max, v2);
//compute center
LLVector4a center;
center.setAdd(min, max);
center.mul(0.5f);
tri->mPositionGroup = center;
//compute "radius"
LLVector4a size;
size.setSub(max, min);
tri->mRadius = size.getLength3().getF32() * scaler;
//insert
mOctree->insert(tri);
}
}
else
{
LL_ERRS() << "Unsupported Primitive mode" << LL_ENDL;
}
//remove unneeded octree layers
while (!mOctree->balance()) {}
//calculate AABB for each node
LLVolumeOctreeRebound rebound;
rebound.traverse(mOctree);
}
const LLVolumeTriangle* Primitive::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
LLVector4a* intersection, LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent_out)
{
if (mOctree.isNull())
{
return nullptr;
}
LLVector4a dir;
dir.setSub(end, start);
F32 closest_t = 2.f; // must be larger than 1
//create a proxy LLVolumeFace for the raycast
LLVolumeFace face;
face.mPositions = mPositions.data();
face.mTexCoords = mTexCoords.data();
face.mNormals = mNormals.data();
face.mTangents = mTangents.data();
face.mIndices = mIndexArray.data();
face.mNumIndices = mIndexArray.size();
face.mNumVertices = mPositions.size();
LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, tangent_out);
intersect.traverse(mOctree);
// null out proxy data so it doesn't get freed
face.mPositions = face.mNormals = face.mTangents = nullptr;
face.mIndices = nullptr;
face.mTexCoords = nullptr;
return intersect.mHitTriangle;
}
Primitive::~Primitive()
{
mOctree = nullptr;
}

View File

@ -0,0 +1,140 @@
#pragma once
/**
* @file primitive.h
* @brief LL GLTF Implementation
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2024, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llvertexbuffer.h"
#include "llvolumeoctree.h"
// LL GLTF Implementation
namespace LL
{
namespace GLTF
{
class Asset;
constexpr U32 ATTRIBUTE_MASK =
LLVertexBuffer::MAP_VERTEX |
LLVertexBuffer::MAP_NORMAL |
LLVertexBuffer::MAP_TEXCOORD0 |
LLVertexBuffer::MAP_TANGENT |
LLVertexBuffer::MAP_COLOR;
class Primitive
{
public:
~Primitive();
// GPU copy of mesh data
LLPointer<LLVertexBuffer> mVertexBuffer;
// CPU copy of mesh data
std::vector<LLVector2> mTexCoords;
std::vector<LLVector4a> mNormals;
std::vector<LLVector4a> mTangents;
std::vector<LLVector4a> mPositions;
std::vector<U16> mIndexArray;
// raycast acceleration structure
LLPointer<LLVolumeOctree> mOctree;
std::vector<LLVolumeTriangle> mOctreeTriangles;
S32 mMaterial = -1;
U32 mMode = TINYGLTF_MODE_TRIANGLES; // default to triangles
U32 mGLMode = LLRender::TRIANGLES;
S32 mIndices = -1;
std::unordered_map<std::string, int> mAttributes;
// copy the attribute in the given BufferView to the given destination
// assumes destination has enough storage for the attribute
template<class T>
void copyAttribute(Asset& asset, S32 bufferViewIdx, LLStrider<T>& dst);
// create octree based on vertex buffer
// must be called before buffer is unmapped and after buffer is populated with good data
void createOctree();
//get the LLVolumeTriangle that intersects with the given line segment at the point
//closest to start. Moves end to the point of intersection. Returns nullptr if no intersection.
//Line segment must be in the same coordinate frame as this Primitive
const LLVolumeTriangle* lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
LLVector4a* intersection = NULL, // return the intersection point
LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point
LLVector4a* normal = NULL, // return the surface normal at the intersection point
LLVector4a* tangent = NULL // return the surface tangent at the intersection point
);
const Primitive& operator=(const tinygltf::Primitive& src)
{
// load material
mMaterial = src.material;
// load mode
mMode = src.mode;
// load indices
mIndices = src.indices;
// load attributes
for (auto& it : src.attributes)
{
mAttributes[it.first] = it.second;
}
switch (mMode)
{
case TINYGLTF_MODE_POINTS:
mGLMode = LLRender::POINTS;
break;
case TINYGLTF_MODE_LINE:
mGLMode = LLRender::LINES;
break;
case TINYGLTF_MODE_LINE_LOOP:
mGLMode = LLRender::LINE_LOOP;
break;
case TINYGLTF_MODE_LINE_STRIP:
mGLMode = LLRender::LINE_STRIP;
break;
case TINYGLTF_MODE_TRIANGLES:
mGLMode = LLRender::TRIANGLES;
break;
case TINYGLTF_MODE_TRIANGLE_STRIP:
mGLMode = LLRender::TRIANGLE_STRIP;
break;
case TINYGLTF_MODE_TRIANGLE_FAN:
mGLMode = LLRender::TRIANGLE_FAN;
break;
default:
mGLMode = GL_TRIANGLES;
}
return *this;
}
void allocateGLResources(Asset& asset);
};
}
}

View File

@ -0,0 +1,470 @@
/**
* @file gltfscenemanager.cpp
* @brief Builds menus out of items.
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2024, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "gltfscenemanager.h"
#include "llviewermenufile.h"
#include "llappviewer.h"
#include "lltinygltfhelper.h"
#include "llvertexbuffer.h"
#include "llselectmgr.h"
#include "llagent.h"
#include "llnotificationsutil.h"
#include "llvoavatarself.h"
#include "llvolumeoctree.h"
#include "gltf/asset.h"
#include "pipeline.h"
#include "llviewershadermgr.h"
using namespace LL;
// temporary location of LL GLTF Implementation
using namespace LL::GLTF;
void GLTFSceneManager::load()
{
LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject();
if (obj)
{
// Load a scene from disk
LLFilePickerReplyThread::startPicker(
[](const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter)
{
if (LLAppViewer::instance()->quitRequested())
{
return;
}
if (filenames.size() > 0)
{
GLTFSceneManager::instance().load(filenames[0]);
}
},
LLFilePicker::FFLOAD_GLTF,
true);
}
else
{
LLNotificationsUtil::add("GLTFPreviewSelection");
}
}
void GLTFSceneManager::load(const std::string& filename)
{
tinygltf::Model model;
LLTinyGLTFHelper::loadModel(filename, model);
LLPointer<Asset> asset = new Asset();
*asset = model;
asset->allocateGLResources(filename, model);
asset->updateTransforms();
// hang the asset off the currently selected object, or off of the avatar if no object is selected
LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject();
if (obj)
{ // assign to self avatar
obj->mGLTFAsset = asset;
mObjects.push_back(obj);
}
}
GLTFSceneManager::~GLTFSceneManager()
{
mObjects.clear();
}
LLMatrix4a getAssetToAgentTransform(LLViewerObject* obj)
{
LLMatrix4 root;
root.initScale(obj->getScale());
root.rotate(obj->getRenderRotation());
root.translate(obj->getPositionAgent());
LLMatrix4a mat;
mat.loadu((F32*) root.mMatrix);
return mat;
}
LLMatrix4a getAgentToAssetTransform(LLViewerObject* obj)
{
LLMatrix4 root;
LLVector3 scale = obj->getScale();
scale.mV[0] = 1.f / scale.mV[0];
scale.mV[1] = 1.f / scale.mV[1];
scale.mV[2] = 1.f / scale.mV[2];
root.translate(-obj->getPositionAgent());
root.rotate(~obj->getRenderRotation());
LLMatrix4 scale_mat;
scale_mat.initScale(scale);
root *= scale_mat;
LLMatrix4a mat;
mat.loadu((F32*) root.mMatrix);
return mat;
}
void GLTFSceneManager::renderOpaque()
{
// for debugging, just render the whole scene as opaque
// by traversing the whole scenegraph
// Assumes camera transform is already set and
// appropriate shader is already bound
gGL.matrixMode(LLRender::MM_MODELVIEW);
for (U32 i = 0; i < mObjects.size(); ++i)
{
if (mObjects[i]->isDead() || mObjects[i]->mGLTFAsset == nullptr)
{
mObjects.erase(mObjects.begin() + i);
--i;
continue;
}
Asset* asset = mObjects[i]->mGLTFAsset;
gGL.pushMatrix();
LLMatrix4a mat = getAssetToAgentTransform(mObjects[i]);
LLMatrix4a modelview;
modelview.loadu(gGLModelView);
matMul(mat, modelview, modelview);
asset->updateRenderTransforms(modelview);
asset->renderOpaque();
gGL.popMatrix();
}
}
LLMatrix4a inverse(const LLMatrix4a& mat)
{
glh::matrix4f m((F32*)mat.mMatrix);
m = m.inverse();
LLMatrix4a ret;
ret.loadu(m.m);
return ret;
}
bool GLTFSceneManager::lineSegmentIntersect(LLVOVolume* obj, Asset* asset, const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, BOOL pick_rigged, BOOL pick_unselectable, S32* node_hit, S32* primitive_hit,
LLVector4a* intersection, LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent)
{
// line segment intersection test
// start and end should be in agent space
// volume space and asset space should be the same coordinate frame
// results should be transformed back to agent space
bool ret = false;
LLVector4a local_start;
LLVector4a local_end;
LLMatrix4a asset_to_agent = getAssetToAgentTransform(obj);
LLMatrix4a agent_to_asset = inverse(asset_to_agent);
agent_to_asset.affineTransform(start, local_start);
agent_to_asset.affineTransform(end, local_end);
LLVector4a p;
LLVector4a n;
LLVector2 tc;
LLVector4a tn;
if (intersection != NULL)
{
p = *intersection;
}
if (tex_coord != NULL)
{
tc = *tex_coord;
}
if (normal != NULL)
{
n = *normal;
}
if (tangent != NULL)
{
tn = *tangent;
}
S32 hit_node_index = asset->lineSegmentIntersect(local_start, local_end, &p, &tc, &n, &tn, primitive_hit);
if (hit_node_index >= 0)
{
local_end = p;
if (node_hit != NULL)
{
*node_hit = hit_node_index;
}
if (intersection != NULL)
{
asset_to_agent.affineTransform(p, *intersection);
}
if (normal != NULL)
{
LLVector3 v_n(n.getF32ptr());
normal->load3(obj->volumeDirectionToAgent(v_n).mV);
(*normal).normalize3fast();
}
if (tangent != NULL)
{
LLVector3 v_tn(tn.getF32ptr());
LLVector4a trans_tangent;
trans_tangent.load3(obj->volumeDirectionToAgent(v_tn).mV);
LLVector4Logical mask;
mask.clear();
mask.setElement<3>();
tangent->setSelectWithMask(mask, tn, trans_tangent);
(*tangent).normalize3fast();
}
if (tex_coord != NULL)
{
*tex_coord = tc;
}
ret = true;
}
return ret;
}
LLDrawable* GLTFSceneManager::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
BOOL pick_transparent,
BOOL pick_rigged,
BOOL pick_unselectable,
BOOL pick_reflection_probe,
S32* node_hit, // return the index of the node that was hit
S32* primitive_hit, // return the index of the primitive that was hit
LLVector4a* intersection, // return the intersection point
LLVector2* tex_coord, // return the texture coordinates of the intersection point
LLVector4a* normal, // return the surface normal at the intersection point
LLVector4a* tangent) // return the surface tangent at the intersection point
{
LLDrawable* drawable = nullptr;
LLVector4a local_end = end;
LLVector4a position;
for (U32 i = 0; i < mObjects.size(); ++i)
{
if (mObjects[i]->isDead() || mObjects[i]->mGLTFAsset == nullptr || !mObjects[i]->getVolume())
{
mObjects.erase(mObjects.begin() + i);
--i;
continue;
}
// temporary debug -- always double check objects that have GLTF scenes hanging off of them even if the ray doesn't intersect the object bounds
if (lineSegmentIntersect((LLVOVolume*) mObjects[i].get(), mObjects[i]->mGLTFAsset, start, local_end, -1, pick_transparent, pick_rigged, pick_unselectable, node_hit, primitive_hit, &position, tex_coord, normal, tangent))
{
local_end = position;
if (intersection)
{
*intersection = position;
}
drawable = mObjects[i]->mDrawable;
}
}
return drawable;
}
void drawBoxOutline(const LLVector4a& pos, const LLVector4a& size);
extern LLVector4a gDebugRaycastStart;
extern LLVector4a gDebugRaycastEnd;
void renderOctreeRaycast(const LLVector4a& start, const LLVector4a& end, const LLVolumeOctree* octree);
void renderAssetDebug(LLViewerObject* obj, Asset* asset)
{
// render debug
// assumes appropriate shader is already bound
// assumes modelview matrix is already set
gGL.pushMatrix();
// get raycast in asset space
LLMatrix4a agent_to_asset = getAgentToAssetTransform(obj);
LLVector4a start;
LLVector4a end;
agent_to_asset.affineTransform(gDebugRaycastStart, start);
agent_to_asset.affineTransform(gDebugRaycastEnd, end);
for (auto& node : asset->mNodes)
{
Mesh& mesh = asset->mMeshes[node.mMesh];
if (node.mMesh != INVALID_INDEX)
{
gGL.loadMatrix((F32*)node.mRenderMatrix.mMatrix);
// draw bounding box of mesh primitives
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES))
{
gGL.color3f(0.f, 1.f, 1.f);
for (auto& primitive : mesh.mPrimitives)
{
auto* listener = (LLVolumeOctreeListener*) primitive.mOctree->getListener(0);
LLVector4a center = listener->mBounds[0];
LLVector4a size = listener->mBounds[1];
drawBoxOutline(center, size);
}
}
#if 0
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
{
gGL.flush();
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// convert raycast to node local space
LLVector4a local_start;
LLVector4a local_end;
node.mAssetMatrixInv.affineTransform(start, local_start);
node.mAssetMatrixInv.affineTransform(end, local_end);
for (auto& primitive : mesh.mPrimitives)
{
if (primitive.mOctree.notNull())
{
renderOctreeRaycast(local_start, local_end, primitive.mOctree);
}
}
gGL.flush();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
#endif
}
}
gGL.popMatrix();
}
void GLTFSceneManager::renderDebug()
{
if (!gPipeline.hasRenderDebugMask(
LLPipeline::RENDER_DEBUG_BBOXES |
LLPipeline::RENDER_DEBUG_RAYCAST))
{
return;
}
gDebugProgram.bind();
LLGLDisable cullface(GL_CULL_FACE);
LLGLEnable blend(GL_BLEND);
gGL.setSceneBlendType(LLRender::BT_ALPHA);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
gPipeline.disableLights();
for (auto& obj : mObjects)
{
if (obj->isDead() || obj->mGLTFAsset == nullptr)
{
continue;
}
Asset* asset = obj->mGLTFAsset;
LLMatrix4a mat = getAssetToAgentTransform(obj);
LLMatrix4a modelview;
modelview.loadu(gGLModelView);
matMul(mat, modelview, modelview);
asset->updateRenderTransforms(modelview);
renderAssetDebug(obj, asset);
}
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
{
S32 node_hit = -1;
S32 primitive_hit = -1;
LLVector4a intersection;
LLDrawable* drawable = lineSegmentIntersect(gDebugRaycastStart, gDebugRaycastEnd, TRUE, TRUE, TRUE, TRUE, &node_hit, &primitive_hit, &intersection, nullptr, nullptr, nullptr);
if (drawable)
{
gGL.pushMatrix();
Asset* asset = drawable->getVObj()->mGLTFAsset;
Node* node = &asset->mNodes[node_hit];
Primitive* primitive = &asset->mMeshes[node->mMesh].mPrimitives[primitive_hit];
gGL.flush();
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
gGL.color3f(1, 0, 1);
drawBoxOutline(intersection, LLVector4a(0.1f, 0.1f, 0.1f, 0.f));
gGL.loadMatrix((F32*) node->mRenderMatrix.mMatrix);
auto* listener = (LLVolumeOctreeListener*) primitive->mOctree->getListener(0);
drawBoxOutline(listener->mBounds[0], listener->mBounds[1]);
gGL.flush();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
gGL.popMatrix();
}
}
gDebugProgram.unbind();
}

View File

@ -0,0 +1,64 @@
#pragma once
/**
* @file gltfscenemanager.h
* @brief Builds menus out of items.
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2024, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llsingleton.h"
#include "llviewerobject.h"
namespace LL
{
class GLTFSceneManager : public LLSimpleton<GLTFSceneManager>
{
public:
~GLTFSceneManager();
// load GLTF file from disk
void load(); // open filepicker to choose asset
void load(const std::string& filename); // load asset from filename
void renderOpaque();
LLDrawable* lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
BOOL pick_transparent,
BOOL pick_rigged,
BOOL pick_unselectable,
BOOL pick_reflection_probe,
S32* node_hit, // return the index of the node that was hit
S32* primitive_hit, // return the index of the primitive that was hit
LLVector4a* intersection, // return the intersection point
LLVector2* tex_coord, // return the texture coordinates of the intersection point
LLVector4a* normal, // return the surface normal at the intersection point
LLVector4a* tangent); // return the surface tangent at the intersection point
bool lineSegmentIntersect(LLVOVolume* obj, GLTF::Asset* asset, const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, BOOL pick_rigged, BOOL pick_unselectable, S32* face_hitp, S32* primitive_hitp,
LLVector4a* intersection, LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent);
void renderDebug();
std::vector<LLPointer<LLViewerObject>> mObjects;
};
}

View File

@ -25,6 +25,7 @@
#include "llviewerprecompiledheaders.h"
#include "llagentbenefits.h"
#include "llviewertexture.h"
// <FS:Ansariel> OpenSim legacy economy
#include "llagent.h"
@ -45,7 +46,6 @@ LLAgentBenefits::LLAgentBenefits():
m_picks_limit(-1),
m_sound_upload_cost(-1),
m_texture_upload_cost(-1),
m_2k_texture_upload_cost(-1),
m_create_group_cost(-1)
{
}
@ -106,7 +106,26 @@ bool LLAgentBenefits::init(const LLSD& benefits_sd)
{
return false;
}
get_required_S32(benefits_sd, "large_texture_upload_cost", m_2k_texture_upload_cost);
if (benefits_sd.has("large_texture_upload_cost"))
{
LLSD large_texture_cost = benefits_sd.get("large_texture_upload_cost");
if (large_texture_cost.isArray())
{
LLSD::array_const_iterator end = large_texture_cost.endArray();
LLSD::array_const_iterator it = large_texture_cost.beginArray();
for (; it != end; ++it)
{
m_2k_texture_upload_cost.push_back(it->asInteger());
}
std::sort(m_2k_texture_upload_cost.begin(), m_2k_texture_upload_cost.end());
}
}
if (m_2k_texture_upload_cost.empty())
{
m_2k_texture_upload_cost.push_back(m_texture_upload_cost);
}
// FIXME PREMIUM - either use this field or get rid of it
m_initalized = true;
@ -221,9 +240,60 @@ S32 LLAgentBenefits::getTextureUploadCost() const
// </FS:Ansariel>
}
S32 LLAgentBenefits::get2KTextureUploadCost() const
S32 LLAgentBenefits::getTextureUploadCost(const LLViewerTexture* tex) const
{
return m_2k_texture_upload_cost;
if (tex)
{
S32 area = tex->getFullHeight() * tex->getFullWidth();
if (area >= MIN_2K_TEXTURE_AREA)
{
return get2KTextureUploadCost(area);
}
else
{
return getTextureUploadCost();
}
}
return getTextureUploadCost();
}
S32 LLAgentBenefits::getTextureUploadCost(const LLImageBase* tex) const
{
if (tex)
{
S32 area = tex->getHeight() * tex->getWidth();
if (area >= MIN_2K_TEXTURE_AREA)
{
return get2KTextureUploadCost(area);
}
else
{
return getTextureUploadCost();
}
}
return getTextureUploadCost();
}
S32 LLAgentBenefits::get2KTextureUploadCost(S32 area) const
{
if (m_2k_texture_upload_cost.empty())
{
return m_texture_upload_cost;
}
const S32 TEXTURE_SEGMENTS = 1024;
if (m_2k_texture_upload_cost.size() == TEXTURE_SEGMENTS)
{
S32 index = (S32)llceil(sqrt((F32)area));
// 1..1024 pixels uses m_texture_upload_cost
// 1025..2048 uses m_2k_texture_upload_cost
// Translate 1025..2048 to 0..1023 of the
// cost array
const S32 PIXELS_TO_2K_ARRAY_TRANLATE = 1025;
index -= PIXELS_TO_2K_ARRAY_TRANLATE;
index = llclamp(index, 0, TEXTURE_SEGMENTS - 1);
return m_2k_texture_upload_cost[index];
}
return m_2k_texture_upload_cost[0];
}
bool LLAgentBenefits::findUploadCost(LLAssetType::EType& asset_type, S32& cost) const

View File

@ -30,6 +30,9 @@
#include "llsd.h"
#include "llassettype.h"
class LLViewerTexture;
class LLImageBase;
class LLAgentBenefits
{
public:
@ -49,7 +52,9 @@ public:
S32 getPicksLimit() const;
S32 getSoundUploadCost() const;
S32 getTextureUploadCost() const;
S32 get2KTextureUploadCost() const;
S32 getTextureUploadCost(const LLViewerTexture* tex) const;
S32 getTextureUploadCost(const LLImageBase* tex) const;
S32 get2KTextureUploadCost(S32 area) const;
bool findUploadCost(LLAssetType::EType& asset_type, S32& cost) const;
@ -62,7 +67,7 @@ private:
S32 m_picks_limit;
S32 m_sound_upload_cost;
S32 m_texture_upload_cost;
S32 m_2k_texture_upload_cost;
std::vector<S32> m_2k_texture_upload_cost;
bool m_initalized;
};

View File

@ -256,6 +256,8 @@
#include "llavatariconctrl.h"
#include "llgroupiconctrl.h"
#include "llviewerassetstats.h"
#include "gltfscenemanager.h"
#include "workqueue.h"
using namespace LL;
@ -1484,6 +1486,8 @@ bool LLAppViewer::init()
LLWorld::createInstance();
LLSelectMgr::createInstance();
LLViewerCamera::createInstance();
LL::GLTFSceneManager::createInstance();
#if LL_WINDOWS
if (!mSecondInstance)
@ -2515,7 +2519,7 @@ bool LLAppViewer::cleanup()
ll_close_fail_log();
LLError::LLCallStacks::cleanup();
LL::GLTFSceneManager::deleteSingleton();
LLEnvironment::deleteSingleton();
LLSelectMgr::deleteSingleton();
LLViewerEventRecorder::deleteSingleton();

View File

@ -30,6 +30,7 @@
#include "lldrawpoolpbropaque.h"
#include "llviewershadermgr.h"
#include "pipeline.h"
#include "gltfscenemanager.h"
LLDrawPoolGLTFPBR::LLDrawPoolGLTFPBR(U32 type) :
LLRenderPass(type)
@ -54,8 +55,11 @@ void LLDrawPoolGLTFPBR::renderDeferred(S32 pass)
llassert(!LLPipeline::sRenderingHUDs);
gDeferredPBROpaqueProgram.bind();
LL::GLTFSceneManager::instance().renderOpaque();
pushGLTFBatches(mRenderType);
gDeferredPBROpaqueProgram.bind(true);
pushRiggedGLTFBatches(mRenderType + 1);
}

View File

@ -293,18 +293,7 @@ void LLFloaterImagePreview::onBtnUpload()
//-----------------------------------------------------------------------------
S32 LLFloaterImagePreview::getExpectedUploadCost() const
{
if (mRawImagep.notNull())
{
if (mRawImagep->getWidth() * mRawImagep->getHeight() >= LLAgentBenefits::MIN_2K_TEXTURE_AREA)
{
return LLAgentBenefitsMgr::current().get2KTextureUploadCost();
}
else
{
return LLAgentBenefitsMgr::current().getTextureUploadCost();
}
}
return 0;
return LLAgentBenefitsMgr::current().getTextureUploadCost(mRawImagep);
}
//-----------------------------------------------------------------------------
@ -591,7 +580,7 @@ bool LLFloaterImagePreview::loadImage(const std::string& src_filename)
return false;
}
raw_image->biasedScaleToPowerOfTwo(1024);
raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
mRawImagep = raw_image;
return true;

View File

@ -243,13 +243,13 @@ void LLGLTFMaterialList::applyOverrideMessage(LLMessageSystem* msg, const std::s
}
}
}
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
// Workaround for server sending empty overrides.
if(cache.mSides.size() > 0)
{
region->cacheFullUpdateGLTFOverride(cache);
LL_DEBUGS("GLTF") << "GLTF Material Override: " << cache.mObjectId << " " << cache.mLocalId << " " << cache.mRegionHandle << " (sides:" << (cache.mSides.size()) << ")" << LL_ENDL;
}
// </FS:Beq>
}
}

View File

@ -64,6 +64,14 @@ LLHeroProbeManager::LLHeroProbeManager()
{
}
LLHeroProbeManager::~LLHeroProbeManager()
{
cleanup();
mHeroVOList.clear();
mNearestHero = nullptr;
}
// helper class to seed octree with probes
void LLHeroProbeManager::update()
{
@ -84,8 +92,7 @@ void LLHeroProbeManager::update()
if (!mRenderTarget.isComplete())
{
U32 color_fmt = GL_RGBA16F;
U32 targetRes = mProbeResolution; // super sample
mRenderTarget.allocate(targetRes, targetRes, color_fmt, true);
mRenderTarget.allocate(mProbeResolution, mProbeResolution, color_fmt, true);
}
if (mMipChain.empty())
@ -472,12 +479,19 @@ void LLHeroProbeManager::renderDebug()
gDebugProgram.unbind();
}
void LLHeroProbeManager::initReflectionMaps()
{
U32 count = LL_MAX_HERO_PROBE_COUNT;
if (mTexture.isNull() || mReflectionProbeCount != count || mReset)
if ((mTexture.isNull() || mReflectionProbeCount != count || mReset) && LLPipeline::RenderMirrors)
{
if (mReset)
{
cleanup();
}
mReset = false;
mReflectionProbeCount = count;
mProbeResolution = gSavedSettings.getS32("RenderHeroProbeResolution");
@ -546,9 +560,8 @@ void LLHeroProbeManager::cleanup()
mDefaultProbe = nullptr;
mUpdatingProbe = nullptr;
mHeroVOList.clear();
mNearestHero = nullptr;
/*
*/
}
void LLHeroProbeManager::doOcclusion()
@ -565,6 +578,11 @@ void LLHeroProbeManager::doOcclusion()
}
}
void LLHeroProbeManager::reset()
{
mReset = true;
}
bool LLHeroProbeManager::registerViewerObject(LLVOVolume* drawablep)
{
llassert(drawablep != nullptr);

View File

@ -60,6 +60,7 @@ public:
// allocate an environment map of the given resolution
LLHeroProbeManager();
~LLHeroProbeManager();
// release any GL state
void cleanup();
@ -77,6 +78,8 @@ public:
// perform occlusion culling on all active reflection probes
void doOcclusion();
void reset();
bool registerViewerObject(LLVOVolume *drawablep);
void unregisterViewerObject(LLVOVolume* drawablep);

View File

@ -492,20 +492,10 @@ BOOL LLMaterialEditor::postBuild()
}
else
{
S32 upload_cost_base = LLAgentBenefitsMgr::current().getTextureUploadCost();
S32 upload_cost_2k = LLAgentBenefitsMgr::current().get2KTextureUploadCost();
bool large_texture = mBaseColorFetched && (mBaseColorFetched->getFullHeight() * mBaseColorFetched->getFullWidth() >= LLAgentBenefits::MIN_2K_TEXTURE_AREA);
getChild<LLUICtrl>("base_color_upload_fee")->setTextArg("[FEE]", llformat("%d", large_texture ? upload_cost_2k : upload_cost_base));
large_texture = mMetallicRoughnessFetched && (mMetallicRoughnessFetched->getFullHeight() * mMetallicRoughnessFetched->getFullWidth() >= LLAgentBenefits::MIN_2K_TEXTURE_AREA);
getChild<LLUICtrl>("metallic_upload_fee")->setTextArg("[FEE]", llformat("%d", large_texture ? upload_cost_2k : upload_cost_base));
large_texture = mEmissiveFetched && (mEmissiveFetched->getFullHeight() * mEmissiveFetched->getFullWidth() >= LLAgentBenefits::MIN_2K_TEXTURE_AREA);
getChild<LLUICtrl>("emissive_upload_fee")->setTextArg("[FEE]", llformat("%d", large_texture ? upload_cost_2k : upload_cost_base));
large_texture = mNormalFetched && (mNormalFetched->getFullHeight() * mNormalFetched->getFullWidth() >= LLAgentBenefits::MIN_2K_TEXTURE_AREA);
getChild<LLUICtrl>("normal_upload_fee")->setTextArg("[FEE]", llformat("%d", large_texture ? upload_cost_2k : upload_cost_base));
getChild<LLUICtrl>("base_color_upload_fee")->setTextArg("[FEE]", llformat("%d", LLAgentBenefitsMgr::current().getTextureUploadCost(mBaseColorFetched)));
getChild<LLUICtrl>("metallic_upload_fee")->setTextArg("[FEE]", llformat("%d", LLAgentBenefitsMgr::current().getTextureUploadCost(mMetallicRoughnessFetched)));
getChild<LLUICtrl>("emissive_upload_fee")->setTextArg("[FEE]", llformat("%d", LLAgentBenefitsMgr::current().getTextureUploadCost(mEmissiveFetched)));
getChild<LLUICtrl>("normal_upload_fee")->setTextArg("[FEE]", llformat("%d", LLAgentBenefitsMgr::current().getTextureUploadCost(mNormalFetched)));
}
boost::function<void(LLUICtrl*, void*)> changes_callback = [this](LLUICtrl * ctrl, void* userData)
@ -854,60 +844,24 @@ void LLMaterialEditor::markChangesUnsaved(U32 dirty_flag)
setCanSave(false);
}
S32 upload_texture_count = 0;
S32 upload_2k_texture_count = 0;
mExpectedUploadCost = 0;
if (mBaseColorTextureUploadId.notNull() && mBaseColorTextureUploadId == getBaseColorId() && mBaseColorFetched)
{
if (mBaseColorFetched->getFullHeight() * mBaseColorFetched->getFullWidth() >= LLAgentBenefits::MIN_2K_TEXTURE_AREA)
{
upload_2k_texture_count++;
}
else
{
upload_texture_count++;
}
mExpectedUploadCost += LLAgentBenefitsMgr::current().getTextureUploadCost(mBaseColorFetched);
}
if (mMetallicTextureUploadId.notNull() && mMetallicTextureUploadId == getMetallicRoughnessId() && mMetallicRoughnessFetched)
{
if (mMetallicRoughnessFetched->getFullHeight() * mMetallicRoughnessFetched->getFullWidth() >= LLAgentBenefits::MIN_2K_TEXTURE_AREA)
{
upload_2k_texture_count++;
}
else
{
upload_texture_count++;
}
mExpectedUploadCost += LLAgentBenefitsMgr::current().getTextureUploadCost(mMetallicRoughnessFetched);
}
if (mEmissiveTextureUploadId.notNull() && mEmissiveTextureUploadId == getEmissiveId() && mEmissiveFetched)
{
if (mEmissiveFetched->getFullHeight() * mEmissiveFetched->getFullWidth() >= LLAgentBenefits::MIN_2K_TEXTURE_AREA)
{
upload_2k_texture_count++;
}
else
{
upload_texture_count++;
}
mExpectedUploadCost += LLAgentBenefitsMgr::current().getTextureUploadCost(mEmissiveFetched);
}
if (mNormalTextureUploadId.notNull() && mNormalTextureUploadId == getNormalId() && mNormalFetched)
{
if (mNormalFetched->getFullHeight() * mNormalFetched->getFullWidth() >= LLAgentBenefits::MIN_2K_TEXTURE_AREA)
{
upload_2k_texture_count++;
}
else
{
upload_texture_count++;
}
mExpectedUploadCost += LLAgentBenefitsMgr::current().getTextureUploadCost(mNormalFetched);
}
mExpectedUploadCost = upload_texture_count * LLAgentBenefitsMgr::current().getTextureUploadCost();
S32 cost_2k = LLAgentBenefitsMgr::current().get2KTextureUploadCost();
if (cost_2k < 0)
{
cost_2k = 0;
}
mExpectedUploadCost += upload_2k_texture_count * cost_2k;
getChild<LLUICtrl>("total_upload_fee")->setTextArg("[FEE]", llformat("%d", mExpectedUploadCost));
}
@ -3553,12 +3507,7 @@ void LLMaterialEditor::saveTexture(LLImageJ2C* img, const std::string& name, con
std::string buffer;
buffer.assign((const char*) img->getData(), img->getDataSize());
U32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost();
if (img->getWidth() * img->getHeight() >= LLAgentBenefits::MIN_2K_TEXTURE_AREA)
{
expected_upload_cost = LLAgentBenefitsMgr::current().get2KTextureUploadCost();
}
U32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(img);
LLSD key = getKey();
std::function<bool(LLUUID itemId, LLSD response, std::string reason)> failed_upload([key](LLUUID assetId, LLSD response, std::string reason)
{

View File

@ -2969,10 +2969,8 @@ void renderLights(LLDrawable* drawablep)
class LLRenderOctreeRaycast : public LLOctreeTriangleRayIntersect
{
public:
LLRenderOctreeRaycast(const LLVector4a& start, const LLVector4a& dir, F32* closest_t)
: LLOctreeTriangleRayIntersect(start, dir, NULL, closest_t, NULL, NULL, NULL, NULL)
: LLOctreeTriangleRayIntersect(start, dir, nullptr, closest_t, NULL, NULL, NULL, NULL)
{
}
@ -2996,7 +2994,7 @@ public:
size.set(vl->mBounds[1].getF32ptr());
}
drawBoxOutline(center, size);
drawBoxOutline(center, size);
for (U32 i = 0; i < 2; i++)
{
@ -3040,6 +3038,13 @@ public:
}
};
void renderOctreeRaycast(const LLVector4a& start, const LLVector4a& end, const LLVolumeOctree* octree)
{
F32 t = 1.f;
LLRenderOctreeRaycast render(start, end, &t);
render.traverse(octree);
}
void renderRaycast(LLDrawable* drawablep)
{
if (drawablep->getNumFaces())
@ -3097,33 +3102,22 @@ void renderRaycast(LLDrawable* drawablep)
dir.setSub(end, start);
gGL.flush();
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
{
//render face positions
// <FS:Ansariel> Use a vbo for the static LLVertexBuffer::drawArray/Element functions; by Drake Arconis/Shyotl Kuhr
//LLVertexBuffer::unbind();
//gGL.diffuseColor4f(0, 1, 1, 0.5f);
//glVertexPointer(3, GL_FLOAT, sizeof(LLVector4a), face.mPositions);
//gGL.syncMatrices();
//glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices);
gGL.diffuseColor4f(0.f, 1.f, 1.f, 0.5f);
LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mPositions, NULL, face.mNumIndices, face.mIndices);
// </FS:Ansariel>
//gGL.diffuseColor4f(0,1,1,0.5f);
//LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mPositions, nullptr, face.mNumIndices, face.mIndices);
}
if (!volume->isUnique())
{
F32 t = 1.f;
if (!face.getOctree())
{
((LLVolumeFace*) &face)->createOctree();
}
LLRenderOctreeRaycast render(start, dir, &t);
render.traverse(face.getOctree());
renderOctreeRaycast(start, end, face.getOctree());
}
gGL.popMatrix();

View File

@ -147,7 +147,7 @@ const tinygltf::Image * LLTinyGLTFHelper::getImageFromTextureIndex(const tinyglt
return nullptr;
}
LLImageRaw * LLTinyGLTFHelper::getTexture(const std::string & folder, const tinygltf::Model & model, S32 texture_index, std::string & name)
LLImageRaw * LLTinyGLTFHelper::getTexture(const std::string & folder, const tinygltf::Model & model, S32 texture_index, std::string & name, bool flip)
{
const tinygltf::Image* image = getImageFromTextureIndex(model, texture_index);
LLImageRaw* rawImage = nullptr;
@ -159,14 +159,17 @@ LLImageRaw * LLTinyGLTFHelper::getTexture(const std::string & folder, const tiny
{
name = image->name;
rawImage = new LLImageRaw(&image->image[0], image->width, image->height, image->component);
rawImage->verticalFlip();
if (flip)
{
rawImage->verticalFlip();
}
rawImage->optimizeAwayAlpha();
}
return rawImage;
}
LLImageRaw * LLTinyGLTFHelper::getTexture(const std::string & folder, const tinygltf::Model & model, S32 texture_index)
LLImageRaw * LLTinyGLTFHelper::getTexture(const std::string & folder, const tinygltf::Model & model, S32 texture_index, bool flip)
{
const tinygltf::Image* image = getImageFromTextureIndex(model, texture_index);
LLImageRaw* rawImage = nullptr;
@ -177,7 +180,10 @@ LLImageRaw * LLTinyGLTFHelper::getTexture(const std::string & folder, const tiny
image->component <= 4)
{
rawImage = new LLImageRaw(&image->image[0], image->width, image->height, image->component);
rawImage->verticalFlip();
if (flip)
{
rawImage->verticalFlip();
}
rawImage->optimizeAwayAlpha();
}
@ -237,7 +243,8 @@ bool LLTinyGLTFHelper::getMaterialFromModel(
const tinygltf::Model& model_in,
S32 mat_index,
LLFetchedGLTFMaterial* material,
std::string& material_name)
std::string& material_name,
bool flip)
{
llassert(material);
@ -256,18 +263,18 @@ bool LLTinyGLTFHelper::getMaterialFromModel(
material_name = material_in.name;
// get base color texture
LLPointer<LLImageRaw> base_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.baseColorTexture.index);
LLPointer<LLImageRaw> base_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.baseColorTexture.index, flip);
// get normal map
LLPointer<LLImageRaw> normal_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.normalTexture.index);
LLPointer<LLImageRaw> normal_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.normalTexture.index, flip);
// get metallic-roughness texture
LLPointer<LLImageRaw> mr_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.metallicRoughnessTexture.index);
LLPointer<LLImageRaw> mr_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.metallicRoughnessTexture.index, flip);
// get emissive texture
LLPointer<LLImageRaw> emissive_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.emissiveTexture.index);
LLPointer<LLImageRaw> emissive_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.emissiveTexture.index, flip);
// get occlusion map if needed
LLPointer<LLImageRaw> occlusion_img;
if (material_in.occlusionTexture.index != material_in.pbrMetallicRoughness.metallicRoughnessTexture.index)
{
occlusion_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.occlusionTexture.index);
occlusion_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.occlusionTexture.index, flip);
}
LLPointer<LLViewerFetchedTexture> base_color_tex;

View File

@ -38,10 +38,8 @@ namespace LLTinyGLTFHelper
{
LLColor4 getColor(const std::vector<double>& in);
const tinygltf::Image* getImageFromTextureIndex(const tinygltf::Model& model, S32 texture_index);
LLImageRaw* getTexture(const std::string& folder, const tinygltf::Model& model, S32 texture_index, std::string& name);
LLImageRaw* getTexture(const std::string& folder, const tinygltf::Model& model, S32 texture_index);
LLImageRaw* getTexture(const std::string& folder, const tinygltf::Model& model, S32 texture_index);
LLImageRaw* getTexture(const std::string& folder, const tinygltf::Model& model, S32 texture_index, std::string& name, bool flip = true);
LLImageRaw* getTexture(const std::string& folder, const tinygltf::Model& model, S32 texture_index, bool flip = true);
bool loadModel(const std::string& filename, tinygltf::Model& model_out);
@ -50,7 +48,8 @@ namespace LLTinyGLTFHelper
const tinygltf::Model& model,
S32 mat_index,
LLFetchedGLTFMaterial* material,
std::string& material_name);
std::string& material_name,
bool flip = true);
void initFetchedTextures(tinygltf::Material& material,
LLPointer<LLImageRaw>& base_color_img,

View File

@ -162,9 +162,9 @@ LLSD LLResourceUploadInfo::generatePostBody()
body["next_owner_mask"] = LLSD::Integer(mNextOwnerPerms);
body["group_mask"] = LLSD::Integer(mGroupPerms);
body["everyone_mask"] = LLSD::Integer(mEveryonePerms);
body["expected_upload_cost"] = mExpectedUploadCost;
return body;
}
void LLResourceUploadInfo::logPreparedUpload()

View File

@ -543,6 +543,19 @@ static bool handleReflectionProbeDetailChanged(const LLSD& newvalue)
gPipeline.createGLBuffers();
LLViewerShaderMgr::instance()->setShaders();
gPipeline.mReflectionMapManager.reset();
gPipeline.mHeroProbeManager.reset();
}
return true;
}
static bool handleHeroProbeResolutionChanged(const LLSD &newvalue)
{
if (gPipeline.isInit())
{
LLPipeline::refreshCachedSettings();
gPipeline.mHeroProbeManager.reset();
gPipeline.releaseGLBuffers();
gPipeline.createGLBuffers();
}
return true;
}
@ -1218,6 +1231,7 @@ void settings_setup_listeners()
setting_setup_signal_listener(gSavedSettings, "RenderReflectionProbeDetail", handleReflectionProbeDetailChanged);
// setting_setup_signal_listener(gSavedSettings, "RenderReflectionsEnabled", handleReflectionsEnabled); // <FS:Beq/> FIRE-33659 better way to enable/disable reflections
setting_setup_signal_listener(gSavedSettings, "RenderScreenSpaceReflections", handleReflectionProbeDetailChanged);
setting_setup_signal_listener(gSavedSettings, "RenderHeroProbeResolution", handleHeroProbeResolutionChanged);
setting_setup_signal_listener(gSavedSettings, "RenderShadowDetail", handleSetShaderChanged);
setting_setup_signal_listener(gSavedSettings, "RenderDeferredSSAO", handleSetShaderChanged);
setting_setup_signal_listener(gSavedSettings, "RenderPerformanceTest", handleRenderPerfTestChanged);

View File

@ -144,6 +144,7 @@
#include <boost/algorithm/string.hpp>
#include "llcleanup.h"
#include "llviewershadermgr.h"
#include "gltfscenemanager.h"
// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
#include "fsavatarrenderpersistence.h"
#include "rlvactions.h"
@ -9919,6 +9920,17 @@ class LLAdvancedClickHDRIPreview: public view_listener_t
}
};
class LLAdvancedClickGLTFScenePreview : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
// open personal lighting floater when previewing an HDRI (keeps HDRI from implicitly unloading when opening build tools)
LL::GLTFSceneManager::instance().load();
return true;
}
};
// these are used in the gl menus to set control values that require shader recompilation
class LLToggleShaderControl : public view_listener_t
{
@ -12367,6 +12379,7 @@ void initialize_menus()
view_listener_t::addMenu(new LLAdvancedClickRenderProfile(), "Advanced.ClickRenderProfile");
view_listener_t::addMenu(new LLAdvancedClickRenderBenchmark(), "Advanced.ClickRenderBenchmark");
view_listener_t::addMenu(new LLAdvancedClickHDRIPreview(), "Advanced.ClickHDRIPreview");
view_listener_t::addMenu(new LLAdvancedClickGLTFScenePreview(), "Advanced.ClickGLTFScenePreview");
view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache");
view_listener_t::addMenu(new LLAdvancedRebuildTerrain(), "Advanced.RebuildTerrain");
//[FIX FIRE-1927 - enable DoubleClickTeleport shortcut : SJ]

View File

@ -571,19 +571,8 @@ void do_bulk_upload(std::vector<std::string> filenames, const LLSD& notification
LLPointer<LLImageFormatted> image_frmted = LLImageFormatted::createFromType(codec);
if (gDirUtilp->fileExists(filename) && image_frmted->load(filename))
{
if (image_frmted->getWidth() * image_frmted->getHeight() >= LLAgentBenefits::MIN_2K_TEXTURE_AREA)
{
expected_upload_cost = LLAgentBenefitsMgr::current().get2KTextureUploadCost();
if (expected_upload_cost >= 0)
{
resource_upload = true;
}
}
else
{
expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost();
resource_upload = true;
}
expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(image_frmted);
resource_upload = true;
}
}
else if (LLAgentBenefitsMgr::current().findUploadCost(asset_type, expected_upload_cost))
@ -632,8 +621,6 @@ bool get_bulk_upload_expected_cost(const std::vector<std::string>& filenames, S3
total_cost = 0;
file_count = 0;
bvh_count = 0;
S32 texture_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost();
S32 texture_2k_upload_cost = LLAgentBenefitsMgr::current().get2KTextureUploadCost();
for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter)
{
std::string filename = (*in_iter);
@ -655,19 +642,8 @@ bool get_bulk_upload_expected_cost(const std::vector<std::string>& filenames, S3
LLPointer<LLImageFormatted> image_frmted = LLImageFormatted::createFromType(codec);
if (gDirUtilp->fileExists(filename) && image_frmted->load(filename))
{
if (image_frmted->getWidth() * image_frmted->getHeight() >= LLAgentBenefits::MIN_2K_TEXTURE_AREA)
{
if (texture_2k_upload_cost >= 0)
{
total_cost += texture_2k_upload_cost;
file_count++;
}
}
else
{
total_cost += texture_upload_cost;
file_count++;
}
total_cost += LLAgentBenefitsMgr::current().getTextureUploadCost(image_frmted);
file_count++;
}
}
else if (LLAgentBenefitsMgr::current().findUploadCost(asset_type, cost))
@ -695,53 +671,22 @@ bool get_bulk_upload_expected_cost(const std::vector<std::string>& filenames, S3
{
// Todo: make it account for possibility of same texture in different
// materials and even in scope of same material
S32 texture_count = 0;
S32 texture_2k_count = 0;
if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR].notNull() && material->mBaseColorTexture)
{
if (material->mBaseColorTexture->getFullHeight() * material->mBaseColorTexture->getFullWidth() >= LLAgentBenefits::MIN_2K_TEXTURE_AREA)
{
texture_2k_count++;
}
else
{
texture_count++;
}
total_cost += LLAgentBenefitsMgr::current().getTextureUploadCost(material->mBaseColorTexture);
}
if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].notNull() && material->mMetallicRoughnessTexture)
{
if (material->mMetallicRoughnessTexture->getFullHeight() * material->mMetallicRoughnessTexture->getFullWidth() >= LLAgentBenefits::MIN_2K_TEXTURE_AREA)
{
texture_2k_count++;
}
else
{
texture_count++;
}
total_cost += LLAgentBenefitsMgr::current().getTextureUploadCost(material->mMetallicRoughnessTexture);
}
if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL].notNull() && material->mNormalTexture)
{
if (material->mNormalTexture->getFullHeight() * material->mNormalTexture->getFullWidth() >= LLAgentBenefits::MIN_2K_TEXTURE_AREA)
{
texture_2k_count++;
}
else
{
texture_count++;
}
total_cost += LLAgentBenefitsMgr::current().getTextureUploadCost(material->mNormalTexture);
}
if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE].notNull() && material->mEmissiveTexture)
{
if (material->mEmissiveTexture->getFullHeight() * material->mEmissiveTexture->getFullWidth() >= LLAgentBenefits::MIN_2K_TEXTURE_AREA)
{
texture_2k_count++;
}
else
{
texture_count++;
}
total_cost += LLAgentBenefitsMgr::current().getTextureUploadCost(material->mEmissiveTexture);
}
total_cost += texture_count * texture_upload_cost + texture_2k_count * texture_2k_upload_cost;
file_count++;
}
}

View File

@ -45,6 +45,7 @@
#include "llbbox.h"
#include "llrigginginfo.h"
#include "llreflectionmap.h"
#include "gltf/asset.h"
#include "fsregioncross.h" // <FS:JN> Improved region crossing support
@ -739,6 +740,8 @@ public:
F32 mPhysicsDensity;
F32 mPhysicsRestitution;
// Associated GLTF Asset
LLPointer<LL::GLTF::Asset> mGLTFAsset;
// Pipeline classes
LLPointer<LLDrawable> mDrawable;

View File

@ -844,13 +844,9 @@ void LLViewerRegion::loadObjectCache()
if(LLVOCache::instanceExists())
{
LLVOCache & vocache = LLVOCache::instance();
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
// vocache.readFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap);
// vocache.readGenericExtrasFromCache(mHandle, mImpl->mCacheID, mImpl->mGLTFOverridesLLSD);
// mark as dirty if read fails to force a rewrite.
// Without this a "corrupted" vocache persists until a cache clear or other rewrite. Mark as dirty hereif read fails to force a rewrite.
mCacheDirty = !vocache.readFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap);
vocache.readGenericExtrasFromCache(mHandle, mImpl->mCacheID, mImpl->mGLTFOverridesLLSD, mImpl->mCacheMap);
// </FS:Beq>
if (mImpl->mCacheMap.empty())
{
@ -1256,17 +1252,13 @@ void LLViewerRegion::killCacheEntry(LLVOCacheEntry* entry, bool for_rendering)
child = entry->getChild();
}
}
// <FS:Beq> Fix the missing kill on overrides
// Kill the assocaited overrides
mImpl->mGLTFOverridesLLSD.erase(entry->getLocalID());
// </FS:Beq>
//will remove it from the object cache, real deletion
entry->setState(LLVOCacheEntry::INACTIVE);
entry->removeOctreeEntry();
entry->setValid(FALSE);
// <FS:Beq/> Fix the missing kill on overrides
// // TODO kill extras/material overrides cache too
}
//physically delete the cache entry
@ -4021,12 +4013,11 @@ void LLViewerRegion::applyCacheMiscExtras(LLViewerObject* obj)
auto iter = mImpl->mGLTFOverridesLLSD.find(local_id);
if (iter != mImpl->mGLTFOverridesLLSD.end())
{
// <FS:Beq> backfill the UUID if it was left empty
// UUID can be inserted null, so backfill the UUID if it was left empty
if (iter->second.mObjectId.isNull())
{
iter->second.mObjectId = obj->getID();
}
// </FS:Beq>
llassert(iter->second.mGLTFMaterial.size() == iter->second.mSides.size());
for (auto& side : iter->second.mGLTFMaterial)

View File

@ -69,6 +69,11 @@ namespace
if (!tex) { return; }
tex->setBoostLevel(LLGLTexture::BOOST_NONE);
tex->setMinDiscardLevel(MAX_DISCARD_LEVEL + 1);
if (tex->getTextureState() == LLGLTexture::NO_DELETE)
{
tex->forceActive();
}
}
void unboost_minimap_material(LLPointer<LLFetchedGLTFMaterial>& mat)
@ -91,6 +96,11 @@ LLTerrainMaterials::LLTerrainMaterials()
LLTerrainMaterials::~LLTerrainMaterials()
{
for (S32 i = 0; i < ASSET_COUNT; ++i)
{
unboost_minimap_texture(mDetailTextures[i]);
unboost_minimap_material(mDetailMaterials[i]);
}
}
BOOL LLTerrainMaterials::generateMaterials()
@ -131,6 +141,12 @@ LLPointer<LLViewerFetchedTexture> fetch_terrain_texture(const LLUUID& id)
void LLTerrainMaterials::setDetailAssetID(S32 asset, const LLUUID& id)
{
// *NOTE: If there were multiple terrain swatches using the same asset
// ID, the asset still in use will be temporarily unboosted.
// It will be boosted again during terrain rendering.
unboost_minimap_texture(mDetailTextures[asset]);
unboost_minimap_material(mDetailMaterials[asset]);
// This is terrain texture, but we are not setting it as BOOST_TERRAIN
// since we will be manipulating it later as needed.
mDetailTextures[asset] = fetch_terrain_texture(id);

View File

@ -1481,7 +1481,7 @@ void LLVOAvatarSelf::updateAttachmentVisibility(U32 camera_mode)
switch (camera_mode)
{
case CAMERA_MODE_MOUSELOOK:
if (LLVOAvatar::sVisibleInFirstPerson && attachment->getVisibleInFirstPerson())
if ((LLVOAvatar::sVisibleInFirstPerson && attachment->getVisibleInFirstPerson()) || gPipeline.mHeroProbeManager.isMirrorPass())
{
// [RLVa:KB] - Checked: RLVa-2.0.2
attachment->setAttachmentVisibility(fRlvCanShowAttachment);

View File

@ -34,7 +34,7 @@
#include "llagentcamera.h"
#include "llsdserialize.h"
#include "llagent.h" // <FS:Beq/> For gAgent
#include "llworld.h" // <FS:Beq/> For LLWorld::getInstance()
#include "llworld.h" // For LLWorld::getInstance()
//static variables
U32 LLVOCacheEntry::sMinFrameRange = 0;
@ -56,10 +56,10 @@ BOOL check_write(LLAPRFile* apr_file, void* src, S32 n_bytes)
{
return apr_file->write(src, n_bytes) == n_bytes ;
}
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
// Material Override Cache needs a version label, so we can upgrade this later.
const std::string LLGLTFOverrideCacheEntry::VERSION_LABEL = {"GLTFCacheVer"};
const int LLGLTFOverrideCacheEntry::VERSION = 1;
// </FS:Beq>
bool LLGLTFOverrideCacheEntry::fromLLSD(const LLSD& data)
{
@ -241,7 +241,7 @@ LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
}
else
{
// <FS:Beq/> improve logging around vocache
// Improve logging around vocache
LL_WARNS() << "Error loading cache entry for " << mLocalID << ", size " << size << " aborting!" << LL_ENDL;
delete[] mBuffer ;
mBuffer = NULL ;
@ -1296,11 +1296,10 @@ void LLVOCache::removeEntry(HeaderEntryInfo* entry)
{
return;
}
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
// Bit more tracking of cache creation/destruction.
std::string filename;
getObjectCacheFilename(entry->mHandle, filename);
LL_INFOS() << "Removing entry for region with filename" << filename << LL_ENDL;
// </FS:Beq>
header_entry_queue_t::iterator iter = mHeaderEntryQueue.find(entry);
if(iter != mHeaderEntryQueue.end())
@ -1371,11 +1370,10 @@ void LLVOCache::removeFromCache(HeaderEntryInfo* entry)
std::string filename;
getObjectCacheFilename(entry->mHandle, filename);
LLAPRFile::remove(filename, mLocalAPRFilePoolp);
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
// Note that removeFromCache should take responsibility for cleaning up all cache artefactgs specfic to the handle/entry.
// Note: `removeFromCache` should take responsibility for cleaning up all cache artefacts specfic to the handle/entry.
// as such this now includes the generic extras
removeGenericExtrasForHandle(entry->mHandle);
// </FS:Beq>
entry->mTime = INVALID_TIME ;
updateEntry(entry) ; //update the head file.
}
@ -1524,17 +1522,15 @@ BOOL LLVOCache::updateEntry(const HeaderEntryInfo* entry)
return check_write(&apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ;
}
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
// void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map)
// we now return bool to trigger dirty cache
// and force a rewrite after a partial read due to corruption.
// this in turn forces a rewrite after a partial read due to corruption.
bool LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map)
// </FS:Beq>
{
if(!mEnabled)
{
LL_WARNS() << "Not reading cache for handle " << handle << "): Cache is currently disabled." << LL_ENDL;
return true; // <FS:Beq/> FIRE-33808 - Material Override Cache causes long delays
return true; // no problem we're just read only
}
llassert_always(mInitialized);
@ -1542,12 +1538,12 @@ bool LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca
if(iter == mHandleEntryMap.end()) //no cache
{
LL_WARNS() << "No handle map entry for " << handle << LL_ENDL;
return false; // <FS:Beq/> FIRE-33808 - Material Override Cache causes long delays
return false; // arguably no a problem, but we'll mark this as dirty anyway.
}
bool success = true ;
S32 num_entries=0; // <FS:Beq/> FIRE-33808 - Material Override Cache causes long delays
std::string filename;
S32 num_entries = 0 ; // lifted out of inner loop.
std::string filename; // lifted out of loop
{
LLUUID cache_id;
getObjectCacheFilename(handle, filename);
@ -1565,7 +1561,6 @@ bool LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca
if(success)
{
// S32 num_entries; // if removal was enabled during write num_entries might be wrong
success = check_read(&apr_file, &num_entries, sizeof(S32)) ;
if(success)
@ -1576,7 +1571,7 @@ bool LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca
if (!entry->getLocalID())
{
LL_WARNS() << "Aborting cache file load for " << filename << ", cache file corruption!" << LL_ENDL;
success = false ;
success = false ;
break ;
}
cache_entry_map[entry->getLocalID()] = entry;
@ -1592,24 +1587,19 @@ bool LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca
{
removeEntry(iter->second) ;
}
}
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
// return ;
LL_DEBUGS("GLTF", "VOCache") << "Read " << cache_entry_map.size() << " entries from object cache " << filename << ", expected " << num_entries << ", success=" << (success?"True":"False") << LL_ENDL;
return success;
// </FS:Beq>
}
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
// void LLVOCache::readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map)
// We now pass in the cache entry map, so that we can remove entries from extras that are no longer in the primary cache.
void LLVOCache::readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map)
{
int loaded= 0;
int discarded = 0;
// get ViewerRegion pointer from handle
LLViewerRegion* pRegion = LLWorld::getInstance()->getRegionFromHandle(handle);
// </FS:Beq>
int loaded= 0;
int discarded = 0;
// get ViewerRegion pointer from handle
LLViewerRegion* pRegion = LLWorld::getInstance()->getRegionFromHandle(handle);
if(!mEnabled)
{
LL_WARNS() << "Not reading cache for handle " << handle << "): Cache is currently disabled." << LL_ENDL;
@ -1629,71 +1619,72 @@ void LLVOCache::readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCac
std::string line;
std::getline(in, line);
if(!in.good()) {
if(!in.good())
{
LL_WARNS() << "Failed reading extras cache for handle " << handle << LL_ENDL;
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
in.close();
removeGenericExtrasForHandle(handle);
// </FS:Beq>
return;
}
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
// file formats need versions, let's add one. legacy cache files will be considered version 0
// This will make it easier to upgrade/revise later.
int versionNumber=0;
if (line.compare(0, LLGLTFOverrideCacheEntry::VERSION_LABEL.length(), LLGLTFOverrideCacheEntry::VERSION_LABEL) == 0)
{
std::string versionStr = line.substr(LLGLTFOverrideCacheEntry::VERSION_LABEL.length()+1); // skip the version label and ':'
versionNumber = std::stol(versionStr);
std::getline(in, line); // read the next line for the region UUID check
}
// </FS:Beq>
// For future versions we may call a legacy handler here, but realistically we'll just consider this cache out of date.
// The important thing is to make sure it gets removed.
if(versionNumber != LLGLTFOverrideCacheEntry::VERSION && versionNumber != 0)
{
LL_WARNS() << "Unexpected version number " << versionNumber << " for extras cache for handle " << handle << LL_ENDL;
in.close();
removeGenericExtrasForHandle(handle);
return;
}
LL_DEBUGS("VOCache") << "Reading extras cache for handle " << handle << ", version " << versionNumber << LL_ENDL;
if(!LLUUID::validate(line))
{
LL_WARNS() << "Failed reading extras cache for handle" << handle << ". invalid uuid line: '" << line << "'" << LL_ENDL;
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
in.close();
removeGenericExtrasForHandle(handle);
// </FS:Beq>
return;
}
LLUUID cache_id(line);
if(cache_id != id)
{
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
// if the cache id doesn't match the expected region we should just kill the file.
LL_WARNS() << "Cache ID doesn't match for this region, deleting it" << LL_ENDL;
in.close();
removeGenericExtrasForHandle(handle);
// </FS:Beq>
return;
}
U32 num_entries; // if removal was enabled during write num_entries might be wrong
std::getline(in, line);
if(!in.good()) {
if(!in.good())
{
LL_WARNS() << "Failed reading extras cache for handle " << handle << LL_ENDL;
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
in.close();
removeGenericExtrasForHandle(handle);
// </FS:Beq>
return;
}
try {
try
{
num_entries = std::stol(line);
}
catch(std::logic_error&) // either invalid_argument or out_of_range
{
LL_WARNS() << "Failed reading extras cache for handle " << handle << ". unreadable num_entries" << LL_ENDL;
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
in.close();
removeGenericExtrasForHandle(handle);
// </FS:Beq>
return;
}
// <FS:Beq/> FIRE-33808 - Material Override Cache causes long delays
LL_DEBUGS("GLTF") << "Beginning reading extras cache for handle " << handle << " from " << getObjectCacheExtrasFilename(handle) << LL_ENDL;
LLSD entry_llsd;
@ -1702,22 +1693,19 @@ void LLVOCache::readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCac
static const U32 max_size = 4096;
bool success = LLSDSerialize::deserialize(entry_llsd, in, max_size);
// check bool(in) this time since eof is not a failure condition here
if(!success || !in) {
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
if(!success || !in)
{
LL_WARNS() << "Failed reading extras cache for handle " << handle << ", entry number " << i << " cache patrtial load only." << LL_ENDL;
in.close();
removeGenericExtrasForHandle(handle);
break;
// </FS:Beq>
}
LLGLTFOverrideCacheEntry entry;
entry.fromLLSD(entry_llsd);
U32 local_id = entry_llsd["local_id"].asInteger();
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
// cache_extras_entry_map[local_id] = entry;
// only add entries that exist in the primary cache
// this is a self-healing test that avoids us polluting the cache with entries that are no longer valid.
// this is a self-healing test that avoids us polluting the cache with entries that are no longer valid based on the main cache.
if(cache_entry_map.find(local_id)!= cache_entry_map.end())
{
// attempt to backfill a null objectId, though these shouldn't be in the persisted cache really
@ -1734,37 +1722,29 @@ void LLVOCache::readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCac
}
}
LL_DEBUGS("GLTF") << "Completed reading extras cache for handle " << handle << ", " << loaded << " loaded, " << discarded << " discarded" << LL_ENDL;
// </FS:Beq>
}
void LLVOCache::purgeEntries(U32 size)
{
// <FS:Beq/> FIRE-33808 - Material Override Cache causes long delays
LL_DEBUGS("VOCache","GLTF") << "Purging " << size << " entries from cache" << LL_ENDL;
while(mHeaderEntryQueue.size() > size)
{
header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ;
HeaderEntryInfo* entry = *iter ;
mHandleEntryMap.erase(entry->mHandle);
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
mHeaderEntryQueue.erase(iter);
removeFromCache(entry);
// </FS:Beq>
HeaderEntryInfo* entry = *iter ;
mHandleEntryMap.erase(entry->mHandle) ;
mHeaderEntryQueue.erase(iter) ;
removeFromCache(entry) ; // This now handles removing extras cache where appropriate.
delete entry;
}
mNumEntries = mHandleEntryMap.size() ;
}
void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache, bool removal_enabled)
{
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
std::string filename;
getObjectCacheFilename(handle, filename);
// </FS:Beq>
if(!mEnabled)
{
// <FS:Beq/> FIRE-33808 - Material Override Cache causes long delays
LL_WARNS() << "Not writing cache for " << filename << " (handle:" << handle << "): Cache is currently disabled." << LL_ENDL;
return ;
}
@ -1772,7 +1752,6 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry:
if(mReadOnly)
{
// <FS:Beq/> FIRE-33808 - Material Override Cache causes long delays
LL_WARNS() << "Not writing cache for " << filename << " (handle:" << handle << "): Cache is currently in read-only mode." << LL_ENDL;
return ;
}
@ -1808,14 +1787,12 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry:
//update cache header
if(!updateEntry(entry))
{
// <FS:Beq/> FIRE-33808 - Material Override Cache causes long delays
LL_WARNS() << "Failed to update cache header index " << entry->mIndex << ". " << filename << " handle = " << handle << LL_ENDL;
return ; //update failed.
}
if(!dirty_cache)
{
// <FS:Beq/> FIRE-33808 - Material Override Cache causes long delays
LL_WARNS() << "Skipping write to cache for " << filename << " (handle:" << handle << "): cache not dirty" << LL_ENDL;
return ; //nothing changed, no need to update.
}
@ -1852,7 +1829,6 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry:
}
else
{
// <FS:Beq/> FIRE-33808 - Material Override Cache causes long delays
LL_WARNS() << "Failed to write cache entry to buffer for " << filename << ", entry number " << iter->second->getLocalID() << LL_ENDL;
success = false;
break;
@ -1865,7 +1841,6 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry:
size_in_buffer = 0;
if (!success)
{
// <FS:Beq/> FIRE-33808 - Material Override Cache causes long delays
LL_WARNS() << "Failed to write cache to disk " << filename << LL_ENDL;
break;
}
@ -1877,15 +1852,12 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry:
{
// final write
success = check_write(&apr_file, (void*)data_buffer, size_in_buffer);
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
if(!success)
{
LL_WARNS() << "Failed to write cache entry to disk " << filename << LL_ENDL;
}
// </FS:Beq>
size_in_buffer = 0;
}
// <FS:Beq/> FIRE-33808 - Material Override Cache causes long delays
LL_DEBUGS("VOCache") << "Wrote " << num_entries << " entries to the primary VOCache file " << filename << ". success = " << (success ? "True":"False") << LL_ENDL;
}
}
@ -1898,7 +1870,7 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry:
return ;
}
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
void LLVOCache::removeGenericExtrasForHandle(U64 handle)
{
if(mReadOnly)
@ -1909,7 +1881,6 @@ void LLVOCache::removeGenericExtrasForHandle(U64 handle)
LL_WARNS("GLTF", "VOCache") << "Removing generic extras for handle " << handle << "Filename: " << getObjectCacheExtrasFilename(handle) << LL_ENDL;
LLFile::remove(getObjectCacheExtrasFilename(handle));
}
// </FS:Beq>
void LLVOCache::writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map, BOOL dirty_cache, bool removal_enabled)
{
@ -1933,27 +1904,6 @@ void LLVOCache::writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LL
if(!out.good())
{
LL_WARNS() << "Failed writing extras cache for handle " << handle << LL_ENDL;
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
// return;
// // TODO - clean up broken cache file
// }
// out << id << '\n';
// if(!out.good())
// {
// LL_WARNS() << "Failed writing extras cache for handle " << handle << LL_ENDL;
// return;
// // TODO - clean up broken cache file
// }
// U32 num_entries = cache_extras_entry_map.size();
// out << num_entries << '\n';
// if(!out.good())
// {
// LL_WARNS() << "Failed writing extras cache for handle " << handle << LL_ENDL;
// return;
// // TODO - clean up broken cache file
// }
removeGenericExtrasForHandle(handle);
return;
}
@ -1965,10 +1915,10 @@ void LLVOCache::writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LL
if(!out.good())
{
LL_WARNS() << "Failed writing extras cache for handle " << handle << LL_ENDL;
removeGenericExtrasForHandle(handle); // <FS:Beq/> FIRE-33808 - Material Override Cache causes long delays
removeGenericExtrasForHandle(handle);
return;
}
// Because we don't write out all the entries we need to record a placeholder and rewrite this later
auto num_entries_placeholder = out.tellp();
out << std::setw(10) << std::setfill('0') << 0 << '\n';
if(!out.good())
@ -1989,17 +1939,17 @@ void LLVOCache::writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LL
{
// Only write out GLTFOverrides that we can actually apply again on import.
// worst case we have an extra cache miss.
// Note: mObjectId is valid in memory as we might have a data race between GLTF of the object itself.
// Note: A null mObjectId is valid when in memory as we might have a data race between GLTF of the object itself.
// This remains a valid state to persist as it is consistent with the localid checks on import with the main cache.
// the mObjectId will be updated if/when the local object is updated from the gObject list (due to full update)
if(entry.mObjectId.isNull() && pRegion)
{
gObjectList.getUUIDFromLocal( entry.mObjectId, local_id, pRegion->getHost().getAddress(), pRegion->getHost().getPort() );
}
if( /*entry.mObjectId.notNull() &&*/
entry.mSides.size() > 0 &&
if( entry.mSides.size() > 0 &&
entry.mSides.size() == entry.mGLTFMaterial.size()
)
)
{
LLSD entry_llsd = entry.toLLSD();
entry_llsd["local_id"] = (S32)local_id;
@ -2019,6 +1969,7 @@ void LLVOCache::writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LL
skipped++;
}
}
// Rewrite the placeholder
out.seekp(num_entries_placeholder);
out << std::setw(10) << std::setfill('0') << num_entries << '\n';
if(!out.good())

View File

@ -291,17 +291,14 @@ public:
// We need this init to be separate from constructor, since we might construct cache, purge it, then init.
void initCache(ELLPath location, U32 size, U32 cache_version);
void removeCache(ELLPath location, bool started = false) ;
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
// void readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) ;
// void readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map);
bool readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) ;
void readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map);
// </FS:Beq>
void writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache, bool removal_enabled);
void writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map, BOOL dirty_cache, bool removal_enabled);
void removeEntry(U64 handle) ;
void removeGenericExtrasForHandle(U64 handle); // <FS:Beq/> FIRE-33808 - Material Override Cache causes long delays
void removeGenericExtrasForHandle(U64 handle);
U32 getCacheEntries() { return mNumEntries; }
U32 getCacheEntriesMax() { return mCacheSize; }

View File

@ -4842,7 +4842,7 @@ LLVector3 LLVOVolume::volumeDirectionToAgent(const LLVector3& dir) const
BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, BOOL pick_rigged, BOOL pick_unselectable, S32 *face_hitp,
LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent)
LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent)
{
if (!mbCanSelect
|| mDrawable->isDead()
@ -5049,7 +5049,7 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&
}
}
}
return ret;
}

View File

@ -411,6 +411,114 @@ private:
return parseValues(status_string, "", param);
}
LLSD parseValue(std::string& status_string, const std::string& key, const std::string& key_pfx, XMLRPC_VALUE param)
{
LLSD response;
XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(param);
switch (type)
{
case xmlrpc_type_empty:
LL_INFOS("LLXMLRPCListener") << "Empty result for key " << key_pfx << key << LL_ENDL;
break;
case xmlrpc_type_base64:
{
S32 len = XMLRPC_GetValueStringLen(param);
const char* buf = XMLRPC_GetValueBase64(param);
if ((len > 0) && buf)
{
// During implementation this code was not tested
// If you encounter this, please make sure this is correct,
// then remove llassert
llassert(0);
LLSD::Binary data;
data.resize(len);
memcpy((void*)&data[0], (void*)buf, len);
response = data;
}
else
{
LL_WARNS("LLXMLRPCListener") << "Potentially malformed xmlrpc_type_base64 for key "
<< key_pfx << key << LL_ENDL;
}
break;
}
case xmlrpc_type_boolean:
{
response = LLSD::Boolean(XMLRPC_GetValueBoolean(param));
LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL;
break;
}
case xmlrpc_type_datetime:
{
std::string iso8601_date(XMLRPC_GetValueDateTime_ISO8601(param));
LL_DEBUGS("LLXMLRPCListener") << "val: " << iso8601_date << LL_ENDL;
response = LLSD::Date(iso8601_date);
break;
}
case xmlrpc_type_double:
{
response = LLSD::Real(XMLRPC_GetValueDouble(param));
LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL;
break;
}
case xmlrpc_type_int:
{
response = LLSD::Integer(XMLRPC_GetValueInt(param));
LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL;
break;
}
case xmlrpc_type_string:
{
response = LLSD::String(XMLRPC_GetValueString(param));
LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL;
break;
}
case xmlrpc_type_mixed:
case xmlrpc_type_array:
{
// We expect this to be an array of submaps. Walk the array,
// recursively parsing each submap and collecting them.
LLSD array;
int i = 0; // for descriptive purposes
for (XMLRPC_VALUE row = XMLRPC_VectorRewind(param); row;
row = XMLRPC_VectorNext(param), ++i)
{
// Recursive call. For the lower-level key_pfx, if 'key'
// is "foo", pass "foo[0]:", then "foo[1]:", etc. In the
// nested call, a subkey "bar" will then be logged as
// "foo[0]:bar", and so forth.
// Parse the scalar subkey/value pairs from this array
// entry into a temp submap. Collect such submaps in 'array'.
array.append(parseValue(status_string, "",
STRINGIZE(key_pfx << key << '[' << i << "]:"),
row));
}
// Having collected an 'array' of 'submap's, insert that whole
// 'array' as the value of this 'key'.
response = array;
break;
}
case xmlrpc_type_struct:
{
response = parseValues(status_string,
STRINGIZE(key_pfx << key << ':'),
param);
break;
}
case xmlrpc_type_none: // Not expected
default:
// whoops - unrecognized type
LL_WARNS("LLXMLRPCListener") << "Unhandled xmlrpc type " << type << " for key "
<< key_pfx << key << LL_ENDL;
response = STRINGIZE("<bad XMLRPC type " << type << '>');
status_string = "BadType";
}
return response;
}
/**
* Parse key/value pairs from a given XMLRPC_VALUE into an LLSD map.
* @param key_pfx Used to describe a given key in log messages. At top
@ -428,113 +536,7 @@ private:
{
std::string key(XMLRPC_GetValueID(current));
LL_DEBUGS("LLXMLRPCListener") << "key: " << key_pfx << key << LL_ENDL;
XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(current);
switch (type)
{
case xmlrpc_type_empty:
LL_INFOS("LLXMLRPCListener") << "Empty result for key " << key_pfx << key << LL_ENDL;
responses.insert(key, LLSD());
break;
case xmlrpc_type_base64:
{
S32 len = XMLRPC_GetValueStringLen(current);
const char* buf = XMLRPC_GetValueBase64(current);
if ((len > 0) && buf)
{
// During implementation this code was not tested
// If you encounter this, please make sure this is correct,
// then remove llassert
llassert(0);
LLSD::Binary data;
data.resize(len);
memcpy((void*)&data[0], (void*)buf, len);
responses.insert(key, data);
}
else
{
LL_WARNS("LLXMLRPCListener") << "Potentially malformed xmlrpc_type_base64 for key "
<< key_pfx << key << LL_ENDL;
responses.insert(key, LLSD());
}
break;
}
case xmlrpc_type_boolean:
{
LLSD::Boolean val(XMLRPC_GetValueBoolean(current));
LL_DEBUGS("LLXMLRPCListener") << "val: " << val << LL_ENDL;
responses.insert(key, val);
break;
}
case xmlrpc_type_datetime:
{
std::string iso8601_date(XMLRPC_GetValueDateTime_ISO8601(current));
LL_DEBUGS("LLXMLRPCListener") << "val: " << iso8601_date << LL_ENDL;
responses.insert(key, LLSD::Date(iso8601_date));
break;
}
case xmlrpc_type_double:
{
LLSD::Real val(XMLRPC_GetValueDouble(current));
LL_DEBUGS("LLXMLRPCListener") << "val: " << val << LL_ENDL;
responses.insert(key, val);
break;
}
case xmlrpc_type_int:
{
LLSD::Integer val(XMLRPC_GetValueInt(current));
LL_DEBUGS("LLXMLRPCListener") << "val: " << val << LL_ENDL;
responses.insert(key, val);
break;
}
case xmlrpc_type_string:
{
LLSD::String val(XMLRPC_GetValueString(current));
LL_DEBUGS("LLXMLRPCListener") << "val: " << val << LL_ENDL;
responses.insert(key, val);
break;
}
case xmlrpc_type_mixed:
case xmlrpc_type_array:
{
// We expect this to be an array of submaps. Walk the array,
// recursively parsing each submap and collecting them.
LLSD array;
int i = 0; // for descriptive purposes
for (XMLRPC_VALUE row = XMLRPC_VectorRewind(current); row;
row = XMLRPC_VectorNext(current), ++i)
{
// Recursive call. For the lower-level key_pfx, if 'key'
// is "foo", pass "foo[0]:", then "foo[1]:", etc. In the
// nested call, a subkey "bar" will then be logged as
// "foo[0]:bar", and so forth.
// Parse the scalar subkey/value pairs from this array
// entry into a temp submap. Collect such submaps in 'array'.
array.append(parseValues(status_string,
STRINGIZE(key_pfx << key << '[' << i << "]:"),
row));
}
// Having collected an 'array' of 'submap's, insert that whole
// 'array' as the value of this 'key'.
responses.insert(key, array);
break;
}
case xmlrpc_type_struct:
{
LLSD submap = parseValues(status_string,
STRINGIZE(key_pfx << key << ':'),
current);
responses.insert(key, submap);
break;
}
case xmlrpc_type_none: // Not expected
default:
// whoops - unrecognized type
LL_WARNS("LLXMLRPCListener") << "Unhandled xmlrpc type " << type << " for key "
<< key_pfx << key << LL_ENDL;
responses.insert(key, STRINGIZE("<bad XMLRPC type " << type << '>'));
status_string = "BadType";
}
responses.insert(key, parseValue(status_string, key, key_pfx, current));
}
return responses;
}

View File

@ -112,6 +112,7 @@
#include "llscenemonitor.h"
#include "llprogressview.h"
#include "llcleanup.h"
#include "gltfscenemanager.h"
// [RLVa:KB] - Checked: RLVa-2.0.0
#include "llvisualeffect.h"
#include "rlvactions.h"
@ -858,6 +859,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
if (RenderMirrors)
{
mHeroProbeManager.initReflectionMaps();
res = mHeroProbeManager.mProbeResolution; // We also scale the hero probe RT to the probe res since we don't super sample it.
mRT = &mHeroProbeRT;
allocateScreenBuffer(res, res, samples);
@ -1254,6 +1256,12 @@ void LLPipeline::releaseScreenBuffers()
mRT->fxaaBuffer.release();
mRT->deferredScreen.release();
mRT->deferredLight.release();
mHeroProbeRT.uiScreen.release();
mHeroProbeRT.screen.release();
mHeroProbeRT.fxaaBuffer.release();
mHeroProbeRT.deferredScreen.release();
mHeroProbeRT.deferredLight.release();
}
void LLPipeline::releaseSunShadowTarget(U32 index)
@ -4671,6 +4679,8 @@ void LLPipeline::renderDebug()
}
}
LL::GLTFSceneManager::instance().renderDebug();
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
{ //render visible selected group occlusion geometry
gDebugProgram.bind();
@ -6482,6 +6492,15 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start,
}
}
}
S32 node_hit = -1;
S32 primitive_hit = -1;
LLDrawable* hit = LL::GLTFSceneManager::instance().lineSegmentIntersect(start, local_end, pick_transparent, pick_rigged, pick_unselectable, pick_reflection_probe, &node_hit, &primitive_hit, &position, tex_coord, normal, tangent);
if (hit)
{
drawable = hit;
local_end = position;
}
if (!sPickAvatar)
{
@ -6698,6 +6717,11 @@ void LLPipeline::renderGLTFObjects(U32 type, bool texture, bool rigged)
gGL.loadMatrix(gGLModelView);
gGLLastMatrix = NULL;
if (!rigged)
{
LL::GLTFSceneManager::instance().renderOpaque();
}
}
// Currently only used for shadows -Cosmic,2023-04-19

View File

@ -335,42 +335,10 @@
name="FSAADisabled"
value="0" />
<combo_box.item
label="2x"
name="2x"
label="FXAA"
name="FXAA"
value="2" />
<combo_box.item
label="4x"
name="4x"
value="4" />
<combo_box.item
label="8x"
name="8x"
value="8" />
<combo_box.item
label="16x"
name="16x"
value="16" />
</combo_box>
<text
type="string"
length="1"
follows="left|top"
height="16"
layout="topleft"
left_pad="10"
name="antialiasing restart"
top_delta="0"
width="130">
(requires restart)
</text>
<view_border
bevel_style="in"
height="322"
layout="topleft"
left="385"
name="vert_border"
top="16"
width="0"/>
<text
type="string"
length="1"
@ -378,23 +346,22 @@
height="16"
layout="topleft"
name="MeshText"
top_delta="20"
left="400"
top="21"
top_delta="16"
left="10"
width="128">
Mesh
Mesh
</text>
<slider
control_name="RenderTerrainLODFactor"
follows="left|top"
follows="topleft"
height="16"
increment="0.125"
initial_value="160"
label="Terrain Mesh Detail:"
label_width="185"
layout="topleft"
left="420"
left="30"
min_val="1"
max_val="2"
name="TerrainMeshDetail"
@ -408,7 +375,7 @@
<text
type="string"
length="1"
follows="left|top"
follows="topleft"
height="16"
layout="topleft"
name="TerrainMeshDetailText"
@ -416,19 +383,19 @@
top_delta="0"
left_delta="304"
width="65">
Low
Low
</text>
<slider
control_name="RenderTreeLODFactor"
follows="left|top"
follows="topleft"
height="16"
increment="0.125"
initial_value="160"
label="Trees:"
label_width="185"
layout="topleft"
left="420"
left="30"
name="TreeMeshDetail"
show_text="false"
top_delta="16"
@ -447,7 +414,7 @@
top_delta="0"
left_delta="304"
width="65">
Low
Low
</text>
<slider
@ -459,7 +426,7 @@
label="Objects:"
label_width="185"
layout="topleft"
left="420"
left="30"
min_val="0"
max_val="4"
name="ObjectMeshDetail"
@ -480,7 +447,7 @@
top_delta="0"
left_delta="304"
width="65">
Low
Low
</text>
<slider
@ -491,7 +458,7 @@
label="Flexiprims:"
label_width="185"
layout="topleft"
left="420"
left="30"
name="FlexibleMeshDetail"
show_text="false"
top_delta="16"
@ -510,8 +477,28 @@
top_delta="0"
left_delta="304"
width="65">
Low
Low
</text>
<text
type="string"
length="1"
follows="left|top"
height="16"
layout="topleft"
left_pad="10"
name="antialiasing restart"
top_delta="0"
width="130">
(requires restart)
</text>
<view_border
bevel_style="in"
height="322"
layout="topleft"
left="385"
name="vert_border"
top="16"
width="0"/>
<text
type="string"
@ -520,7 +507,7 @@
height="16"
layout="topleft"
name="ShadersText"
top_delta="20"
top_delta="-10"
left="400"
width="128">
Shaders
@ -747,6 +734,102 @@
width="260">
</slider>
<!-- Mirror settings. -->
<check_box
control_name="RenderMirrors"
height="16"
initial_value="false"
label="Mirrors"
layout="topleft"
left="420"
name="Mirrors"
top_delta="24"
width="240">
<check_box.commit_callback
function="Pref.RenderOptionUpdate" />
</check_box>
<text
type="string"
length="1"
follows="left|top"
height="16"
layout="topleft"
left="420"
name="MirrorResolutionText"
text_readonly_color="LabelDisabledColor"
top_delta="22"
width="128">
Mirror Resolution:
</text>
<combo_box
control_name="RenderHeroProbeResolution"
height="18"
layout="topleft"
left_delta="130"
top_delta="0"
name="MirrorResolution"
width="150">
<combo_box.item
label="256"
name="0"
value="256"/>
<combo_box.item
label="512"
name="1"
value="512"/>
<combo_box.item
label="1024"
name="2"
value="1024"/>
<combo_box.item
label="2048"
name="3"
value="2048"/>
</combo_box>
<text
type="string"
length="1"
follows="left|top"
height="16"
layout="topleft"
left="420"
name="HeroProbeUpdateText"
text_readonly_color="LabelDisabledColor"
top_delta="22"
width="128">
Mirror Update Rate:
</text>
<combo_box
control_name="RenderHeroProbeUpdateRate"
height="18"
layout="topleft"
left_delta="130"
top_delta="0"
name="HeroProbeUpdateRate"
width="150">
<combo_box.item
label="Every Frame"
name="0"
value="1"/>
<combo_box.item
label="Every 2nd Frame"
name="1"
value="2"/>
<combo_box.item
label="Every 3rd Frame"
name="2"
value="3"/>
<combo_box.item
label="Every 4th Frame"
name="3"
value="4"/>
</combo_box>
<!-- End of mirror settings -->
<!-- End of Advanced Settings block -->
<view_border
bevel_style="in"

View File

@ -4124,6 +4124,12 @@
<menu_item_call.on_click
function="Advanced.ClickHDRIPreview" />
</menu_item_call>
<menu_item_call
label="GLTF Scene Preview"
name="GLTF Scene Preview">
<menu_item_call.on_click
function="Advanced.ClickGLTFScenePreview" />
</menu_item_call>
</menu>
<menu
create_jump_keys="true"

View File

@ -14291,7 +14291,18 @@ If you want to see this object, remove it and re-attach it to an avatar attachme
name="okignore"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="GLTFPreviewSelection"
type="alert">
You must select an object to act as a handle to the GLTF asset you are previewing.
<tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"

View File

@ -221,26 +221,15 @@
width="80">
Ultra
</text>
<check_box
control_name="FullScreen"
height="16"
initial_value="false"
label="Fullscreen Mode"
layout="topleft"
left="4"
name="Fullscreen Mode"
tool_tip="Run Firestorm in Fullscreen mode. A restart is required to change mode."
top="80"
width="280" />
<text
type="string"
length="1"
follows="left|top"
height="12"
layout="topleft"
left_delta="1"
left="4"
name="ShadersText"
top_pad="5"
top="70"
width="128">
Shaders:
</text>
@ -283,6 +272,19 @@
<check_box.commit_callback
function="Pref.RenderOptionUpdate" />
</check_box>
<check_box
control_name="RenderMirrors"
height="16"
initial_value="false"
label="Mirrors"
layout="topleft"
left_delta="0"
name="Mirrors"
top_pad="1"
width="280">
<check_box.commit_callback
function="Pref.RenderOptionUpdate" />
</check_box>
<text
type="string"
length="1"
@ -391,8 +393,6 @@
name="3"
value="3"/>
</combo_box>
<!-- FS:TM Avatar Physics was moved down to LOD section-->
<!-- FS:TM Point Lighting added instead of above-->
<text
type="string"
length="1"
@ -428,7 +428,101 @@
name="1"
value="1"/>
</combo_box>
<!-- Mirror settings. -->
<text
type="string"
length="1"
follows="left|top"
height="12"
layout="topleft"
left_delta="-5"
name="MirrorResolutionText"
text_readonly_color="LabelDisabledColor"
top_pad="4"
width="170">
Mirror Resolution:
</text>
<combo_box
control_name="RenderHeroProbeResolution"
enabled_control="RenderMirrors"
height="23"
layout="topleft"
left_delta="5"
top_pad="3"
name="MirrorResolution"
width="150">
<combo_box.item
label="256"
name="0"
value="256"/>
<combo_box.item
label="512"
name="1"
value="512"/>
<combo_box.item
label="1024"
name="2"
value="1024"/>
<combo_box.item
label="2048"
name="3"
value="2048"/>
</combo_box>
<text
type="string"
length="1"
follows="left|top"
height="12"
layout="topleft"
left_delta="-5"
name="HeroProbeUpdateText"
text_readonly_color="LabelDisabledColor"
top_pad="4"
width="170">
Mirror Update Rate:
</text>
<combo_box
control_name="RenderHeroProbeUpdateRate"
enabled_control="RenderMirrors"
height="23"
layout="topleft"
left_delta="5"
top_pad="3"
name="HeroProbeUpdateRate"
width="150">
<combo_box.item
label="Every Frame"
name="0"
value="1"/>
<combo_box.item
label="Every 2nd Frame"
name="1"
value="2"/>
<combo_box.item
label="Every 3rd Frame"
name="2"
value="3"/>
<combo_box.item
label="Every 4th Frame"
name="3"
value="4"/>
</combo_box>
<!-- End of mirror settings -->
<!--Top of second column in General tab-->
<check_box
control_name="FullScreen"
height="16"
initial_value="false"
label="Fullscreen Mode"
layout="topleft"
left="196"
name="Fullscreen Mode"
tool_tip="Run Firestorm in Fullscreen mode. A restart is required to change mode."
top="80"
width="280" />
<slider
control_name="RenderFarClip"
decimal_digits="0"
@ -443,7 +537,7 @@
max_val="1024"
min_val="32"
name="DrawDistance"
top="80"
top_pad="6"
width="301" />
<text
type="string"
@ -877,21 +971,9 @@
name="FSAADisabled"
value="0" />
<combo_box.item
label="2x"
name="2x"
label="FXAA"
name="FXAA"
value="2" />
<combo_box.item
label="4x"
name="4x"
value="4" />
<combo_box.item
label="8x"
name="8x"
value="8" />
<combo_box.item
label="16x"
name="16x"
value="16" />
</combo_box>
</panel>

View File

@ -629,7 +629,7 @@ class Windows_x86_64_Manifest(ViewerManifest):
# 'secondlife-bin.*',
# '*_Setup.exe',
# '*.bat',
# '*.tar.bz2')))
# '*.tar.xz')))
# </FS:Ansariel>
# <FS:Ansariel> Remove VMP