Apertura del repositorio

This commit is contained in:
2025-05-24 18:09:39 -03:00
parent 76e6359dad
commit d883ddd0d0
35253 changed files with 2891973 additions and 2 deletions
+92
View File
@@ -0,0 +1,92 @@
# -*- cmake -*-
project(llprimitive)
include(00-Common)
include(LLCommon)
include(LLCoreHttp)
include(LLPhysicsExtensions)
include(LLPrimitive)
include(GLM)
include(TinyGLTF)
include(ColladaDom)
set(llprimitive_SOURCE_FILES
lldaeloader.cpp
llgltfloader.cpp
llgltfmaterial.cpp
llmaterialid.cpp
llmaterial.cpp
llmaterialtable.cpp
llmediaentry.cpp
llmodel.cpp
llmodelloader.cpp
llprimitive.cpp
llprimtexturelist.cpp
lltextureanim.cpp
lltextureentry.cpp
lltreeparams.cpp
llvolumemessage.cpp
material_codes.cpp
)
set(llprimitive_HEADER_FILES
CMakeLists.txt
lldaeloader.h
llgltfloader.h
llgltfmaterial.h
llgltfmaterial_templates.h
legacy_object_types.h
llmaterial.h
llmaterialid.h
llmaterialtable.h
llmediaentry.h
llmodel.h
llmodelloader.h
llprimitive.h
llprimtexturelist.h
lllslconstants.h
lltextureanim.h
lltextureentry.h
lltreeparams.h
lltree_common.h
llvolumemessage.h
material_codes.h
object_flags.h
)
list(APPEND llprimitive_SOURCE_FILES ${llprimitive_HEADER_FILES})
add_library (llprimitive ${llprimitive_SOURCE_FILES})
target_include_directories( llprimitive INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(llprimitive
llcommon
llmath
llmessage
llcorehttp
llxml
llcharacter
llrender
llphysicsextensions_impl
ll::colladadom
ll::glm
)
if(LINUX)
# GLIB uses pcre, so we need to keep it for Linux
target_link_libraries(ll::pcre)
endif(LINUX)
#add unit tests
if (LL_TESTS)
INCLUDE(LLAddBuildTest)
SET(llprimitive_TEST_SOURCE_FILES
llmediaentry.cpp
llprimitive.cpp
llgltfmaterial.cpp
)
set_property(SOURCE llprimitive.cpp PROPERTY LL_TEST_ADDITIONAL_LIBRARIES llmessage)
LL_ADD_PROJECT_UNIT_TESTS(llprimitive "${llprimitive_TEST_SOURCE_FILES}")
endif (LL_TESTS)
+77
View File
@@ -0,0 +1,77 @@
/**
* @file legacy_object_types.h
* @brief Byte codes for basic object and primitive types
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#ifndef LL_LEGACY_OBJECT_TYPES_H
#define LL_LEGACY_OBJECT_TYPES_H
const S8 PLAYER = 'c';
//const S8 BASIC_SHOT = 's';
//const S8 BIG_SHOT = 'S';
//const S8 TREE_SHOT = 'g';
//const S8 PHYSICAL_BALL = 'b';
const S8 TREE = 'T';
const S8 TREE_NEW = 'R';
//const S8 SPARK = 'p';
//const S8 SMOKE = 'q';
//const S8 BOX = 'x';
//const S8 CYLINDER = 'y';
//const S8 CONE = 'o';
//const S8 SPHERE = 'h';
//const S8 BIRD = 'r'; // ascii 114
//const S8 ATOR = 'a';
//const S8 ROCK = 'k';
const S8 GRASS = 'd';
const S8 PART_SYS = 'P';
//const S8 ORACLE = 'O';
//const S8 TEXTBUBBLE = 't'; // Text bubble to show communication
//const S8 DEMON = 'M'; // Maxwell's demon for scarfing legacy_object_types.h
//const S8 CUBE = 'f';
//const S8 LSL_TEST = 'L';
//const S8 PRISM = '1';
//const S8 PYRAMID = '2';
//const S8 TETRAHEDRON = '3';
//const S8 HALF_CYLINDER = '4';
//const S8 HALF_CONE = '5';
//const S8 HALF_SPHERE = '6';
const S8 PRIMITIVE_VOLUME = 'v';
// Misc constants
//const F32 AVATAR_RADIUS = 0.5f;
//const F32 SHOT_RADIUS = 0.05f;
//const F32 BIG_SHOT_RADIUS = 0.05f;
//const F32 TREE_SIZE = 5.f;
//const F32 BALL_SIZE = 4.f;
//const F32 SHOT_VELOCITY = 100.f;
//const F32 GRENADE_BLAST_RADIUS = 5.f;
#endif
File diff suppressed because it is too large Load Diff
+116
View File
@@ -0,0 +1,116 @@
/**
* @file lldaeloader.h
* @brief LLDAELoader class definition
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2013, 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$
*/
#ifndef LL_LLDAELOADER_H
#define LL_LLDAELOADER_H
#include "llmodelloader.h"
#include <array> // <FS:Beq/> configurable lod suffixes
class DAE;
class daeElement;
class domProfile_COMMON;
class domInstance_geometry;
class domNode;
class domTranslate;
class domController;
class domSkin;
class domMesh;
using LODSuffixArray = std::array<std::string,LLModel::NUM_LODS>; // <FS:Beq/> configurable lod suffixes
class LLDAELoader : public LLModelLoader
{
public:
typedef std::map<std::string, LLImportMaterial> material_map;
typedef std::map<daeElement*, std::vector<LLPointer<LLModel> > > dae_model_map;
dae_model_map mModelsMap;
LLDAELoader(
std::string filename,
S32 lod,
LLModelLoader::load_callback_t load_cb,
LLModelLoader::joint_lookup_func_t joint_lookup_func,
LLModelLoader::texture_load_func_t texture_load_func,
LLModelLoader::state_callback_t state_cb,
void* opaque_userdata,
JointTransformMap& jointTransformMap,
JointNameSet& jointsFromNodes,
std::map<std::string, std::string, std::less<>>& jointAliasMap,
U32 maxJointsPerMesh,
U32 modelLimit,
// <FS:Beq> configrable lod suffix support
// bool preprocess);
bool preprocess,
const LODSuffixArray& lod_suffix);
// </FS:Beq>
virtual ~LLDAELoader() ;
virtual bool OpenFile(const std::string& filename);
protected:
void processElement(daeElement* element, bool& badElement, DAE* dae);
void processDomModel(LLModel* model, DAE* dae, daeElement* pRoot, domMesh* mesh, domSkin* skin);
material_map getMaterials(LLModel* model, domInstance_geometry* instance_geo, DAE* dae);
LLImportMaterial profileToMaterial(domProfile_COMMON* material, DAE* dae);
LLColor4 getDaeColor(daeElement* element);
daeElement* getChildFromElement( daeElement* pElement, std::string const & name );
bool isNodeAJoint( domNode* pNode );
void processJointNode( domNode* pNode, std::map<std::string,LLMatrix4>& jointTransforms );
void extractTranslation( domTranslate* pTranslate, LLMatrix4& transform );
void extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform );
void extractTranslationViaSID( daeElement* pElement, LLMatrix4& transform );
void buildJointToNodeMappingFromScene( daeElement* pRoot );
void processJointToNodeMapping( domNode* pNode );
void processChildJoints( domNode* pParentNode );
bool verifyCount( int expected, int result );
//Verify that a controller matches vertex counts
bool verifyController( domController* pController );
static bool addVolumeFacesFromDomMesh(LLModel* model, domMesh* mesh, LLSD& log_msg);
// Loads a mesh breaking it into one or more models as necessary
// to get around volume face limitations while retaining >8 materials
//
bool loadModelsFromDomMesh(domMesh* mesh, std::vector<LLModel*>& models_out, U32 submodel_limit);
static std::string getElementLabel(daeElement *element);
static size_t getSuffixPosition(std::string label);
static std::string getLodlessLabel(daeElement *element);
static LODSuffixArray sLODSuffix; // <FS:Beq/> mesh loader suffix configuration
public: // <FS:Beq/> open up for local mesh to use
static std::string preprocessDAE(std::string filename);
private:
U32 mGeneratedModelLimit; // Attempt to limit amount of generated submodels
bool mPreprocessDAE;
};
#endif // LL_LLDAELLOADER_H
+404
View File
@@ -0,0 +1,404 @@
/**
* @file LLGLTFLoader.cpp
* @brief LLGLTFLoader class implementation
*
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2022, 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 "llgltfloader.h"
// Import & define single-header gltf import/export lib
#define TINYGLTF_IMPLEMENTATION
#define TINYGLTF_USE_CPP14 // default is C++ 11
// tinygltf by default loads image files using STB
#define STB_IMAGE_IMPLEMENTATION
// to use our own image loading:
// 1. replace this definition with TINYGLTF_NO_STB_IMAGE
// 2. provide image loader callback with TinyGLTF::SetImageLoader(LoadimageDataFunction LoadImageData, void *user_data)
// tinygltf saves image files using STB
#define STB_IMAGE_WRITE_IMPLEMENTATION
// similarly, can override with TINYGLTF_NO_STB_IMAGE_WRITE and TinyGLTF::SetImageWriter(fxn, data)
// Additionally, disable inclusion of STB header files entirely with
// TINYGLTF_NO_INCLUDE_STB_IMAGE
// TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE
#include "tinygltf/tiny_gltf.h"
// TODO: includes inherited from dae loader. Validate / prune
#include "llsdserialize.h"
#include "lljoint.h"
#include "llmatrix4a.h"
#include <boost/regex.hpp>
#include <boost/algorithm/string/replace.hpp>
static const std::string lod_suffix[LLModel::NUM_LODS] =
{
"_LOD0",
"_LOD1",
"_LOD2",
"",
"_PHYS",
};
LLGLTFLoader::LLGLTFLoader(std::string filename,
S32 lod,
LLModelLoader::load_callback_t load_cb,
LLModelLoader::joint_lookup_func_t joint_lookup_func,
LLModelLoader::texture_load_func_t texture_load_func,
LLModelLoader::state_callback_t state_cb,
void * opaque_userdata,
JointTransformMap & jointTransformMap,
JointNameSet & jointsFromNodes,
std::map<std::string, std::string, std::less<>> & jointAliasMap,
U32 maxJointsPerMesh,
U32 modelLimit) //,
//bool preprocess)
: LLModelLoader( filename,
lod,
load_cb,
joint_lookup_func,
texture_load_func,
state_cb,
opaque_userdata,
jointTransformMap,
jointsFromNodes,
jointAliasMap,
maxJointsPerMesh ),
//mPreprocessGLTF(preprocess),
mMeshesLoaded(false),
mMaterialsLoaded(false)
{
}
LLGLTFLoader::~LLGLTFLoader() {}
bool LLGLTFLoader::OpenFile(const std::string &filename)
{
tinygltf::TinyGLTF loader;
std::string error_msg;
std::string warn_msg;
std::string filename_lc(filename);
LLStringUtil::toLower(filename_lc);
// Load a tinygltf model fom a file. Assumes that the input filename has already been
// been sanitized to one of (.gltf , .glb) extensions, so does a simple find to distinguish.
if (std::string::npos == filename_lc.rfind(".gltf"))
{ // file is binary
mGltfLoaded = loader.LoadBinaryFromFile(&mGltfModel, &error_msg, &warn_msg, filename);
}
else
{ // file is ascii
mGltfLoaded = loader.LoadASCIIFromFile(&mGltfModel, &error_msg, &warn_msg, filename);
}
if (!mGltfLoaded)
{
if (!warn_msg.empty())
LL_WARNS("GLTF_IMPORT") << "gltf load warning: " << warn_msg.c_str() << LL_ENDL;
if (!error_msg.empty())
LL_WARNS("GLTF_IMPORT") << "gltf load error: " << error_msg.c_str() << LL_ENDL;
return false;
}
mMeshesLoaded = parseMeshes();
if (mMeshesLoaded) uploadMeshes();
mMaterialsLoaded = parseMaterials();
if (mMaterialsLoaded) uploadMaterials();
return (mMeshesLoaded || mMaterialsLoaded);
}
bool LLGLTFLoader::parseMeshes()
{
if (!mGltfLoaded) return false;
// 2022-04 DJH Volume params from dae example. TODO understand PCODE
LLVolumeParams volume_params;
volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
for (tinygltf::Mesh mesh : mGltfModel.meshes)
{
LLModel *pModel = new LLModel(volume_params, 0.f);
if (populateModelFromMesh(pModel, mesh) &&
(LLModel::NO_ERRORS == pModel->getStatus()) &&
validate_model(pModel))
{
mModelList.push_back(pModel);
}
else
{
setLoadState(ERROR_MODEL + pModel->getStatus());
delete(pModel);
return false;
}
}
return true;
}
bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const tinygltf::Mesh &mesh)
{
pModel->mLabel = mesh.name;
int pos_idx;
tinygltf::Accessor indices_a, positions_a, normals_a, uv0_a, color0_a;
auto prims = mesh.primitives;
for (auto prim : prims)
{
if (prim.indices >= 0) indices_a = mGltfModel.accessors[prim.indices];
pos_idx = (prim.attributes.count("POSITION") > 0) ? prim.attributes.at("POSITION") : -1;
if (pos_idx >= 0)
{
positions_a = mGltfModel.accessors[pos_idx];
if (TINYGLTF_COMPONENT_TYPE_FLOAT != positions_a.componentType)
continue;
auto positions_bv = mGltfModel.bufferViews[positions_a.bufferView];
auto positions_buf = mGltfModel.buffers[positions_bv.buffer];
//auto type = positions_vb.
//if (positions_buf.name
}
#if 0
int norm_idx, tan_idx, uv0_idx, uv1_idx, color0_idx, color1_idx;
norm_idx = (prim.attributes.count("NORMAL") > 0) ? prim.attributes.at("NORMAL") : -1;
tan_idx = (prim.attributes.count("TANGENT") > 0) ? prim.attributes.at("TANGENT") : -1;
uv0_idx = (prim.attributes.count("TEXCOORDS_0") > 0) ? prim.attributes.at("TEXCOORDS_0") : -1;
uv1_idx = (prim.attributes.count("TEXCOORDS_1") > 0) ? prim.attributes.at("TEXCOORDS_1") : -1;
color0_idx = (prim.attributes.count("COLOR_0") > 0) ? prim.attributes.at("COLOR_0") : -1;
color1_idx = (prim.attributes.count("COLOR_1") > 0) ? prim.attributes.at("COLOR_1") : -1;
#endif
if (prim.mode == TINYGLTF_MODE_TRIANGLES)
{
//auto pos = mesh. TODO resume here DJH 2022-04
}
}
//pModel->addFace()
return false;
}
bool LLGLTFLoader::parseMaterials()
{
if (!mGltfLoaded) return false;
// fill local texture data structures
mSamplers.clear();
for (auto in_sampler : mGltfModel.samplers)
{
gltf_sampler sampler;
sampler.magFilter = in_sampler.magFilter > 0 ? in_sampler.magFilter : GL_LINEAR;
sampler.minFilter = in_sampler.minFilter > 0 ? in_sampler.minFilter : GL_LINEAR;;
sampler.wrapS = in_sampler.wrapS;
sampler.wrapT = in_sampler.wrapT;
sampler.name = in_sampler.name; // unused
mSamplers.push_back(sampler);
}
mImages.clear();
for (auto in_image : mGltfModel.images)
{
gltf_image image;
image.numChannels = in_image.component;
image.bytesPerChannel = in_image.bits >> 3; // Convert bits to bytes
image.pixelType = in_image.pixel_type; // Maps exactly, i.e. TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE == GL_UNSIGNED_BYTE, etc
image.size = static_cast<U32>(in_image.image.size());
image.height = in_image.height;
image.width = in_image.width;
image.data = in_image.image.data();
if (in_image.as_is)
{
LL_WARNS("GLTF_IMPORT") << "Unsupported image encoding" << LL_ENDL;
return false;
}
if (image.size != image.height * image.width * image.numChannels * image.bytesPerChannel)
{
LL_WARNS("GLTF_IMPORT") << "Image size error" << LL_ENDL;
return false;
}
mImages.push_back(image);
}
mTextures.clear();
for (auto in_tex : mGltfModel.textures)
{
gltf_texture tex;
tex.imageIdx = in_tex.source;
tex.samplerIdx = in_tex.sampler;
tex.imageUuid.setNull();
if (tex.imageIdx >= mImages.size() || tex.samplerIdx >= mSamplers.size())
{
LL_WARNS("GLTF_IMPORT") << "Texture sampler/image index error" << LL_ENDL;
return false;
}
mTextures.push_back(tex);
}
// parse each material
for (tinygltf::Material gltf_material : mGltfModel.materials)
{
gltf_render_material mat;
mat.name = gltf_material.name;
tinygltf::PbrMetallicRoughness& pbr = gltf_material.pbrMetallicRoughness;
mat.hasPBR = true; // Always true, for now
mat.baseColor.set(pbr.baseColorFactor.data());
mat.hasBaseTex = pbr.baseColorTexture.index >= 0;
mat.baseColorTexIdx = pbr.baseColorTexture.index;
mat.baseColorTexCoords = pbr.baseColorTexture.texCoord;
mat.metalness = pbr.metallicFactor;
mat.roughness = pbr.roughnessFactor;
mat.hasMRTex = pbr.metallicRoughnessTexture.index >= 0;
mat.metalRoughTexIdx = pbr.metallicRoughnessTexture.index;
mat.metalRoughTexCoords = pbr.metallicRoughnessTexture.texCoord;
mat.normalScale = gltf_material.normalTexture.scale;
mat.hasNormalTex = gltf_material.normalTexture.index >= 0;
mat.normalTexIdx = gltf_material.normalTexture.index;
mat.normalTexCoords = gltf_material.normalTexture.texCoord;
mat.occlusionScale = gltf_material.occlusionTexture.strength;
mat.hasOcclusionTex = gltf_material.occlusionTexture.index >= 0;
mat.occlusionTexIdx = gltf_material.occlusionTexture.index;
mat.occlusionTexCoords = gltf_material.occlusionTexture.texCoord;
mat.emissiveColor.set(gltf_material.emissiveFactor.data());
mat.hasEmissiveTex = gltf_material.emissiveTexture.index >= 0;
mat.emissiveTexIdx = gltf_material.emissiveTexture.index;
mat.emissiveTexCoords = gltf_material.emissiveTexture.texCoord;
mat.alphaMode = gltf_material.alphaMode;
mat.alphaMask = gltf_material.alphaCutoff;
if ((mat.hasNormalTex && (mat.normalTexIdx >= mTextures.size())) ||
(mat.hasOcclusionTex && (mat.occlusionTexIdx >= mTextures.size())) ||
(mat.hasEmissiveTex && (mat.emissiveTexIdx >= mTextures.size())) ||
(mat.hasBaseTex && (mat.baseColorTexIdx >= mTextures.size())) ||
(mat.hasMRTex && (mat.metalRoughTexIdx >= mTextures.size())))
{
LL_WARNS("GLTF_IMPORT") << "Texture resource index error" << LL_ENDL;
return false;
}
if ((mat.hasNormalTex && (mat.normalTexCoords > 2)) || // mesh can have up to 3 sets of UV
(mat.hasOcclusionTex && (mat.occlusionTexCoords > 2)) ||
(mat.hasEmissiveTex && (mat.emissiveTexCoords > 2)) ||
(mat.hasBaseTex && (mat.baseColorTexCoords > 2)) ||
(mat.hasMRTex && (mat.metalRoughTexCoords > 2)))
{
LL_WARNS("GLTF_IMPORT") << "Image texcoord index error" << LL_ENDL;
return false;
}
mMaterials.push_back(mat);
}
return true;
}
// TODO: convert raw vertex buffers to UUIDs
void LLGLTFLoader::uploadMeshes()
{
llassert(0);
}
// convert raw image buffers to texture UUIDs & assemble into a render material
void LLGLTFLoader::uploadMaterials()
{
for (gltf_render_material mat : mMaterials) // Initially 1 material per gltf file, but design for multiple
{
if (mat.hasBaseTex)
{
gltf_texture& gtex = mTextures[mat.baseColorTexIdx];
if (gtex.imageUuid.isNull())
{
gtex.imageUuid = imageBufferToTextureUUID(gtex);
}
}
if (mat.hasMRTex)
{
gltf_texture& gtex = mTextures[mat.metalRoughTexIdx];
if (gtex.imageUuid.isNull())
{
gtex.imageUuid = imageBufferToTextureUUID(gtex);
}
}
if (mat.hasNormalTex)
{
gltf_texture& gtex = mTextures[mat.normalTexIdx];
if (gtex.imageUuid.isNull())
{
gtex.imageUuid = imageBufferToTextureUUID(gtex);
}
}
if (mat.hasOcclusionTex)
{
gltf_texture& gtex = mTextures[mat.occlusionTexIdx];
if (gtex.imageUuid.isNull())
{
gtex.imageUuid = imageBufferToTextureUUID(gtex);
}
}
if (mat.hasEmissiveTex)
{
gltf_texture& gtex = mTextures[mat.emissiveTexIdx];
if (gtex.imageUuid.isNull())
{
gtex.imageUuid = imageBufferToTextureUUID(gtex);
}
}
}
}
LLUUID LLGLTFLoader::imageBufferToTextureUUID(const gltf_texture& tex)
{
//gltf_image& image = mImages[tex.imageIdx];
//gltf_sampler& sampler = mSamplers[tex.samplerIdx];
// fill an LLSD container with image+sampler data
// upload texture
// retrieve UUID
return LLUUID::null;
}
+206
View File
@@ -0,0 +1,206 @@
/**
* @file LLGLTFLoader.h
* @brief LLGLTFLoader class definition
*
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2022, 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$
*/
#ifndef LL_LLGLTFLoader_H
#define LL_LLGLTFLoader_H
#include "tinygltf/tiny_gltf.h"
#include "llglheaders.h"
#include "llmodelloader.h"
// gltf_* structs are temporary, used to organize the subset of data that eventually goes into the material LLSD
class gltf_sampler
{
public:
// Uses GL enums
S32 minFilter; // GL_NEAREST, GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR or GL_LINEAR_MIPMAP_LINEAR
S32 magFilter; // GL_NEAREST or GL_LINEAR
S32 wrapS; // GL_CLAMP_TO_EDGE, GL_MIRRORED_REPEAT or GL_REPEAT
S32 wrapT; // GL_CLAMP_TO_EDGE, GL_MIRRORED_REPEAT or GL_REPEAT
//S32 wrapR; // Found in some sample files, but not part of glTF 2.0 spec. Ignored.
std::string name; // optional, currently unused
// extensions and extras are sampler optional fields that we don't support - at least initially
};
class gltf_image
{
public:// Note that glTF images are defined with row 0 at the top (opposite of OpenGL)
U8* data; // ptr to decoded image data
U32 size; // in bytes, regardless of channel width
U32 width;
U32 height;
U32 numChannels; // range 1..4
U32 bytesPerChannel; // converted from gltf "bits", expects only 8, 16 or 32 as input
U32 pixelType; // one of (TINYGLTF_COMPONENT_TYPE)_UNSIGNED_BYTE, _UNSIGNED_SHORT, _UNSIGNED_INT, or _FLOAT
};
class gltf_texture
{
public:
U32 imageIdx;
U32 samplerIdx;
LLUUID imageUuid = LLUUID::null;
};
class gltf_render_material
{
public:
std::string name;
// scalar values
LLColor4 baseColor; // linear encoding. Multiplied with vertex color, if present.
double metalness;
double roughness;
double normalScale; // scale applies only to X,Y components of normal
double occlusionScale; // strength multiplier for occlusion
LLColor4 emissiveColor; // emissive mulitiplier, assumed linear encoding (spec 2.0 is silent)
std::string alphaMode; // "OPAQUE", "MASK" or "BLEND"
double alphaMask; // alpha cut-off
// textures
U32 baseColorTexIdx; // always sRGB encoded
U32 metalRoughTexIdx; // always linear, roughness in G channel, metalness in B channel
U32 normalTexIdx; // linear, valid range R[0-1], G[0-1], B[0.5-1]. Normal = texel * 2 - vec3(1.0)
U32 occlusionTexIdx; // linear, occlusion in R channel, 0 meaning fully occluded, 1 meaning not occluded
U32 emissiveTexIdx; // always stored as sRGB, in nits (candela / meter^2)
// texture coordinates
U32 baseColorTexCoords;
U32 metalRoughTexCoords;
U32 normalTexCoords;
U32 occlusionTexCoords;
U32 emissiveTexCoords;
// TODO: Add traditional (diffuse, normal, specular) UUIDs here, or add this struct to LL_TextureEntry??
bool hasPBR;
bool hasBaseTex, hasMRTex, hasNormalTex, hasOcclusionTex, hasEmissiveTex;
// This field is populated after upload
LLUUID material_uuid = LLUUID::null;
};
class gltf_mesh
{
public:
std::string name;
// TODO add mesh import DJH 2022-04
};
class LLGLTFLoader : public LLModelLoader
{
public:
typedef std::map<std::string, LLImportMaterial> material_map;
LLGLTFLoader(std::string filename,
S32 lod,
LLModelLoader::load_callback_t load_cb,
LLModelLoader::joint_lookup_func_t joint_lookup_func,
LLModelLoader::texture_load_func_t texture_load_func,
LLModelLoader::state_callback_t state_cb,
void * opaque_userdata,
JointTransformMap & jointTransformMap,
JointNameSet & jointsFromNodes,
std::map<std::string, std::string,std::less<>> &jointAliasMap,
U32 maxJointsPerMesh,
U32 modelLimit); //,
//bool preprocess );
virtual ~LLGLTFLoader();
virtual bool OpenFile(const std::string &filename);
protected:
tinygltf::Model mGltfModel;
bool mGltfLoaded;
bool mMeshesLoaded;
bool mMaterialsLoaded;
std::vector<gltf_mesh> mMeshes;
std::vector<gltf_render_material> mMaterials;
std::vector<gltf_texture> mTextures;
std::vector<gltf_image> mImages;
std::vector<gltf_sampler> mSamplers;
private:
bool parseMeshes();
void uploadMeshes();
bool parseMaterials();
void uploadMaterials();
bool populateModelFromMesh(LLModel* pModel, const tinygltf::Mesh &mesh);
LLUUID imageBufferToTextureUUID(const gltf_texture& tex);
// bool mPreprocessGLTF;
/* Below inherited from dae loader - unknown if/how useful here
void processElement(gltfElement *element, bool &badElement, GLTF *gltf);
void processGltfModel(LLModel *model, GLTF *gltf, gltfElement *pRoot, gltfMesh *mesh, gltfSkin *skin);
material_map getMaterials(LLModel *model, gltfInstance_geometry *instance_geo, GLTF *gltf);
LLImportMaterial profileToMaterial(gltfProfile_COMMON *material, GLTF *gltf);
LLColor4 getGltfColor(gltfElement *element);
gltfElement *getChildFromElement(gltfElement *pElement, std::string const &name);
bool isNodeAJoint(gltfNode *pNode);
void processJointNode(gltfNode *pNode, std::map<std::string, LLMatrix4> &jointTransforms);
void extractTranslation(gltfTranslate *pTranslate, LLMatrix4 &transform);
void extractTranslationViaElement(gltfElement *pTranslateElement, LLMatrix4 &transform);
void extractTranslationViaSID(gltfElement *pElement, LLMatrix4 &transform);
void buildJointToNodeMappingFromScene(gltfElement *pRoot);
void processJointToNodeMapping(gltfNode *pNode);
void processChildJoints(gltfNode *pParentNode);
bool verifyCount(int expected, int result);
// Verify that a controller matches vertex counts
bool verifyController(gltfController *pController);
static bool addVolumeFacesFromGltfMesh(LLModel *model, gltfMesh *mesh, LLSD &log_msg);
static bool createVolumeFacesFromGltfMesh(LLModel *model, gltfMesh *mesh);
static LLModel *loadModelFromGltfMesh(gltfMesh *mesh);
// Loads a mesh breaking it into one or more models as necessary
// to get around volume face limitations while retaining >8 materials
//
bool loadModelsFromGltfMesh(gltfMesh *mesh, std::vector<LLModel *> &models_out, U32 submodel_limit);
static std::string getElementLabel(gltfElement *element);
static size_t getSuffixPosition(std::string label);
static std::string getLodlessLabel(gltfElement *element);
static std::string preprocessGLTF(std::string filename);
*/
};
#endif // LL_LLGLTFLLOADER_H
+925
View File
@@ -0,0 +1,925 @@
/**
* @file llgltfmaterial.cpp
* @brief Material definition
*
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2022, 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 "linden_common.h"
#include "llgltfmaterial.h"
#include "llsdserialize.h"
// NOTE -- this should be the one and only place tiny_gltf.h is included
#include "tinygltf/tiny_gltf.h"
#include "llgltfmaterial_templates.h"
const char* const LLGLTFMaterial::ASSET_VERSION = "1.1";
const char* const LLGLTFMaterial::ASSET_TYPE = "GLTF 2.0";
const std::array<std::string, 2> LLGLTFMaterial::ACCEPTED_ASSET_VERSIONS = { "1.0", "1.1" };
const char* const LLGLTFMaterial::GLTF_FILE_EXTENSION_TRANSFORM = "KHR_texture_transform";
const char* const LLGLTFMaterial::GLTF_FILE_EXTENSION_TRANSFORM_SCALE = "scale";
const char* const LLGLTFMaterial::GLTF_FILE_EXTENSION_TRANSFORM_OFFSET = "offset";
const char* const LLGLTFMaterial::GLTF_FILE_EXTENSION_TRANSFORM_ROTATION = "rotation";
// special UUID that indicates a null UUID in override data
const LLUUID LLGLTFMaterial::GLTF_OVERRIDE_NULL_UUID = LLUUID("ffffffff-ffff-ffff-ffff-ffffffffffff");
LLGLTFMaterial::LLGLTFMaterial()
{
// IMPORTANT: since we use the hash of the member variables memory block of
// this class to detect changes, we must ensure that all its padding bytes
// have been zeroed out. But of course, we must leave the LLRefCount member
// variable untouched (and skip it when hashing), and we cannot either
// touch the local texture overrides map (else we destroy pointers, and
// sundry private data, which would lead to a crash when using that map).
// The variable members have therefore been arranged so that anything,
// starting at mLocalTexDataDigest and up to the end of the members, can be
// safely zeroed. HB
const size_t offset = intptr_t(&mLocalTexDataDigest) - intptr_t(this);
memset((void*)((const char*)this + offset), 0, sizeof(*this) - offset);
// Now that we zeroed out our member variables, we can set the ones that
// should not be zero to their default value. HB
mBaseColor.set(1.f, 1.f, 1.f, 1.f);
mMetallicFactor = mRoughnessFactor = 1.f;
mAlphaCutoff = 0.5f;
for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)
{
mTextureTransform[i].mScale.set(1.f, 1.f);
#if 0
mTextureTransform[i].mOffset.clear();
mTextureTransform[i].mRotation = 0.f;
#endif
}
#if 0
mLocalTexDataDigest = 0;
mAlphaMode = ALPHA_MODE_OPAQUE; // This is 0
mOverrideDoubleSided = mOverrideAlphaMode = false;
#endif
}
void LLGLTFMaterial::TextureTransform::getPacked(Pack& packed) const
{
packed[0] = mScale.mV[VX];
packed[1] = mScale.mV[VY];
packed[2] = mRotation;
packed[4] = mOffset.mV[VX];
packed[5] = mOffset.mV[VY];
// Not used but nonetheless zeroed for proper hashing. HB
packed[3] = packed[6] = packed[7] = 0.f;
}
void LLGLTFMaterial::TextureTransform::getPackedTight(PackTight& packed) const
{
packed[0] = mScale.mV[VX];
packed[1] = mScale.mV[VY];
packed[2] = mRotation;
packed[3] = mOffset.mV[VX];
packed[4] = mOffset.mV[VY];
}
bool LLGLTFMaterial::TextureTransform::operator==(const TextureTransform& other) const
{
return mOffset == other.mOffset && mScale == other.mScale && mRotation == other.mRotation;
}
LLGLTFMaterial::LLGLTFMaterial(const LLGLTFMaterial& rhs)
{
*this = rhs;
}
LLGLTFMaterial& LLGLTFMaterial::operator=(const LLGLTFMaterial& rhs)
{
//have to do a manual operator= because of LLRefCount
mTextureId = rhs.mTextureId;
mTextureTransform = rhs.mTextureTransform;
mBaseColor = rhs.mBaseColor;
mEmissiveColor = rhs.mEmissiveColor;
mMetallicFactor = rhs.mMetallicFactor;
mRoughnessFactor = rhs.mRoughnessFactor;
mAlphaCutoff = rhs.mAlphaCutoff;
mDoubleSided = rhs.mDoubleSided;
mAlphaMode = rhs.mAlphaMode;
mOverrideDoubleSided = rhs.mOverrideDoubleSided;
mOverrideAlphaMode = rhs.mOverrideAlphaMode;
if (rhs.mTrackingIdToLocalTexture.empty())
{
mTrackingIdToLocalTexture.clear();
mLocalTexDataDigest = 0;
}
else
{
mTrackingIdToLocalTexture = rhs.mTrackingIdToLocalTexture;
updateLocalTexDataDigest();
updateTextureTracking();
}
return *this;
}
void LLGLTFMaterial::updateLocalTexDataDigest()
{
mLocalTexDataDigest = 0;
if (!mTrackingIdToLocalTexture.empty())
{
for (local_tex_map_t::const_iterator
it = mTrackingIdToLocalTexture.begin(),
end = mTrackingIdToLocalTexture.end();
it != end; ++it)
{
mLocalTexDataDigest ^= it->first.getDigest64() ^
it->second.getDigest64();
}
}
}
bool LLGLTFMaterial::operator==(const LLGLTFMaterial& rhs) const
{
return mTextureId == rhs.mTextureId &&
mTextureTransform == rhs.mTextureTransform &&
mBaseColor == rhs.mBaseColor &&
mEmissiveColor == rhs.mEmissiveColor &&
mMetallicFactor == rhs.mMetallicFactor &&
mRoughnessFactor == rhs.mRoughnessFactor &&
mAlphaCutoff == rhs.mAlphaCutoff &&
mDoubleSided == rhs.mDoubleSided &&
mAlphaMode == rhs.mAlphaMode &&
mOverrideDoubleSided == rhs.mOverrideDoubleSided &&
mOverrideAlphaMode == rhs.mOverrideAlphaMode;
}
bool LLGLTFMaterial::fromJSON(const std::string& json, std::string& warn_msg, std::string& error_msg)
{
LL_PROFILE_ZONE_SCOPED;
tinygltf::TinyGLTF gltf;
tinygltf::Model model_in;
if (gltf.LoadASCIIFromString(&model_in, &error_msg, &warn_msg, json.c_str(), static_cast<unsigned int>(json.length()), ""))
{
setFromModel(model_in, 0);
return true;
}
return false;
}
std::string LLGLTFMaterial::asJSON(bool prettyprint) const
{
LL_PROFILE_ZONE_SCOPED;
tinygltf::TinyGLTF gltf;
tinygltf::Model model_out;
std::ostringstream str;
writeToModel(model_out, 0);
// To ensure consistency in asset upload, this should be the only reference
// to WriteGltfSceneToStream in the viewer.
gltf.WriteGltfSceneToStream(&model_out, str, prettyprint, false);
return str.str();
}
void LLGLTFMaterial::setFromModel(const tinygltf::Model& model, S32 mat_index)
{
LL_PROFILE_ZONE_SCOPED;
if (model.materials.size() <= mat_index)
{
return;
}
const tinygltf::Material& material_in = model.materials[mat_index];
// Apply base color texture
setFromTexture(model, material_in.pbrMetallicRoughness.baseColorTexture, GLTF_TEXTURE_INFO_BASE_COLOR);
// Apply normal map
setFromTexture(model, material_in.normalTexture, GLTF_TEXTURE_INFO_NORMAL);
// Apply metallic-roughness texture
setFromTexture(model, material_in.pbrMetallicRoughness.metallicRoughnessTexture, GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS);
// Apply emissive texture
setFromTexture(model, material_in.emissiveTexture, GLTF_TEXTURE_INFO_EMISSIVE);
setAlphaMode(material_in.alphaMode);
mAlphaCutoff = llclamp((F32)material_in.alphaCutoff, 0.f, 1.f);
mBaseColor.set(material_in.pbrMetallicRoughness.baseColorFactor);
mEmissiveColor.set(material_in.emissiveFactor);
mMetallicFactor = llclamp((F32)material_in.pbrMetallicRoughness.metallicFactor, 0.f, 1.f);
mRoughnessFactor = llclamp((F32)material_in.pbrMetallicRoughness.roughnessFactor, 0.f, 1.f);
mDoubleSided = material_in.doubleSided;
if (material_in.extras.IsObject())
{
tinygltf::Value::Object extras = material_in.extras.Get<tinygltf::Value::Object>();
const auto& alpha_mode = extras.find("override_alpha_mode");
if (alpha_mode != extras.end())
{
mOverrideAlphaMode = alpha_mode->second.Get<bool>();
}
const auto& double_sided = extras.find("override_double_sided");
if (double_sided != extras.end())
{
mOverrideDoubleSided = double_sided->second.Get<bool>();
}
}
}
// static
LLVector2 LLGLTFMaterial::vec2FromJson(const tinygltf::Value::Object& object, const char* key, const LLVector2& default_value)
{
const auto it = object.find(key);
if (it == object.end())
{
return default_value;
}
const tinygltf::Value& vec2_json = std::get<1>(*it);
if (!vec2_json.IsArray() || vec2_json.ArrayLen() < LENGTHOFVECTOR2)
{
return default_value;
}
LLVector2 value;
for (U32 i = 0; i < LENGTHOFVECTOR2; ++i)
{
const tinygltf::Value& real_json = vec2_json.Get(i);
if (!real_json.IsReal())
{
return default_value;
}
value.mV[i] = (F32)real_json.Get<double>();
}
return value;
}
// static
F32 LLGLTFMaterial::floatFromJson(const tinygltf::Value::Object& object, const char* key, const F32 default_value)
{
const auto it = object.find(key);
if (it == object.end())
{
return default_value;
}
const tinygltf::Value& real_json = std::get<1>(*it);
if (!real_json.IsReal())
{
return default_value;
}
return (F32)real_json.GetNumberAsDouble();
}
void LLGLTFMaterial::writeToModel(tinygltf::Model& model, S32 mat_index) const
{
LL_PROFILE_ZONE_SCOPED;
if (model.materials.size() < mat_index+1)
{
model.materials.resize(mat_index + 1);
}
tinygltf::Material& material_out = model.materials[mat_index];
// set base color texture
writeToTexture(model, material_out.pbrMetallicRoughness.baseColorTexture, GLTF_TEXTURE_INFO_BASE_COLOR);
// set normal texture
writeToTexture(model, material_out.normalTexture, GLTF_TEXTURE_INFO_NORMAL);
// set metallic-roughness texture
writeToTexture(model, material_out.pbrMetallicRoughness.metallicRoughnessTexture, GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS);
// set emissive texture
writeToTexture(model, material_out.emissiveTexture, GLTF_TEXTURE_INFO_EMISSIVE);
// set occlusion texture
// *NOTE: This is required for ORM materials for GLTF compliance.
// See: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#_material_occlusiontexture
writeToTexture(model, material_out.occlusionTexture, GLTF_TEXTURE_INFO_OCCLUSION);
material_out.alphaMode = getAlphaMode();
material_out.alphaCutoff = mAlphaCutoff;
mBaseColor.write(material_out.pbrMetallicRoughness.baseColorFactor);
if (mEmissiveColor != LLGLTFMaterial::getDefaultEmissiveColor())
{
material_out.emissiveFactor.resize(3);
mEmissiveColor.write(material_out.emissiveFactor);
}
material_out.pbrMetallicRoughness.metallicFactor = mMetallicFactor;
material_out.pbrMetallicRoughness.roughnessFactor = mRoughnessFactor;
material_out.doubleSided = mDoubleSided;
// generate "extras" string
tinygltf::Value::Object extras;
bool write_extras = false;
if (mOverrideAlphaMode && mAlphaMode == getDefaultAlphaMode())
{
extras["override_alpha_mode"] = tinygltf::Value(mOverrideAlphaMode);
write_extras = true;
}
if (mOverrideDoubleSided && mDoubleSided == getDefaultDoubleSided())
{
extras["override_double_sided"] = tinygltf::Value(mOverrideDoubleSided);
write_extras = true;
}
if (write_extras)
{
material_out.extras = tinygltf::Value(extras);
}
model.asset.version = "2.0";
}
void LLGLTFMaterial::sanitizeAssetMaterial()
{
mTextureTransform = sDefault.mTextureTransform;
}
bool LLGLTFMaterial::setBaseMaterial()
{
const LLGLTFMaterial old_override = *this;
*this = sDefault;
setBaseMaterial(old_override);
return *this != old_override;
}
// For material overrides only. Copies transforms from the old override.
void LLGLTFMaterial::setBaseMaterial(const LLGLTFMaterial& old_override_mat)
{
mTextureTransform = old_override_mat.mTextureTransform;
}
bool LLGLTFMaterial::isClearedForBaseMaterial() const
{
LLGLTFMaterial cleared_override = sDefault;
cleared_override.setBaseMaterial(*this);
return *this == cleared_override;
}
// static
void LLGLTFMaterial::hackOverrideUUID(LLUUID& id)
{
if (id == LLUUID::null)
{
id = GLTF_OVERRIDE_NULL_UUID;
}
}
void LLGLTFMaterial::setTextureId(TextureInfo texture_info, const LLUUID& id, bool for_override)
{
mTextureId[texture_info] = id;
if (for_override)
{
hackOverrideUUID(mTextureId[texture_info]);
}
}
void LLGLTFMaterial::setBaseColorId(const LLUUID& id, bool for_override)
{
setTextureId(GLTF_TEXTURE_INFO_BASE_COLOR, id, for_override);
}
void LLGLTFMaterial::setNormalId(const LLUUID& id, bool for_override)
{
setTextureId(GLTF_TEXTURE_INFO_NORMAL, id, for_override);
}
void LLGLTFMaterial::setOcclusionRoughnessMetallicId(const LLUUID& id, bool for_override)
{
setTextureId(GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS, id, for_override);
}
void LLGLTFMaterial::setEmissiveId(const LLUUID& id, bool for_override)
{
setTextureId(GLTF_TEXTURE_INFO_EMISSIVE, id, for_override);
}
void LLGLTFMaterial::setBaseColorFactor(const LLColor4& baseColor, bool for_override)
{
mBaseColor.set(baseColor);
mBaseColor.clamp();
if (for_override)
{ // hack -- nudge off of default value
if (mBaseColor == getDefaultBaseColor())
{
mBaseColor.mV[3] -= FLT_EPSILON;
}
}
}
void LLGLTFMaterial::setAlphaCutoff(F32 cutoff, bool for_override)
{
mAlphaCutoff = llclamp(cutoff, 0.f, 1.f);
if (for_override)
{ // hack -- nudge off of default value
if (mAlphaCutoff == getDefaultAlphaCutoff())
{
mAlphaCutoff -= FLT_EPSILON;
}
}
}
void LLGLTFMaterial::setEmissiveColorFactor(const LLColor3& emissiveColor, bool for_override)
{
mEmissiveColor = emissiveColor;
mEmissiveColor.clamp();
if (for_override)
{ // hack -- nudge off of default value
if (mEmissiveColor == getDefaultEmissiveColor())
{
mEmissiveColor.mV[0] += FLT_EPSILON;
}
}
}
void LLGLTFMaterial::setMetallicFactor(F32 metallic, bool for_override)
{
mMetallicFactor = llclamp(metallic, 0.f, for_override ? 1.f - FLT_EPSILON : 1.f);
}
void LLGLTFMaterial::setRoughnessFactor(F32 roughness, bool for_override)
{
mRoughnessFactor = llclamp(roughness, 0.f, for_override ? 1.f - FLT_EPSILON : 1.f);
}
void LLGLTFMaterial::setAlphaMode(const std::string& mode, bool for_override)
{
S32 m = getDefaultAlphaMode();
if (mode == "MASK")
{
m = ALPHA_MODE_MASK;
}
else if (mode == "BLEND")
{
m = ALPHA_MODE_BLEND;
}
setAlphaMode(m, for_override);
}
const char* LLGLTFMaterial::getAlphaMode() const
{
switch (mAlphaMode)
{
case ALPHA_MODE_MASK: return "MASK";
case ALPHA_MODE_BLEND: return "BLEND";
default: return "OPAQUE";
}
}
void LLGLTFMaterial::setAlphaMode(S32 mode, bool for_override)
{
mAlphaMode = (AlphaMode) llclamp(mode, (S32) ALPHA_MODE_OPAQUE, (S32) ALPHA_MODE_MASK);
mOverrideAlphaMode = for_override && mAlphaMode == getDefaultAlphaMode();
}
void LLGLTFMaterial::setDoubleSided(bool double_sided, bool for_override)
{
// sure, no clamping will ever be needed for a bool, but include the
// setter for consistency with the clamping API
mDoubleSided = double_sided;
mOverrideDoubleSided = for_override && mDoubleSided == getDefaultDoubleSided();
}
void LLGLTFMaterial::setTextureOffset(TextureInfo texture_info, const LLVector2& offset)
{
mTextureTransform[texture_info].mOffset = offset;
}
void LLGLTFMaterial::setTextureScale(TextureInfo texture_info, const LLVector2& scale)
{
mTextureTransform[texture_info].mScale = scale;
}
void LLGLTFMaterial::setTextureRotation(TextureInfo texture_info, float rotation)
{
mTextureTransform[texture_info].mRotation = rotation;
}
// Default value accessors (NOTE: these MUST match the GLTF specification)
// Make a static default material for accessors
const LLGLTFMaterial LLGLTFMaterial::sDefault;
F32 LLGLTFMaterial::getDefaultAlphaCutoff()
{
return sDefault.mAlphaCutoff;
}
S32 LLGLTFMaterial::getDefaultAlphaMode()
{
return (S32) sDefault.mAlphaMode;
}
F32 LLGLTFMaterial::getDefaultMetallicFactor()
{
return sDefault.mMetallicFactor;
}
F32 LLGLTFMaterial::getDefaultRoughnessFactor()
{
return sDefault.mRoughnessFactor;
}
LLColor4 LLGLTFMaterial::getDefaultBaseColor()
{
return sDefault.mBaseColor;
}
LLColor3 LLGLTFMaterial::getDefaultEmissiveColor()
{
return sDefault.mEmissiveColor;
}
bool LLGLTFMaterial::getDefaultDoubleSided()
{
return sDefault.mDoubleSided;
}
LLVector2 LLGLTFMaterial::getDefaultTextureOffset()
{
return sDefault.mTextureTransform[0].mOffset;
}
LLVector2 LLGLTFMaterial::getDefaultTextureScale()
{
return sDefault.mTextureTransform[0].mScale;
}
F32 LLGLTFMaterial::getDefaultTextureRotation()
{
return sDefault.mTextureTransform[0].mRotation;
}
// static
void LLGLTFMaterial::applyOverrideUUID(LLUUID& dst_id, const LLUUID& override_id)
{
if (override_id != GLTF_OVERRIDE_NULL_UUID)
{
if (override_id != LLUUID::null)
{
dst_id = override_id;
}
}
else
{
dst_id = LLUUID::null;
}
}
void LLGLTFMaterial::applyOverride(const LLGLTFMaterial& override_mat)
{
LL_PROFILE_ZONE_SCOPED;
for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)
{
LLUUID& texture_id = mTextureId[i];
const LLUUID& override_texture_id = override_mat.mTextureId[i];
applyOverrideUUID(texture_id, override_texture_id);
}
if (override_mat.mBaseColor != getDefaultBaseColor())
{
mBaseColor = override_mat.mBaseColor;
}
if (override_mat.mEmissiveColor != getDefaultEmissiveColor())
{
mEmissiveColor = override_mat.mEmissiveColor;
}
if (override_mat.mMetallicFactor != getDefaultMetallicFactor())
{
mMetallicFactor = override_mat.mMetallicFactor;
}
if (override_mat.mRoughnessFactor != getDefaultRoughnessFactor())
{
mRoughnessFactor = override_mat.mRoughnessFactor;
}
if (override_mat.mAlphaMode != getDefaultAlphaMode() || override_mat.mOverrideAlphaMode)
{
mAlphaMode = override_mat.mAlphaMode;
}
if (override_mat.mAlphaCutoff != getDefaultAlphaCutoff())
{
mAlphaCutoff = override_mat.mAlphaCutoff;
}
if (override_mat.mDoubleSided != getDefaultDoubleSided() || override_mat.mOverrideDoubleSided)
{
mDoubleSided = override_mat.mDoubleSided;
}
for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)
{
if (override_mat.mTextureTransform[i].mOffset != getDefaultTextureOffset())
{
mTextureTransform[i].mOffset = override_mat.mTextureTransform[i].mOffset;
}
if (override_mat.mTextureTransform[i].mScale != getDefaultTextureScale())
{
mTextureTransform[i].mScale = override_mat.mTextureTransform[i].mScale;
}
if (override_mat.mTextureTransform[i].mRotation != getDefaultTextureRotation())
{
mTextureTransform[i].mRotation = override_mat.mTextureTransform[i].mRotation;
}
}
if (!override_mat.mTrackingIdToLocalTexture.empty())
{
auto it = override_mat.mTrackingIdToLocalTexture.begin();
mTrackingIdToLocalTexture.insert(it, it);
updateLocalTexDataDigest();
updateTextureTracking();
}
}
void LLGLTFMaterial::getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& data) const
{
LL_PROFILE_ZONE_SCOPED;
llassert(data.isUndefined());
// make every effort to shave bytes here
for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)
{
const LLUUID& texture_id = mTextureId[i];
const LLUUID& override_texture_id = override_mat.mTextureId[i];
if (override_texture_id.notNull() && override_texture_id != texture_id)
{
data["tex"][i] = LLSD::UUID(override_texture_id);
}
}
if (override_mat.mBaseColor != getDefaultBaseColor())
{
data["bc"] = override_mat.mBaseColor.getValue();
}
if (override_mat.mEmissiveColor != getDefaultEmissiveColor())
{
data["ec"] = override_mat.mEmissiveColor.getValue();
}
if (override_mat.mMetallicFactor != getDefaultMetallicFactor())
{
data["mf"] = override_mat.mMetallicFactor;
}
if (override_mat.mRoughnessFactor != getDefaultRoughnessFactor())
{
data["rf"] = override_mat.mRoughnessFactor;
}
if (override_mat.mAlphaMode != getDefaultAlphaMode() || override_mat.mOverrideAlphaMode)
{
data["am"] = override_mat.mAlphaMode;
}
if (override_mat.mAlphaCutoff != getDefaultAlphaCutoff())
{
data["ac"] = override_mat.mAlphaCutoff;
}
if (override_mat.mDoubleSided != getDefaultDoubleSided() || override_mat.mOverrideDoubleSided)
{
data["ds"] = override_mat.mDoubleSided;
}
for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)
{
if (override_mat.mTextureTransform[i].mOffset != getDefaultTextureOffset())
{
data["ti"][i]["o"] = override_mat.mTextureTransform[i].mOffset.getValue();
}
if (override_mat.mTextureTransform[i].mScale != getDefaultTextureScale())
{
data["ti"][i]["s"] = override_mat.mTextureTransform[i].mScale.getValue();
}
if (override_mat.mTextureTransform[i].mRotation != getDefaultTextureRotation())
{
data["ti"][i]["r"] = override_mat.mTextureTransform[i].mRotation;
}
}
}
void LLGLTFMaterial::applyOverrideLLSD(const LLSD& data)
{
const LLSD& tex = data["tex"];
if (tex.isArray())
{
for (int i = 0; i < tex.size(); ++i)
{
mTextureId[i] = tex[i].asUUID();
}
}
const LLSD& bc = data["bc"];
if (bc.isDefined())
{
mBaseColor.setValue(bc);
if (mBaseColor == getDefaultBaseColor())
{
// HACK -- nudge by epsilon if we receive a default value (indicates override to default)
mBaseColor.mV[3] -= FLT_EPSILON;
}
}
const LLSD& ec = data["ec"];
if (ec.isDefined())
{
mEmissiveColor.setValue(ec);
if (mEmissiveColor == getDefaultEmissiveColor())
{
// HACK -- nudge by epsilon if we receive a default value (indicates override to default)
mEmissiveColor.mV[0] += FLT_EPSILON;
}
}
const LLSD& mf = data["mf"];
if (mf.isReal())
{
mMetallicFactor = (F32)mf.asReal();
if (mMetallicFactor == getDefaultMetallicFactor())
{
// HACK -- nudge by epsilon if we receive a default value (indicates override to default)
mMetallicFactor -= FLT_EPSILON;
}
}
const LLSD& rf = data["rf"];
if (rf.isReal())
{
mRoughnessFactor = (F32)rf.asReal();
if (mRoughnessFactor == getDefaultRoughnessFactor())
{
// HACK -- nudge by epsilon if we receive a default value (indicates override to default)
mRoughnessFactor -= FLT_EPSILON;
}
}
const LLSD& am = data["am"];
if (am.isInteger())
{
mAlphaMode = (AlphaMode) am.asInteger();
mOverrideAlphaMode = true;
}
const LLSD& ac = data["ac"];
if (ac.isReal())
{
mAlphaCutoff = (F32)ac.asReal();
if (mAlphaCutoff == getDefaultAlphaCutoff())
{
// HACK -- nudge by epsilon if we receive a default value (indicates override to default)
mAlphaCutoff -= FLT_EPSILON;
}
}
const LLSD& ds = data["ds"];
if (ds.isBoolean())
{
mDoubleSided = ds.asBoolean();
mOverrideDoubleSided = true;
}
const LLSD& ti = data["ti"];
if (ti.isArray())
{
for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)
{
const LLSD& o = ti[i]["o"];
if (o.isDefined())
{
mTextureTransform[i].mOffset.setValue(o);
}
const LLSD& s = ti[i]["s"];
if (s.isDefined())
{
mTextureTransform[i].mScale.setValue(s);
}
const LLSD& r = ti[i]["r"];
if (r.isReal())
{
mTextureTransform[i].mRotation = (F32)r.asReal();
}
}
}
}
LLUUID LLGLTFMaterial::getHash() const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
// *HACK: hash the bytes of this object but do not include the ref count
// neither the local texture overrides (which is a map, with pointers to
// key/value pairs that would change from one LLGLTFMaterial instance to
// the other, even though the key/value pairs could be the same, and stored
// elsewhere in the memory heap or on the stack).
// Note: this does work properly to compare two LLGLTFMaterial instances
// only because the padding bytes between their member variables have been
// dutifully zeroed in the constructor. HB
const size_t offset = intptr_t(&mLocalTexDataDigest) - intptr_t(this);
return HBXXH128::digest((const void*)((const char*)this + offset),
sizeof(*this) - offset);
}
void LLGLTFMaterial::addLocalTextureTracking(const LLUUID& tracking_id, const LLUUID& tex_id)
{
mTrackingIdToLocalTexture[tracking_id] = tex_id;
updateLocalTexDataDigest();
}
void LLGLTFMaterial::removeLocalTextureTracking(const LLUUID& tracking_id)
{
mTrackingIdToLocalTexture.erase(tracking_id);
updateLocalTexDataDigest();
}
bool LLGLTFMaterial::replaceLocalTexture(const LLUUID& tracking_id, const LLUUID& old_id, const LLUUID& new_id)
{
bool res = false;
for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)
{
if (mTextureId[i] == old_id)
{
mTextureId[i] = new_id;
res = true;
}
else if (mTextureId[i] == new_id)
{
res = true;
}
}
if (res)
{
mTrackingIdToLocalTexture[tracking_id] = new_id;
}
else
{
mTrackingIdToLocalTexture.erase(tracking_id);
}
updateLocalTexDataDigest();
return res;
}
void LLGLTFMaterial::updateTextureTracking()
{
// setTEGLTFMaterialOverride is responsible for tracking
// for material overrides editor will set it
}
+278
View File
@@ -0,0 +1,278 @@
/**
* @file llgltfmaterial.h
* @brief Material definition
*
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2022, 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$
*/
#pragma once
#include "llrefcount.h"
#include "llmemory.h"
#include "v4color.h"
#include "v3color.h"
#include "v2math.h"
#include "lluuid.h"
#include "hbxxh.h"
#include <array>
#include <string>
#include <map>
namespace tinygltf
{
class Model;
struct TextureInfo;
class Value;
}
class LLTextureEntry;
class LLGLTFMaterial : public LLRefCount
{
public:
// default material for reference
static const LLGLTFMaterial sDefault;
static const char* const ASSET_VERSION;
static const char* const ASSET_TYPE;
// Max allowed size of a GLTF material asset or override, when serialized
// as a minified JSON string
static constexpr size_t MAX_ASSET_LENGTH = 2048;
static const std::array<std::string, 2> ACCEPTED_ASSET_VERSIONS;
static bool isAcceptedVersion(const std::string& version) { return std::find(ACCEPTED_ASSET_VERSIONS.cbegin(), ACCEPTED_ASSET_VERSIONS.cend(), version) != ACCEPTED_ASSET_VERSIONS.cend(); }
struct TextureTransform
{
LLVector2 mOffset = { 0.f, 0.f };
LLVector2 mScale = { 1.f, 1.f };
F32 mRotation = 0.f;
static const size_t PACK_SIZE = 8;
static const size_t PACK_TIGHT_SIZE = 5;
using Pack = F32[PACK_SIZE];
using PackTight = F32[PACK_TIGHT_SIZE];
void getPacked(Pack& packed) const;
void getPackedTight(PackTight& packed) const;
bool operator==(const TextureTransform& other) const;
bool operator!=(const TextureTransform& other) const { return !(*this == other); }
};
enum AlphaMode
{
ALPHA_MODE_OPAQUE = 0,
ALPHA_MODE_BLEND,
ALPHA_MODE_MASK
};
LLGLTFMaterial();
LLGLTFMaterial(const LLGLTFMaterial& rhs);
LLGLTFMaterial& operator=(const LLGLTFMaterial& rhs);
bool operator==(const LLGLTFMaterial& rhs) const;
bool operator!=(const LLGLTFMaterial& rhs) const { return !(*this == rhs); }
enum TextureInfo : U32
{
GLTF_TEXTURE_INFO_BASE_COLOR,
GLTF_TEXTURE_INFO_NORMAL,
GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS,
// *NOTE: GLTF_TEXTURE_INFO_OCCLUSION is currently ignored, in favor of
// the values specified with GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS.
// Currently, only ORM materials are supported (materials which define
// occlusion, roughness, and metallic in the same texture).
// -Cosmic,2023-01-26
GLTF_TEXTURE_INFO_OCCLUSION = GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS,
GLTF_TEXTURE_INFO_EMISSIVE,
GLTF_TEXTURE_INFO_COUNT
};
static const char* const GLTF_FILE_EXTENSION_TRANSFORM;
static const char* const GLTF_FILE_EXTENSION_TRANSFORM_SCALE;
static const char* const GLTF_FILE_EXTENSION_TRANSFORM_OFFSET;
static const char* const GLTF_FILE_EXTENSION_TRANSFORM_ROTATION;
static const LLUUID GLTF_OVERRIDE_NULL_UUID;
// get a UUID based on a hash of this LLGLTFMaterial
LLUUID getHash() const;
//setters for various members (will clamp to acceptable ranges)
// for_override - set to true if this value is being set as part of an override (important for handling override to default value)
void setTextureId(TextureInfo texture_info, const LLUUID& id, bool for_override = false);
void setBaseColorId(const LLUUID& id, bool for_override = false);
void setNormalId(const LLUUID& id, bool for_override = false);
void setOcclusionRoughnessMetallicId(const LLUUID& id, bool for_override = false);
void setEmissiveId(const LLUUID& id, bool for_override = false);
void setBaseColorFactor(const LLColor4& baseColor, bool for_override = false);
void setAlphaCutoff(F32 cutoff, bool for_override = false);
void setEmissiveColorFactor(const LLColor3& emissiveColor, bool for_override = false);
void setMetallicFactor(F32 metallic, bool for_override = false);
void setRoughnessFactor(F32 roughness, bool for_override = false);
void setAlphaMode(S32 mode, bool for_override = false);
void setDoubleSided(bool double_sided, bool for_override = false);
// *NOTE: texture offsets only exist in overrides, so "for_override" is not needed
void setTextureOffset(TextureInfo texture_info, const LLVector2& offset);
void setTextureScale(TextureInfo texture_info, const LLVector2& scale);
void setTextureRotation(TextureInfo texture_info, float rotation);
// Default value accessors
static F32 getDefaultAlphaCutoff();
static S32 getDefaultAlphaMode();
static F32 getDefaultMetallicFactor();
static F32 getDefaultRoughnessFactor();
static LLColor4 getDefaultBaseColor();
static LLColor3 getDefaultEmissiveColor();
static bool getDefaultDoubleSided();
static LLVector2 getDefaultTextureOffset();
static LLVector2 getDefaultTextureScale();
static F32 getDefaultTextureRotation();
static void hackOverrideUUID(LLUUID& id);
static void applyOverrideUUID(LLUUID& dst_id, const LLUUID& override_id);
// set mAlphaMode from string.
// Anything otherthan "MASK" or "BLEND" sets mAlphaMode to ALPHA_MODE_OPAQUE
void setAlphaMode(const std::string& mode, bool for_override = false);
const char* getAlphaMode() const;
// set the contents of this LLGLTFMaterial from the given json
// returns true if successful
// if unsuccessful, the contents of this LLGLTFMaterial should be left unchanged and false is returned
// json - the json text to load from
// warn_msg - warning message from TinyGLTF if any
// error_msg - error_msg from TinyGLTF if any
bool fromJSON(const std::string& json, std::string& warn_msg, std::string& error_msg);
// get the contents of this LLGLTFMaterial as a json string
std::string asJSON(bool prettyprint = false) const;
// initialize from given tinygltf::Model
// model - the model to reference
// mat_index - index of material in model's material array
void setFromModel(const tinygltf::Model& model, S32 mat_index);
// write to given tinygltf::Model
void writeToModel(tinygltf::Model& model, S32 mat_index) const;
virtual void applyOverride(const LLGLTFMaterial& override_mat);
// apply the given LLSD override data
void applyOverrideLLSD(const LLSD& data);
// Get the given override on this LLGLTFMaterial as LLSD
// override_mat -- the override source data
// data -- output LLSD object (should be passed in empty)
void getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& data) const;
// For base materials only (i.e. assets). Clears transforms to
// default since they're not supported in assets yet.
void sanitizeAssetMaterial();
// For material overrides only. Clears most properties to
// default/fallthrough, but preserves the transforms.
bool setBaseMaterial();
void setBaseMaterial(const LLGLTFMaterial& old_override_mat);
// True if setBaseMaterial() was just called
bool isClearedForBaseMaterial() const;
// For local materials, they have to keep track of where
// they are assigned to for full updates
virtual void addTextureEntry(LLTextureEntry* te) {};
virtual void removeTextureEntry(LLTextureEntry* te) {};
// For local textures so that editor will know to track changes
void addLocalTextureTracking(const LLUUID& tracking_id, const LLUUID &tex_id);
void removeLocalTextureTracking(const LLUUID& tracking_id);
bool hasLocalTextures() { return !mTrackingIdToLocalTexture.empty(); }
virtual bool replaceLocalTexture(const LLUUID& tracking_id, const LLUUID &old_id, const LLUUID& new_id);
virtual void updateTextureTracking();
protected:
static LLVector2 vec2FromJson(const std::map<std::string, tinygltf::Value>& object, const char* key, const LLVector2& default_value);
static F32 floatFromJson(const std::map<std::string, tinygltf::Value>& object, const char* key, const F32 default_value);
template<typename T>
static void allocateTextureImage(tinygltf::Model& model, T& texture_info, const std::string& uri);
template<typename T>
void setFromTexture(const tinygltf::Model& model, const T& texture_info, TextureInfo texture_info_id);
template<typename T>
static void setFromTexture(const tinygltf::Model& model, const T& texture_info, LLUUID& texture_id, TextureTransform& transform);
template<typename T>
void writeToTexture(tinygltf::Model& model, T& texture_info, TextureInfo texture_info_id, bool force_write = false) const;
template<typename T>
static void writeToTexture(tinygltf::Model& model, T& texture_info, const LLUUID& texture_id, const TextureTransform& transform, bool force_write = false);
// Used to update the digest of the mTrackingIdToLocalTexture map each time
// it is changed; this way, that digest can be used by the fast getHash()
// method intsead of having to hash all individual keys and values. HB
void updateLocalTexDataDigest();
public:
// *TODO: If/when we implement additional GLTF extensions, they may not be
// compatible with our GLTF terrain implementation. We may want to disallow
// materials with some features from being set on terrain, if their
// implementation on terrain is not compliant with the spec:
// - KHR_materials_transmission: Probably OK?
// - KHR_materials_ior: Probably OK?
// - KHR_materials_volume: Likely incompatible, as our terrain
// heightmaps cannot currently be described as finite enclosed
// volumes.
// See also LLPanelRegionTerrainInfo::validateMaterials
// These fields are local to viewer and are a part of local bitmap support
typedef std::map<LLUUID, LLUUID> local_tex_map_t;
local_tex_map_t mTrackingIdToLocalTexture;
// Used to store a digest of mTrackingIdToLocalTexture when the latter is
// not empty, or zero otherwise. HB
U64 mLocalTexDataDigest;
std::array<LLUUID, GLTF_TEXTURE_INFO_COUNT> mTextureId;
std::array<TextureTransform, GLTF_TEXTURE_INFO_COUNT> mTextureTransform;
// NOTE: initialize values to defaults according to the GLTF spec
// NOTE: these values should be in linear color space
LLColor4 mBaseColor;
LLColor3 mEmissiveColor;
F32 mMetallicFactor;
F32 mRoughnessFactor;
F32 mAlphaCutoff;
AlphaMode mAlphaMode;
bool mDoubleSided = false;
// Override specific flags for state that can't use off-by-epsilon or UUID
// hack
bool mOverrideDoubleSided = false;
bool mOverrideAlphaMode = false;
};
@@ -0,0 +1,142 @@
/**
* @file llgltfmaterial_templates.h
* @brief Material template definition
*
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2023, 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$
*/
#pragma once
#include "llgltfmaterial.h"
// Use templates here as workaround for the different similar texture info classes in tinygltf
// Includer must first include tiny_gltf.h with the desired flags
template<typename T>
std::string gltf_get_texture_image(const tinygltf::Model& model, const T& texture_info)
{
const S32 texture_idx = texture_info.index;
if (texture_idx < 0 || texture_idx >= model.textures.size())
{
return "";
}
const tinygltf::Texture& texture = model.textures[texture_idx];
// Ignore texture.sampler for now
const S32 image_idx = texture.source;
if (image_idx < 0 || image_idx >= model.images.size())
{
return "";
}
const tinygltf::Image& image = model.images[image_idx];
return image.uri;
}
template<typename T>
void LLGLTFMaterial::setFromTexture(const tinygltf::Model& model, const T& texture_info, TextureInfo texture_info_id)
{
setFromTexture(model, texture_info, mTextureId[texture_info_id], mTextureTransform[texture_info_id]);
const std::string uri = gltf_get_texture_image(model, texture_info);
}
// static
template<typename T>
void LLGLTFMaterial::setFromTexture(const tinygltf::Model& model, const T& texture_info, LLUUID& texture_id, TextureTransform& transform)
{
LL_PROFILE_ZONE_SCOPED;
const std::string uri = gltf_get_texture_image(model, texture_info);
texture_id.set(uri);
const tinygltf::Value::Object& extensions_object = texture_info.extensions;
const auto transform_it = extensions_object.find(GLTF_FILE_EXTENSION_TRANSFORM);
if (transform_it != extensions_object.end())
{
const tinygltf::Value& transform_json = std::get<1>(*transform_it);
if (transform_json.IsObject())
{
const tinygltf::Value::Object& transform_object = transform_json.Get<tinygltf::Value::Object>();
transform.mOffset = vec2FromJson(transform_object, GLTF_FILE_EXTENSION_TRANSFORM_OFFSET, getDefaultTextureOffset());
transform.mScale = vec2FromJson(transform_object, GLTF_FILE_EXTENSION_TRANSFORM_SCALE, getDefaultTextureScale());
transform.mRotation = floatFromJson(transform_object, GLTF_FILE_EXTENSION_TRANSFORM_ROTATION, getDefaultTextureRotation());
}
}
}
// static
template<typename T>
void LLGLTFMaterial::allocateTextureImage(tinygltf::Model& model, T& texture_info, const std::string& uri)
{
const S32 image_idx = static_cast<S32>(model.images.size());
model.images.emplace_back();
model.images[image_idx].uri = uri;
// The texture, not to be confused with the texture info
const S32 texture_idx = static_cast<S32>(model.textures.size());
model.textures.emplace_back();
tinygltf::Texture& texture = model.textures[texture_idx];
texture.source = image_idx;
texture_info.index = texture_idx;
}
// static
template<typename T>
void LLGLTFMaterial::writeToTexture(tinygltf::Model& model, T& texture_info, TextureInfo texture_info_id, bool force_write) const
{
writeToTexture(model, texture_info, mTextureId[texture_info_id], mTextureTransform[texture_info_id], force_write);
}
// static
template<typename T>
void LLGLTFMaterial::writeToTexture(tinygltf::Model& model, T& texture_info, const LLUUID& texture_id, const TextureTransform& transform, bool force_write)
{
LL_PROFILE_ZONE_SCOPED;
const bool is_blank_transform = transform == sDefault.mTextureTransform[0];
// Check if this material matches all the fallback values, and if so, then
// skip including it to reduce material size
if (!force_write && texture_id.isNull() && is_blank_transform)
{
return;
}
// tinygltf will discard this texture info if there is no valid texture,
// causing potential loss of information for overrides, so ensure one is
// defined. -Cosmic,2023-01-30
allocateTextureImage(model, texture_info, texture_id.asString());
if (!is_blank_transform)
{
tinygltf::Value::Object transform_map;
transform_map[GLTF_FILE_EXTENSION_TRANSFORM_OFFSET] = tinygltf::Value(tinygltf::Value::Array({
tinygltf::Value(transform.mOffset.mV[VX]),
tinygltf::Value(transform.mOffset.mV[VY])
}));
transform_map[GLTF_FILE_EXTENSION_TRANSFORM_SCALE] = tinygltf::Value(tinygltf::Value::Array({
tinygltf::Value(transform.mScale.mV[VX]),
tinygltf::Value(transform.mScale.mV[VY])
}));
transform_map[GLTF_FILE_EXTENSION_TRANSFORM_ROTATION] = tinygltf::Value(transform.mRotation);
texture_info.extensions[GLTF_FILE_EXTENSION_TRANSFORM] = tinygltf::Value(transform_map);
}
}
+261
View File
@@ -0,0 +1,261 @@
/**
* @file lllslconstants.h
* @author James Cook
* @brief Constants used in lsl.
*
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#ifndef LL_LLLSLCONSTANTS_H
#define LL_LLLSLCONSTANTS_H
// LSL: Return flags for llGetAgentInfo
const U32 AGENT_FLYING = 0x0001;
const U32 AGENT_ATTACHMENTS = 0x0002;
const U32 AGENT_SCRIPTED = 0x0004;
const U32 AGENT_MOUSELOOK = 0x0008;
const U32 AGENT_SITTING = 0x0010;
const U32 AGENT_ON_OBJECT = 0x0020;
const U32 AGENT_AWAY = 0x0040;
const U32 AGENT_WALKING = 0x0080;
const U32 AGENT_IN_AIR = 0x0100;
const U32 AGENT_TYPING = 0x0200;
const U32 AGENT_CROUCHING = 0x0400;
const U32 AGENT_BUSY = 0x0800;
const U32 AGENT_ALWAYS_RUN = 0x1000;
const U32 AGENT_AUTOPILOT = 0x2000;
const S32 LSL_REMOTE_DATA_CHANNEL = 1;
const S32 LSL_REMOTE_DATA_REQUEST = 2;
const S32 LSL_REMOTE_DATA_REPLY = 3;
// Constants used in extended LSL primitive setter and getters
const S32 LSL_PRIM_TYPE_LEGACY = 1; // No longer supported.
const S32 LSL_PRIM_MATERIAL = 2;
const S32 LSL_PRIM_PHYSICS = 3;
const S32 LSL_PRIM_TEMP_ON_REZ = 4;
const S32 LSL_PRIM_PHANTOM = 5;
const S32 LSL_PRIM_POSITION = 6;
const S32 LSL_PRIM_SIZE = 7;
const S32 LSL_PRIM_ROTATION = 8;
const S32 LSL_PRIM_TYPE = 9; // Replacement for LSL_PRIM_TYPE_LEGACY
const S32 LSL_PRIM_TEXTURE = 17;
const S32 LSL_PRIM_COLOR = 18;
const S32 LSL_PRIM_BUMP_SHINY = 19;
const S32 LSL_PRIM_FULLBRIGHT = 20;
const S32 LSL_PRIM_FLEXIBLE = 21;
const S32 LSL_PRIM_TEXGEN = 22;
const S32 LSL_PRIM_POINT_LIGHT = 23;
const S32 LSL_PRIM_CAST_SHADOWS = 24;
const S32 LSL_PRIM_GLOW = 25;
const S32 LSL_PRIM_TEXT = 26;
const S32 LSL_PRIM_NAME = 27;
const S32 LSL_PRIM_DESC = 28;
const S32 LSL_PRIM_ROT_LOCAL = 29;
const S32 LSL_PRIM_PHYSICS_SHAPE_TYPE = 30;
const S32 LSL_PRIM_OMEGA = 32;
const S32 LSL_PRIM_POS_LOCAL = 33;
const S32 LSL_PRIM_LINK_TARGET = 34;
const S32 LSL_PRIM_SLICE = 35;
const S32 LSL_PRIM_PHYSICS_SHAPE_PRIM = 0;
const S32 LSL_PRIM_PHYSICS_SHAPE_NONE = 1;
const S32 LSL_PRIM_PHYSICS_SHAPE_CONVEX = 2;
const S32 LSL_PRIM_TYPE_BOX = 0;
const S32 LSL_PRIM_TYPE_CYLINDER= 1;
const S32 LSL_PRIM_TYPE_PRISM = 2;
const S32 LSL_PRIM_TYPE_SPHERE = 3;
const S32 LSL_PRIM_TYPE_TORUS = 4;
const S32 LSL_PRIM_TYPE_TUBE = 5;
const S32 LSL_PRIM_TYPE_RING = 6;
const S32 LSL_PRIM_TYPE_SCULPT = 7;
const S32 LSL_PRIM_HOLE_DEFAULT = 0x00;
const S32 LSL_PRIM_HOLE_CIRCLE = 0x10;
const S32 LSL_PRIM_HOLE_SQUARE = 0x20;
const S32 LSL_PRIM_HOLE_TRIANGLE= 0x30;
const S32 LSL_PRIM_MATERIAL_STONE = 0;
const S32 LSL_PRIM_MATERIAL_METAL = 1;
const S32 LSL_PRIM_MATERIAL_GLASS = 2;
const S32 LSL_PRIM_MATERIAL_WOOD = 3;
const S32 LSL_PRIM_MATERIAL_FLESH = 4;
const S32 LSL_PRIM_MATERIAL_PLASTIC = 5;
const S32 LSL_PRIM_MATERIAL_RUBBER = 6;
const S32 LSL_PRIM_MATERIAL_LIGHT = 7;
const S32 LSL_PRIM_SHINY_NONE = 0;
const S32 LSL_PRIM_SHINY_LOW = 1;
const S32 LSL_PRIM_SHINY_MEDIUM = 2;
const S32 LSL_PRIM_SHINY_HIGH = 3;
const S32 LSL_PRIM_TEXGEN_DEFAULT = 0;
const S32 LSL_PRIM_TEXGEN_PLANAR = 1;
const S32 LSL_PRIM_BUMP_NONE = 0;
const S32 LSL_PRIM_BUMP_BRIGHT = 1;
const S32 LSL_PRIM_BUMP_DARK = 2;
const S32 LSL_PRIM_BUMP_WOOD = 3;
const S32 LSL_PRIM_BUMP_BARK = 4;
const S32 LSL_PRIM_BUMP_BRICKS = 5;
const S32 LSL_PRIM_BUMP_CHECKER = 6;
const S32 LSL_PRIM_BUMP_CONCRETE = 7;
const S32 LSL_PRIM_BUMP_TILE = 8;
const S32 LSL_PRIM_BUMP_STONE = 9;
const S32 LSL_PRIM_BUMP_DISKS = 10;
const S32 LSL_PRIM_BUMP_GRAVEL = 11;
const S32 LSL_PRIM_BUMP_BLOBS = 12;
const S32 LSL_PRIM_BUMP_SIDING = 13;
const S32 LSL_PRIM_BUMP_LARGETILE = 14;
const S32 LSL_PRIM_BUMP_STUCCO = 15;
const S32 LSL_PRIM_BUMP_SUCTION = 16;
const S32 LSL_PRIM_BUMP_WEAVE = 17;
const S32 LSL_PRIM_SCULPT_TYPE_SPHERE = 1;
const S32 LSL_PRIM_SCULPT_TYPE_TORUS = 2;
const S32 LSL_PRIM_SCULPT_TYPE_PLANE = 3;
const S32 LSL_PRIM_SCULPT_TYPE_CYLINDER = 4;
const S32 LSL_PRIM_SCULPT_TYPE_MASK = 7;
const S32 LSL_PRIM_SCULPT_FLAG_INVERT = 64;
const S32 LSL_PRIM_SCULPT_FLAG_MIRROR = 128;
const S32 LSL_ALL_SIDES = -1;
const S32 LSL_LINK_ROOT = 1;
const S32 LSL_LINK_FIRST_CHILD = 2;
const S32 LSL_LINK_SET = -1;
const S32 LSL_LINK_ALL_OTHERS = -2;
const S32 LSL_LINK_ALL_CHILDREN = -3;
const S32 LSL_LINK_THIS = -4;
// LSL constants for llSetForSell
const S32 SELL_NOT = 0;
const S32 SELL_ORIGINAL = 1;
const S32 SELL_COPY = 2;
const S32 SELL_CONTENTS = 3;
// LSL constants for llSetPayPrice
const S32 PAY_PRICE_HIDE = -1;
const S32 PAY_PRICE_DEFAULT = -2;
const S32 MAX_PAY_BUTTONS = 4;
const S32 PAY_BUTTON_DEFAULT_0 = 1;
const S32 PAY_BUTTON_DEFAULT_1 = 5;
const S32 PAY_BUTTON_DEFAULT_2 = 10;
const S32 PAY_BUTTON_DEFAULT_3 = 20;
// lsl email registration.
const S32 EMAIL_REG_SUBSCRIBE_OBJECT = 0x01;
const S32 EMAIL_REG_UNSUBSCRIBE_OBJECT = 0x02;
const S32 EMAIL_REG_UNSUBSCRIBE_SIM = 0x04;
const S32 LIST_STAT_RANGE = 0;
const S32 LIST_STAT_MIN = 1;
const S32 LIST_STAT_MAX = 2;
const S32 LIST_STAT_MEAN = 3;
const S32 LIST_STAT_MEDIAN = 4;
const S32 LIST_STAT_STD_DEV = 5;
const S32 LIST_STAT_SUM = 6;
const S32 LIST_STAT_SUM_SQUARES = 7;
const S32 LIST_STAT_NUM_COUNT = 8;
const S32 LIST_STAT_GEO_MEAN = 9;
const S32 STRING_TRIM_HEAD = 0x01;
const S32 STRING_TRIM_TAIL = 0x02;
const S32 STRING_TRIM = STRING_TRIM_HEAD | STRING_TRIM_TAIL;
// llGetObjectDetails
const S32 OBJECT_UNKNOWN_DETAIL = -1;
const S32 OBJECT_NAME = 1;
const S32 OBJECT_DESC = 2;
const S32 OBJECT_POS = 3;
const S32 OBJECT_ROT = 4;
const S32 OBJECT_VELOCITY = 5;
const S32 OBJECT_OWNER = 6;
const S32 OBJECT_GROUP = 7;
const S32 OBJECT_CREATOR = 8;
const S32 OBJECT_RUNNING_SCRIPT_COUNT = 9;
const S32 OBJECT_TOTAL_SCRIPT_COUNT = 10;
const S32 OBJECT_SCRIPT_MEMORY = 11;
const S32 OBJECT_SCRIPT_TIME = 12;
const S32 OBJECT_PRIM_EQUIVALENCE = 13;
const S32 OBJECT_SERVER_COST = 14;
const S32 OBJECT_STREAMING_COST = 15;
const S32 OBJECT_PHYSICS_COST = 16;
const S32 OBJECT_CHARACTER_TIME = 17;
const S32 OBJECT_ROOT = 18;
const S32 OBJECT_ATTACHED_POINT = 19;
const S32 OBJECT_PATHFINDING_TYPE = 20;
const S32 OBJECT_PHYSICS = 21;
const S32 OBJECT_PHANTOM = 22;
const S32 OBJECT_TEMP_ON_REZ = 23;
const S32 OBJECT_RENDER_WEIGHT = 24;
// llTextBox() magic token string - yes this is a hack. sue me.
char const* const TEXTBOX_MAGIC_TOKEN = "!!llTextBox!!";
// changed() event flags
const U32 CHANGED_NONE = 0x0;
const U32 CHANGED_INVENTORY = 0x1;
const U32 CHANGED_COLOR = 0x2;
const U32 CHANGED_SHAPE = 0x4;
const U32 CHANGED_SCALE = 0x8;
const U32 CHANGED_TEXTURE = 0x10;
const U32 CHANGED_LINK = 0x20;
const U32 CHANGED_ALLOWED_DROP = 0x40;
const U32 CHANGED_OWNER = 0x80;
const U32 CHANGED_REGION = 0x100;
const U32 CHANGED_TELEPORT = 0x200;
const U32 CHANGED_REGION_START = 0x400;
const U32 CHANGED_MEDIA = 0x800;
// Possible error results
const U32 LSL_STATUS_OK = 0;
const U32 LSL_STATUS_MALFORMED_PARAMS = 1000;
const U32 LSL_STATUS_TYPE_MISMATCH = 1001;
const U32 LSL_STATUS_BOUNDS_ERROR = 1002;
const U32 LSL_STATUS_NOT_FOUND = 1003;
const U32 LSL_STATUS_NOT_SUPPORTED = 1004;
const U32 LSL_STATUS_INTERNAL_ERROR = 1999;
// Start per-function errors below, starting at 2000:
const U32 LSL_STATUS_WHITELIST_FAILED = 2001;
const S32 LSL_XP_ERROR_NONE = 0;
const S32 LSL_XP_ERROR_THROTTLED = 1;
const S32 LSL_XP_ERROR_EXPERIENCES_DISABLED = 2;
const S32 LSL_XP_ERROR_INVALID_PARAMETERS = 3;
const S32 LSL_XP_ERROR_NOT_PERMITTED = 4;
const S32 LSL_XP_ERROR_NO_EXPERIENCE = 5;
const S32 LSL_XP_ERROR_NOT_FOUND = 6;
const S32 LSL_XP_ERROR_INVALID_EXPERIENCE = 7;
const S32 LSL_XP_ERROR_EXPERIENCE_DISABLED = 8;
const S32 LSL_XP_ERROR_EXPERIENCE_SUSPENDED = 9;
const S32 LSL_XP_ERROR_UNKNOWN_ERROR = 10;
const S32 LSL_XP_ERROR_QUOTA_EXCEEDED = 11;
const S32 LSL_XP_ERROR_STORE_DISABLED = 12;
const S32 LSL_XP_ERROR_STORAGE_EXCEPTION = 13;
const S32 LSL_XP_ERROR_KEY_NOT_FOUND = 14;
const S32 LSL_XP_ERROR_RETRY_UPDATE = 15;
const S32 LSL_XP_ERROR_MATURITY_EXCEEDED = 16;
#endif
+476
View File
@@ -0,0 +1,476 @@
/**
* @file llmaterial.cpp
* @brief Material definition
*
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "linden_common.h"
#include "llmaterial.h"
#include "hbxxh.h"
/**
* Materials cap parameters
*/
#define MATERIALS_CAP_NORMAL_MAP_FIELD "NormMap"
#define MATERIALS_CAP_NORMAL_MAP_OFFSET_X_FIELD "NormOffsetX"
#define MATERIALS_CAP_NORMAL_MAP_OFFSET_Y_FIELD "NormOffsetY"
#define MATERIALS_CAP_NORMAL_MAP_REPEAT_X_FIELD "NormRepeatX"
#define MATERIALS_CAP_NORMAL_MAP_REPEAT_Y_FIELD "NormRepeatY"
#define MATERIALS_CAP_NORMAL_MAP_ROTATION_FIELD "NormRotation"
#define MATERIALS_CAP_SPECULAR_MAP_FIELD "SpecMap"
#define MATERIALS_CAP_SPECULAR_MAP_OFFSET_X_FIELD "SpecOffsetX"
#define MATERIALS_CAP_SPECULAR_MAP_OFFSET_Y_FIELD "SpecOffsetY"
#define MATERIALS_CAP_SPECULAR_MAP_REPEAT_X_FIELD "SpecRepeatX"
#define MATERIALS_CAP_SPECULAR_MAP_REPEAT_Y_FIELD "SpecRepeatY"
#define MATERIALS_CAP_SPECULAR_MAP_ROTATION_FIELD "SpecRotation"
#define MATERIALS_CAP_SPECULAR_COLOR_FIELD "SpecColor"
#define MATERIALS_CAP_SPECULAR_EXP_FIELD "SpecExp"
#define MATERIALS_CAP_ENV_INTENSITY_FIELD "EnvIntensity"
#define MATERIALS_CAP_ALPHA_MASK_CUTOFF_FIELD "AlphaMaskCutoff"
#define MATERIALS_CAP_DIFFUSE_ALPHA_MODE_FIELD "DiffuseAlphaMode"
const LLColor4U LLMaterial::DEFAULT_SPECULAR_LIGHT_COLOR(255,255,255,255);
/**
* Materials constants
*/
const F32 MATERIALS_MULTIPLIER = 10000.f;
/**
* Helper functions
*/
template<typename T> T getMaterialField(const LLSD& data, const std::string& field, const LLSD::Type field_type)
{
if ( (data.has(field)) && (field_type == data[field].type()) )
{
return (T)data[field];
}
LL_ERRS() << "Missing or mistyped field '" << field << "' in material definition" << LL_ENDL;
return (T)LLSD();
}
// GCC didn't like the generic form above for some reason
template<> LLUUID getMaterialField(const LLSD& data, const std::string& field, const LLSD::Type field_type)
{
if ( (data.has(field)) && (field_type == data[field].type()) )
{
return data[field].asUUID();
}
LL_ERRS() << "Missing or mistyped field '" << field << "' in material definition" << LL_ENDL;
return LLUUID::null;
}
/**
* LLMaterial class
*/
const LLMaterial LLMaterial::null;
LLMaterial::LLMaterial()
: mNormalOffsetX(0.0f)
, mNormalOffsetY(0.0f)
, mNormalRepeatX(1.0f)
, mNormalRepeatY(1.0f)
, mNormalRotation(0.0f)
, mSpecularOffsetX(0.0f)
, mSpecularOffsetY(0.0f)
, mSpecularRepeatX(1.0f)
, mSpecularRepeatY(1.0f)
, mSpecularRotation(0.0f)
, mSpecularLightColor(LLMaterial::DEFAULT_SPECULAR_LIGHT_COLOR)
, mSpecularLightExponent(LLMaterial::DEFAULT_SPECULAR_LIGHT_EXPONENT)
, mEnvironmentIntensity(LLMaterial::DEFAULT_ENV_INTENSITY)
, mDiffuseAlphaMode(LLMaterial::DIFFUSE_ALPHA_MODE_BLEND)
, mAlphaMaskCutoff(0)
{
}
LLMaterial::LLMaterial(const LLSD& material_data)
{
fromLLSD(material_data);
}
const LLUUID& LLMaterial::getNormalID() const
{
return mNormalID;
}
void LLMaterial::setNormalID(const LLUUID& normal_id)
{
mNormalID = normal_id;
}
void LLMaterial::getNormalOffset(F32& offset_x, F32& offset_y) const
{
offset_x = mNormalOffsetX;
offset_y = mNormalOffsetY;
}
F32 LLMaterial::getNormalOffsetX() const
{
return mNormalOffsetX;
}
F32 LLMaterial::getNormalOffsetY() const
{
return mNormalOffsetY;
}
void LLMaterial::setNormalOffset(F32 offset_x, F32 offset_y)
{
mNormalOffsetX = offset_x;
mNormalOffsetY = offset_y;
}
void LLMaterial::setNormalOffsetX(F32 offset_x)
{
mNormalOffsetX = offset_x;
}
void LLMaterial::setNormalOffsetY(F32 offset_y)
{
mNormalOffsetY = offset_y;
}
void LLMaterial::getNormalRepeat(F32& repeat_x, F32& repeat_y) const
{
repeat_x = mNormalRepeatX;
repeat_y = mNormalRepeatY;
}
F32 LLMaterial::getNormalRepeatX() const
{
return mNormalRepeatX;
}
F32 LLMaterial::getNormalRepeatY() const
{
return mNormalRepeatY;
}
void LLMaterial::setNormalRepeat(F32 repeat_x, F32 repeat_y)
{
mNormalRepeatX = repeat_x;
mNormalRepeatY = repeat_y;
}
void LLMaterial::setNormalRepeatX(F32 repeat_x)
{
mNormalRepeatX = repeat_x;
}
void LLMaterial::setNormalRepeatY(F32 repeat_y)
{
mNormalRepeatY = repeat_y;
}
F32 LLMaterial::getNormalRotation() const
{
return mNormalRotation;
}
void LLMaterial::setNormalRotation(F32 rot)
{
mNormalRotation = rot;
}
const LLUUID& LLMaterial::getSpecularID() const
{
return mSpecularID;
}
void LLMaterial::setSpecularID(const LLUUID& specular_id)
{
mSpecularID = specular_id;
}
void LLMaterial::getSpecularOffset(F32& offset_x, F32& offset_y) const
{
offset_x = mSpecularOffsetX;
offset_y = mSpecularOffsetY;
}
F32 LLMaterial::getSpecularOffsetX() const
{
return mSpecularOffsetX;
}
F32 LLMaterial::getSpecularOffsetY() const
{
return mSpecularOffsetY;
}
void LLMaterial::setSpecularOffset(F32 offset_x, F32 offset_y)
{
mSpecularOffsetX = offset_x;
mSpecularOffsetY = offset_y;
}
void LLMaterial::setSpecularOffsetX(F32 offset_x)
{
mSpecularOffsetX = offset_x;
}
void LLMaterial::setSpecularOffsetY(F32 offset_y)
{
mSpecularOffsetY = offset_y;
}
void LLMaterial::getSpecularRepeat(F32& repeat_x, F32& repeat_y) const
{
repeat_x = mSpecularRepeatX;
repeat_y = mSpecularRepeatY;
}
F32 LLMaterial::getSpecularRepeatX() const
{
return mSpecularRepeatX;
}
F32 LLMaterial::getSpecularRepeatY() const
{
return mSpecularRepeatY;
}
void LLMaterial::setSpecularRepeat(F32 repeat_x, F32 repeat_y)
{
mSpecularRepeatX = repeat_x; mSpecularRepeatY = repeat_y;
}
void LLMaterial::setSpecularRepeatX(F32 repeat_x)
{
mSpecularRepeatX = repeat_x;
}
void LLMaterial::setSpecularRepeatY(F32 repeat_y)
{
mSpecularRepeatY = repeat_y;
}
F32 LLMaterial::getSpecularRotation() const
{
return mSpecularRotation;
}
void LLMaterial::setSpecularRotation(F32 rot)
{
mSpecularRotation = rot;
}
const LLColor4U LLMaterial::getSpecularLightColor() const
{
return mSpecularLightColor;
}
void LLMaterial::setSpecularLightColor(const LLColor4U& color)
{
mSpecularLightColor = color;
}
U8 LLMaterial::getSpecularLightExponent() const
{
return mSpecularLightExponent;
}
void LLMaterial::setSpecularLightExponent(U8 exponent)
{
mSpecularLightExponent = exponent;
}
U8 LLMaterial::getEnvironmentIntensity() const
{
return mEnvironmentIntensity;
}
void LLMaterial::setEnvironmentIntensity(U8 intensity)
{
mEnvironmentIntensity = intensity;
}
U8 LLMaterial::getDiffuseAlphaMode() const
{
return mDiffuseAlphaMode;
}
void LLMaterial::setDiffuseAlphaMode(U8 alpha_mode)
{
mDiffuseAlphaMode = alpha_mode;
}
U8 LLMaterial::getAlphaMaskCutoff() const
{
return mAlphaMaskCutoff;
}
void LLMaterial::setAlphaMaskCutoff(U8 cutoff)
{
mAlphaMaskCutoff = cutoff;
}
LLSD LLMaterial::asLLSD() const
{
LLSD material_data;
S32 normalOffsetXInt = ll_round(mNormalOffsetX * MATERIALS_MULTIPLIER);
S32 normalOffsetYInt = ll_round(mNormalOffsetY * MATERIALS_MULTIPLIER);
S32 normalRotInt = ll_round(mNormalRotation * MATERIALS_MULTIPLIER);
material_data[MATERIALS_CAP_NORMAL_MAP_FIELD] = mNormalID;
material_data[MATERIALS_CAP_NORMAL_MAP_OFFSET_X_FIELD] = normalOffsetXInt;
material_data[MATERIALS_CAP_NORMAL_MAP_OFFSET_Y_FIELD] = normalOffsetYInt;
material_data[MATERIALS_CAP_NORMAL_MAP_REPEAT_X_FIELD] = ll_round(mNormalRepeatX * MATERIALS_MULTIPLIER);
material_data[MATERIALS_CAP_NORMAL_MAP_REPEAT_Y_FIELD] = ll_round(mNormalRepeatY * MATERIALS_MULTIPLIER);
material_data[MATERIALS_CAP_NORMAL_MAP_ROTATION_FIELD] = normalRotInt;
material_data[MATERIALS_CAP_SPECULAR_MAP_FIELD] = mSpecularID;
S32 specularOffsetXInt = ll_round(mSpecularOffsetX * MATERIALS_MULTIPLIER);
S32 specularOffsetYInt = ll_round(mSpecularOffsetY * MATERIALS_MULTIPLIER);
S32 specularRotInt = ll_round(mSpecularRotation * MATERIALS_MULTIPLIER);
material_data[MATERIALS_CAP_SPECULAR_MAP_OFFSET_X_FIELD] = specularOffsetXInt;
material_data[MATERIALS_CAP_SPECULAR_MAP_OFFSET_Y_FIELD] = specularOffsetYInt;
material_data[MATERIALS_CAP_SPECULAR_MAP_REPEAT_X_FIELD] = ll_round(mSpecularRepeatX * MATERIALS_MULTIPLIER);
material_data[MATERIALS_CAP_SPECULAR_MAP_REPEAT_Y_FIELD] = ll_round(mSpecularRepeatY * MATERIALS_MULTIPLIER);
material_data[MATERIALS_CAP_SPECULAR_MAP_ROTATION_FIELD] = specularRotInt;
material_data[MATERIALS_CAP_SPECULAR_COLOR_FIELD] = mSpecularLightColor.getValue();
material_data[MATERIALS_CAP_SPECULAR_EXP_FIELD] = mSpecularLightExponent;
material_data[MATERIALS_CAP_ENV_INTENSITY_FIELD] = mEnvironmentIntensity;
material_data[MATERIALS_CAP_DIFFUSE_ALPHA_MODE_FIELD] = mDiffuseAlphaMode;
material_data[MATERIALS_CAP_ALPHA_MASK_CUTOFF_FIELD] = mAlphaMaskCutoff;
return material_data;
}
void LLMaterial::fromLLSD(const LLSD& material_data)
{
mNormalID = getMaterialField<LLSD::UUID>(material_data, MATERIALS_CAP_NORMAL_MAP_FIELD, LLSD::TypeUUID);
S32 normalOffsetXInt = getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_NORMAL_MAP_OFFSET_X_FIELD, LLSD::TypeInteger);
S32 normalOffsetYInt = getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_NORMAL_MAP_OFFSET_Y_FIELD, LLSD::TypeInteger);
S32 normalRotInt = getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_NORMAL_MAP_ROTATION_FIELD, LLSD::TypeInteger);
S32 normalRepeatXInt = getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_NORMAL_MAP_REPEAT_X_FIELD, LLSD::TypeInteger);
S32 normalRepeatYInt = getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_NORMAL_MAP_REPEAT_Y_FIELD, LLSD::TypeInteger);
mNormalOffsetX = F32(normalOffsetXInt) / MATERIALS_MULTIPLIER;
mNormalOffsetY = F32(normalOffsetYInt) / MATERIALS_MULTIPLIER;
mNormalRotation = F32(normalRotInt) / MATERIALS_MULTIPLIER;
mNormalRepeatX = F32(normalRepeatXInt) / MATERIALS_MULTIPLIER;
mNormalRepeatY = F32(normalRepeatYInt) / MATERIALS_MULTIPLIER;
mSpecularID = getMaterialField<LLSD::UUID>(material_data, MATERIALS_CAP_SPECULAR_MAP_FIELD, LLSD::TypeUUID);
S32 specularOffsetXInt = getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_SPECULAR_MAP_OFFSET_X_FIELD, LLSD::TypeInteger);
S32 specularOffsetYInt = getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_SPECULAR_MAP_OFFSET_Y_FIELD, LLSD::TypeInteger);
S32 specularRotInt = getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_SPECULAR_MAP_ROTATION_FIELD, LLSD::TypeInteger);
S32 specularRepeatXInt = getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_SPECULAR_MAP_REPEAT_X_FIELD, LLSD::TypeInteger);
S32 specularRepeatYInt = getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_SPECULAR_MAP_REPEAT_Y_FIELD, LLSD::TypeInteger);
mSpecularOffsetX = F32(specularOffsetXInt) / MATERIALS_MULTIPLIER;
mSpecularOffsetY = F32(specularOffsetYInt) / MATERIALS_MULTIPLIER;
mSpecularRotation = F32(specularRotInt) / MATERIALS_MULTIPLIER;
mSpecularRepeatX = F32(specularRepeatXInt) / MATERIALS_MULTIPLIER;
mSpecularRepeatY = F32(specularRepeatYInt) / MATERIALS_MULTIPLIER;
mSpecularLightColor.setValue(getMaterialField<LLSD>(material_data, MATERIALS_CAP_SPECULAR_COLOR_FIELD, LLSD::TypeArray));
mSpecularLightExponent = (U8)getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_SPECULAR_EXP_FIELD, LLSD::TypeInteger);
mEnvironmentIntensity = (U8)getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_ENV_INTENSITY_FIELD, LLSD::TypeInteger);
mDiffuseAlphaMode = (U8)getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_DIFFUSE_ALPHA_MODE_FIELD, LLSD::TypeInteger);
mAlphaMaskCutoff = (U8)getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_ALPHA_MASK_CUTOFF_FIELD, LLSD::TypeInteger);
}
bool LLMaterial::isNull() const
{
return (*this == null);
}
bool LLMaterial::operator == (const LLMaterial& rhs) const
{
return
(mNormalID == rhs.mNormalID) && (mNormalOffsetX == rhs.mNormalOffsetX) && (mNormalOffsetY == rhs.mNormalOffsetY) &&
(mNormalRepeatX == rhs.mNormalRepeatX) && (mNormalRepeatY == rhs.mNormalRepeatY) && (mNormalRotation == rhs.mNormalRotation) &&
(mSpecularID == rhs.mSpecularID) && (mSpecularOffsetX == rhs.mSpecularOffsetX) && (mSpecularOffsetY == rhs.mSpecularOffsetY) &&
(mSpecularRepeatX == rhs.mSpecularRepeatX) && (mSpecularRepeatY == rhs.mSpecularRepeatY) && (mSpecularRotation == rhs.mSpecularRotation) &&
(mSpecularLightColor == rhs.mSpecularLightColor) && (mSpecularLightExponent == rhs.mSpecularLightExponent) &&
(mEnvironmentIntensity == rhs.mEnvironmentIntensity) && (mDiffuseAlphaMode == rhs.mDiffuseAlphaMode) && (mAlphaMaskCutoff == rhs.mAlphaMaskCutoff);
}
bool LLMaterial::operator != (const LLMaterial& rhs) const
{
return !(*this == rhs);
}
U32 LLMaterial::getShaderMask(U32 alpha_mode, bool is_alpha)
{ //NEVER incorporate this value into the message system -- this function will vary depending on viewer implementation
//two least significant bits are "diffuse alpha mode"
U32 ret = alpha_mode;
if (ret == DIFFUSE_ALPHA_MODE_DEFAULT)
{
ret = getDiffuseAlphaMode();
if (ret == DIFFUSE_ALPHA_MODE_BLEND && !is_alpha)
{
ret = DIFFUSE_ALPHA_MODE_NONE;
}
}
llassert(ret < SHADER_COUNT);
//next bit is whether or not specular map is present
const U32 SPEC_BIT = 0x4;
if (getSpecularID().notNull())
{
ret |= SPEC_BIT;
}
llassert(ret < SHADER_COUNT);
//next bit is whether or not normal map is present
const U32 NORM_BIT = 0x8;
if (getNormalID().notNull())
{
ret |= NORM_BIT;
}
llassert(ret < SHADER_COUNT);
return ret;
}
LLUUID LLMaterial::getHash() const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
// HACK - hash the bytes of this LLMaterial, but trim off the S32 in LLRefCount
LLUUID id;
HBXXH128::digest(id, (unsigned char*)this + sizeof(LLRefCount), sizeof(*this) - sizeof(LLRefCount));
return id;
}
+162
View File
@@ -0,0 +1,162 @@
/**
* @file llmaterial.h
* @brief Material definition
*
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#ifndef LL_LLMATERIAL_H
#define LL_LLMATERIAL_H
#include "llmaterialid.h"
#include "llsd.h"
#include "v4coloru.h"
#include "llpointer.h"
#include "llrefcount.h"
class LLMaterial : public LLRefCount
{
public:
typedef enum
{
DIFFUSE_ALPHA_MODE_NONE = 0,
DIFFUSE_ALPHA_MODE_BLEND = 1,
DIFFUSE_ALPHA_MODE_MASK = 2,
DIFFUSE_ALPHA_MODE_EMISSIVE = 3,
DIFFUSE_ALPHA_MODE_DEFAULT = 4,
} eDiffuseAlphaMode;
typedef enum
{
SHADER_COUNT = 16,
ALPHA_SHADER_COUNT = 4
} eShaderCount;
static const U8 DEFAULT_SPECULAR_LIGHT_EXPONENT = ((U8)(0.2f * 255));
static const LLColor4U DEFAULT_SPECULAR_LIGHT_COLOR;
static const U8 DEFAULT_ENV_INTENSITY = 0;
LLMaterial();
LLMaterial(const LLSD& material_data);
LLSD asLLSD() const;
void fromLLSD(const LLSD& material_data);
bool isEmpty() const
{
if( mNormalID.notNull() || mSpecularID.notNull() ) //|| mDiffuseAlphaMode != DIFFUSE_ALPHA_MODE_BLEND)
{
return false;
}
return true;
}
const LLUUID& getNormalID() const;
void setNormalID(const LLUUID& normal_id);
void getNormalOffset(F32& offset_x, F32& offset_y) const;
F32 getNormalOffsetX() const;
F32 getNormalOffsetY() const;
void setNormalOffset(F32 offset_x, F32 offset_y);
void setNormalOffsetX(F32 offset_x);
void setNormalOffsetY(F32 offset_y);
void getNormalRepeat(F32& repeat_x, F32& repeat_y) const;
F32 getNormalRepeatX() const;
F32 getNormalRepeatY() const;
void setNormalRepeat(F32 repeat_x, F32 repeat_y);
void setNormalRepeatX(F32 repeat_x);
void setNormalRepeatY(F32 repeat_y);
F32 getNormalRotation() const;
void setNormalRotation(F32 rot);
const LLUUID& getSpecularID() const;
void setSpecularID(const LLUUID& specular_id);
void getSpecularOffset(F32& offset_x, F32& offset_y) const;
F32 getSpecularOffsetX() const;
F32 getSpecularOffsetY() const;
void setSpecularOffset(F32 offset_x, F32 offset_y);
void setSpecularOffsetX(F32 offset_x);
void setSpecularOffsetY(F32 offset_y);
void getSpecularRepeat(F32& repeat_x, F32& repeat_y) const;
F32 getSpecularRepeatX() const;
F32 getSpecularRepeatY() const;
void setSpecularRepeat(F32 repeat_x, F32 repeat_y);
void setSpecularRepeatX(F32 repeat_x);
void setSpecularRepeatY(F32 repeat_y);
F32 getSpecularRotation() const;
void setSpecularRotation(F32 rot);
const LLColor4U getSpecularLightColor() const;
void setSpecularLightColor(const LLColor4U& color);
U8 getSpecularLightExponent() const;
void setSpecularLightExponent(U8 exponent);
U8 getEnvironmentIntensity() const;
void setEnvironmentIntensity(U8 intensity);
U8 getDiffuseAlphaMode() const;
void setDiffuseAlphaMode(U8 alpha_mode);
U8 getAlphaMaskCutoff() const;
void setAlphaMaskCutoff(U8 cutoff);
bool isNull() const;
static const LLMaterial null;
bool operator == (const LLMaterial& rhs) const;
bool operator != (const LLMaterial& rhs) const;
U32 getShaderMask(U32 alpha_mode, bool is_alpha);
LLUUID getHash() const;
protected:
LLUUID mNormalID;
F32 mNormalOffsetX;
F32 mNormalOffsetY;
F32 mNormalRepeatX;
F32 mNormalRepeatY;
F32 mNormalRotation;
LLUUID mSpecularID;
F32 mSpecularOffsetX;
F32 mSpecularOffsetY;
F32 mSpecularRepeatX;
F32 mSpecularRepeatY;
F32 mSpecularRotation;
LLColor4U mSpecularLightColor;
U8 mSpecularLightExponent;
U8 mEnvironmentIntensity;
U8 mDiffuseAlphaMode;
U8 mAlphaMaskCutoff;
};
typedef LLPointer<LLMaterial> LLMaterialPtr;
#endif // LL_LLMATERIAL_H
+195
View File
@@ -0,0 +1,195 @@
/**
* @file llmaterialid.cpp
* @brief Implementation of llmaterialid
* @author Stinson@lindenlab.com
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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 "linden_common.h"
#include "llmaterialid.h"
#include <string>
#include "llformat.h"
const LLMaterialID LLMaterialID::null;
LLMaterialID::LLMaterialID()
{
clear();
}
LLMaterialID::LLMaterialID(const LLSD& pMaterialID)
{
llassert(pMaterialID.isBinary());
parseFromBinary(pMaterialID.asBinary());
}
LLMaterialID::LLMaterialID(const LLSD::Binary& pMaterialID)
{
parseFromBinary(pMaterialID);
}
LLMaterialID::LLMaterialID(const void* pMemory)
{
set(pMemory);
}
LLMaterialID::LLMaterialID(const LLMaterialID& pOtherMaterialID)
{
copyFromOtherMaterialID(pOtherMaterialID);
}
LLMaterialID::LLMaterialID(const LLUUID& lluid)
{
set(lluid.mData);
}
LLMaterialID::~LLMaterialID()
{
}
bool LLMaterialID::operator == (const LLMaterialID& pOtherMaterialID) const
{
return (compareToOtherMaterialID(pOtherMaterialID) == 0);
}
bool LLMaterialID::operator != (const LLMaterialID& pOtherMaterialID) const
{
return (compareToOtherMaterialID(pOtherMaterialID) != 0);
}
bool LLMaterialID::operator < (const LLMaterialID& pOtherMaterialID) const
{
return (compareToOtherMaterialID(pOtherMaterialID) < 0);
}
bool LLMaterialID::operator <= (const LLMaterialID& pOtherMaterialID) const
{
return (compareToOtherMaterialID(pOtherMaterialID) <= 0);
}
bool LLMaterialID::operator > (const LLMaterialID& pOtherMaterialID) const
{
return (compareToOtherMaterialID(pOtherMaterialID) > 0);
}
bool LLMaterialID::operator >= (const LLMaterialID& pOtherMaterialID) const
{
return (compareToOtherMaterialID(pOtherMaterialID) >= 0);
}
LLMaterialID& LLMaterialID::operator = (const LLMaterialID& pOtherMaterialID)
{
copyFromOtherMaterialID(pOtherMaterialID);
return (*this);
}
bool LLMaterialID::isNull() const
{
return (compareToOtherMaterialID(LLMaterialID::null) == 0);
}
const U8* LLMaterialID::get() const
{
return mID;
}
void LLMaterialID::set(const void* pMemory)
{
llassert(pMemory != NULL);
// assumes that the required size of memory is available
memcpy(mID, pMemory, MATERIAL_ID_SIZE * sizeof(U8));
}
void LLMaterialID::clear()
{
memset(mID, 0, MATERIAL_ID_SIZE * sizeof(U8));
}
LLSD LLMaterialID::asLLSD() const
{
LLSD::Binary materialIDBinary;
materialIDBinary.resize(MATERIAL_ID_SIZE * sizeof(U8));
memcpy(materialIDBinary.data(), mID, MATERIAL_ID_SIZE * sizeof(U8));
LLSD materialID = std::move(materialIDBinary);
return materialID;
}
std::string LLMaterialID::asString() const
{
std::string materialIDString;
for (unsigned int i = 0U; i < static_cast<unsigned int>(MATERIAL_ID_SIZE / sizeof(U32)); ++i)
{
if (i != 0U)
{
materialIDString += "-";
}
const U32 *value = reinterpret_cast<const U32*>(&get()[i * sizeof(U32)]);
materialIDString += llformat("%08x", *value);
}
return materialIDString;
}
LLUUID LLMaterialID::asUUID() const
{
LLUUID ret;
memcpy(ret.mData, mID, MATERIAL_ID_SIZE);
return ret;
}
std::ostream& operator<<(std::ostream& s, const LLMaterialID &material_id)
{
s << material_id.asString();
return s;
}
void LLMaterialID::parseFromBinary (const LLSD::Binary& pMaterialID)
{
llassert(pMaterialID.size() == (MATERIAL_ID_SIZE * sizeof(U8)));
memcpy(mID, &pMaterialID[0], MATERIAL_ID_SIZE * sizeof(U8));
}
void LLMaterialID::copyFromOtherMaterialID(const LLMaterialID& pOtherMaterialID)
{
memcpy(mID, pOtherMaterialID.get(), MATERIAL_ID_SIZE * sizeof(U8));
}
int LLMaterialID::compareToOtherMaterialID(const LLMaterialID& pOtherMaterialID) const
{
int retVal = 0;
for (unsigned int i = 0U; (retVal == 0) && (i < static_cast<unsigned int>(MATERIAL_ID_SIZE / sizeof(U32))); ++i)
{
const U32 *thisValue = reinterpret_cast<const U32*>(&get()[i * sizeof(U32)]);
const U32 *otherValue = reinterpret_cast<const U32*>(&pOtherMaterialID.get()[i * sizeof(U32)]);
retVal = ((*thisValue < *otherValue) ? -1 : ((*thisValue > *otherValue) ? 1 : 0));
}
return retVal;
}
+105
View File
@@ -0,0 +1,105 @@
/**
* @file llmaterialid.h
* @brief Header file for llmaterialid
* @author Stinson@lindenlab.com
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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$
*/
#ifndef LL_LLMATERIALID_H
#define LL_LLMATERIALID_H
#define MATERIAL_ID_SIZE 16
#include <string>
#include "llsd.h"
class LLMaterialID
{
public:
LLMaterialID();
LLMaterialID(const LLSD& pMaterialID);
LLMaterialID(const LLSD::Binary& pMaterialID);
LLMaterialID(const void* pMemory);
LLMaterialID(const LLMaterialID& pOtherMaterialID);
LLMaterialID(const LLUUID& lluid);
~LLMaterialID();
bool operator == (const LLMaterialID& pOtherMaterialID) const;
bool operator != (const LLMaterialID& pOtherMaterialID) const;
bool operator < (const LLMaterialID& pOtherMaterialID) const;
bool operator <= (const LLMaterialID& pOtherMaterialID) const;
bool operator > (const LLMaterialID& pOtherMaterialID) const;
bool operator >= (const LLMaterialID& pOtherMaterialID) const;
LLMaterialID& operator = (const LLMaterialID& pOtherMaterialID);
bool isNull() const;
const U8* get() const;
void set(const void* pMemory);
void clear();
LLSD asLLSD() const;
std::string asString() const;
LLUUID asUUID() const;
friend std::ostream& operator<<(std::ostream& s, const LLMaterialID &material_id);
static const LLMaterialID null;
// Returns a 64 bits digest of the material Id, by XORing its two 64 bits
// long words. HB
inline U64 getDigest64() const
{
U64* tmp = (U64*)mID;
return tmp[0] ^ tmp[1];
}
private:
void parseFromBinary(const LLSD::Binary& pMaterialID);
void copyFromOtherMaterialID(const LLMaterialID& pOtherMaterialID);
int compareToOtherMaterialID(const LLMaterialID& pOtherMaterialID) const;
U8 mID[MATERIAL_ID_SIZE];
} ;
// std::hash implementation for LLMaterialID
namespace std
{
template<> struct hash<LLMaterialID>
{
inline size_t operator()(const LLMaterialID& id) const noexcept
{
return (size_t)id.getDigest64();
}
};
}
// For use with boost containers.
inline size_t hash_value(const LLMaterialID& id) noexcept
{
return (size_t)id.getDigest64();
}
#endif // LL_LLMATERIALID_H
+863
View File
@@ -0,0 +1,863 @@
/**
* @file llmaterialtable.cpp
* @brief Table of material names and IDs for viewer
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "linden_common.h"
#include "llmaterialtable.h"
#include "indra_constants.h"
#include "llstl.h"
#include "material_codes.h"
#include "sound_ids.h"
LLMaterialTable LLMaterialTable::basic(1);
/*
Old Havok 1 constants
// these are the approximately correct friction values for various materials
// however Havok1's friction dynamics are not very correct, so the effective
// friction coefficients that result from these numbers are approximately
// 25-50% too low, more incorrect for the lower values.
F32 const LLMaterialTable::FRICTION_MIN = 0.2f;
F32 const LLMaterialTable::FRICTION_GLASS = 0.2f; // borosilicate glass
F32 const LLMaterialTable::FRICTION_LIGHT = 0.2f; //
F32 const LLMaterialTable::FRICTION_METAL = 0.3f; // steel
F32 const LLMaterialTable::FRICTION_PLASTIC = 0.4f; // HDPE
F32 const LLMaterialTable::FRICTION_WOOD = 0.6f; // southern pine
F32 const LLMaterialTable::FRICTION_FLESH = 0.60f; // saltwater
F32 const LLMaterialTable::FRICTION_LAND = 0.78f; // dirt
F32 const LLMaterialTable::FRICTION_STONE = 0.8f; // concrete
F32 const LLMaterialTable::FRICTION_RUBBER = 0.9f; //
F32 const LLMaterialTable::FRICTION_MAX = 0.95f; //
*/
// #if LL_CURRENT_HAVOK_VERSION == LL_HAVOK_VERSION_460
// Havok4 has more correct friction dynamics, however here we have to use
// the "incorrect" equivalents for the legacy Havok1 behavior
F32 const LLMaterialTable::FRICTION_MIN = 0.15f;
F32 const LLMaterialTable::FRICTION_GLASS = 0.13f; // borosilicate glass
F32 const LLMaterialTable::FRICTION_LIGHT = 0.14f; //
F32 const LLMaterialTable::FRICTION_METAL = 0.22f; // steel
F32 const LLMaterialTable::FRICTION_PLASTIC = 0.3f; // HDPE
F32 const LLMaterialTable::FRICTION_WOOD = 0.44f; // southern pine
F32 const LLMaterialTable::FRICTION_FLESH = 0.46f; // saltwater
F32 const LLMaterialTable::FRICTION_LAND = 0.58f; // dirt
F32 const LLMaterialTable::FRICTION_STONE = 0.6f; // concrete
F32 const LLMaterialTable::FRICTION_RUBBER = 0.67f; //
F32 const LLMaterialTable::FRICTION_MAX = 0.71f; //
// #endif
F32 const LLMaterialTable::RESTITUTION_MIN = 0.02f;
F32 const LLMaterialTable::RESTITUTION_LAND = LLMaterialTable::RESTITUTION_MIN;
F32 const LLMaterialTable::RESTITUTION_FLESH = 0.2f; // saltwater
F32 const LLMaterialTable::RESTITUTION_STONE = 0.4f; // concrete
F32 const LLMaterialTable::RESTITUTION_METAL = 0.4f; // steel
F32 const LLMaterialTable::RESTITUTION_WOOD = 0.5f; // southern pine
F32 const LLMaterialTable::RESTITUTION_GLASS = 0.7f; // borosilicate glass
F32 const LLMaterialTable::RESTITUTION_PLASTIC = 0.7f; // HDPE
F32 const LLMaterialTable::RESTITUTION_LIGHT = 0.7f; //
F32 const LLMaterialTable::RESTITUTION_RUBBER = 0.9f; //
F32 const LLMaterialTable::RESTITUTION_MAX = 0.95f;
F32 const LLMaterialTable::DEFAULT_FRICTION = 0.5f;
F32 const LLMaterialTable::DEFAULT_RESTITUTION = 0.4f;
LLMaterialTable::LLMaterialTable()
: mCollisionSoundMatrix(NULL),
mSlidingSoundMatrix(NULL),
mRollingSoundMatrix(NULL)
{
}
LLMaterialTable::LLMaterialTable(U8 isBasic)
{
initBasicTable();
}
LLMaterialTable::~LLMaterialTable()
{
if (mCollisionSoundMatrix)
{
delete [] mCollisionSoundMatrix;
mCollisionSoundMatrix = NULL;
}
if (mSlidingSoundMatrix)
{
delete [] mSlidingSoundMatrix;
mSlidingSoundMatrix = NULL;
}
if (mRollingSoundMatrix)
{
delete [] mRollingSoundMatrix;
mRollingSoundMatrix = NULL;
}
for_each(mMaterialInfoList.begin(), mMaterialInfoList.end(), DeletePointer());
mMaterialInfoList.clear();
}
void LLMaterialTable::initTableTransNames(std::map<std::string, std::string> namemap)
{
for (info_list_t::iterator iter = mMaterialInfoList.begin();
iter != mMaterialInfoList.end(); ++iter)
{
LLMaterialInfo *infop = *iter;
std::string name = infop->mName;
infop->mName = namemap[name];
}
}
void LLMaterialTable::initBasicTable()
{
// *TODO: Translate
add(LL_MCODE_STONE,std::string("Stone"), LL_DEFAULT_STONE_UUID);
add(LL_MCODE_METAL,std::string("Metal"), LL_DEFAULT_METAL_UUID);
add(LL_MCODE_GLASS,std::string("Glass"), LL_DEFAULT_GLASS_UUID);
add(LL_MCODE_WOOD,std::string("Wood"), LL_DEFAULT_WOOD_UUID);
add(LL_MCODE_FLESH,std::string("Flesh"), LL_DEFAULT_FLESH_UUID);
add(LL_MCODE_PLASTIC,std::string("Plastic"), LL_DEFAULT_PLASTIC_UUID);
add(LL_MCODE_RUBBER,std::string("Rubber"), LL_DEFAULT_RUBBER_UUID);
add(LL_MCODE_LIGHT,std::string("Light"), LL_DEFAULT_LIGHT_UUID);
// specify densities for these materials. . .
// these were taken from http://www.mcelwee.net/html/densities_of_various_materials.html
addDensity(LL_MCODE_STONE,30.f);
addDensity(LL_MCODE_METAL,50.f);
addDensity(LL_MCODE_GLASS,20.f);
addDensity(LL_MCODE_WOOD,10.f);
addDensity(LL_MCODE_FLESH,10.f);
addDensity(LL_MCODE_PLASTIC,5.f);
addDensity(LL_MCODE_RUBBER,0.5f); //
addDensity(LL_MCODE_LIGHT,20.f); //
// add damage and energy values
addDamageAndEnergy(LL_MCODE_STONE, 1.f, 1.f, 1.f); // concrete
addDamageAndEnergy(LL_MCODE_METAL, 1.f, 1.f, 1.f); // steel
addDamageAndEnergy(LL_MCODE_GLASS, 1.f, 1.f, 1.f); // borosilicate glass
addDamageAndEnergy(LL_MCODE_WOOD, 1.f, 1.f, 1.f); // southern pine
addDamageAndEnergy(LL_MCODE_FLESH, 1.f, 1.f, 1.f); // saltwater
addDamageAndEnergy(LL_MCODE_PLASTIC, 1.f, 1.f, 1.f); // HDPE
addDamageAndEnergy(LL_MCODE_RUBBER, 1.f, 1.f, 1.f); //
addDamageAndEnergy(LL_MCODE_LIGHT, 1.f, 1.f, 1.f); //
addFriction(LL_MCODE_STONE,0.8f); // concrete
addFriction(LL_MCODE_METAL,0.3f); // steel
addFriction(LL_MCODE_GLASS,0.2f); // borosilicate glass
addFriction(LL_MCODE_WOOD,0.6f); // southern pine
addFriction(LL_MCODE_FLESH,0.9f); // saltwater
addFriction(LL_MCODE_PLASTIC,0.4f); // HDPE
addFriction(LL_MCODE_RUBBER,0.9f); //
addFriction(LL_MCODE_LIGHT,0.2f); //
addRestitution(LL_MCODE_STONE,0.4f); // concrete
addRestitution(LL_MCODE_METAL,0.4f); // steel
addRestitution(LL_MCODE_GLASS,0.7f); // borosilicate glass
addRestitution(LL_MCODE_WOOD,0.5f); // southern pine
addRestitution(LL_MCODE_FLESH,0.3f); // saltwater
addRestitution(LL_MCODE_PLASTIC,0.7f); // HDPE
addRestitution(LL_MCODE_RUBBER,0.9f); //
addRestitution(LL_MCODE_LIGHT,0.7f); //
addShatterSound(LL_MCODE_STONE,LLUUID("ea296329-0f09-4993-af1b-e6784bab1dc9"));
addShatterSound(LL_MCODE_METAL,LLUUID("d1375446-1c4d-470b-9135-30132433b678"));
addShatterSound(LL_MCODE_GLASS,LLUUID("85cda060-b393-48e6-81c8-2cfdfb275351"));
addShatterSound(LL_MCODE_WOOD,LLUUID("6f00669f-15e0-4793-a63e-c03f62fee43a"));
addShatterSound(LL_MCODE_FLESH,LLUUID("2d8c6f51-149e-4e23-8413-93a379b42b67"));
addShatterSound(LL_MCODE_PLASTIC,LLUUID("d55c7f3c-e1c3-4ddc-9eff-9ef805d9190e"));
addShatterSound(LL_MCODE_RUBBER,LLUUID("212b6d1e-8d9c-4986-b3aa-f3c6df8d987d"));
addShatterSound(LL_MCODE_LIGHT,LLUUID("d55c7f3c-e1c3-4ddc-9eff-9ef805d9190e"));
// CollisionSounds
mCollisionSoundMatrix = new LLUUID[LL_MCODE_END*LL_MCODE_END];
if (mCollisionSoundMatrix)
{
addCollisionSound(LL_MCODE_STONE, LL_MCODE_STONE, SND_STONE_STONE);
addCollisionSound(LL_MCODE_STONE, LL_MCODE_METAL, SND_STONE_METAL);
addCollisionSound(LL_MCODE_STONE, LL_MCODE_GLASS, SND_STONE_GLASS);
addCollisionSound(LL_MCODE_STONE, LL_MCODE_WOOD, SND_STONE_WOOD);
addCollisionSound(LL_MCODE_STONE, LL_MCODE_FLESH, SND_STONE_FLESH);
addCollisionSound(LL_MCODE_STONE, LL_MCODE_PLASTIC, SND_STONE_PLASTIC);
addCollisionSound(LL_MCODE_STONE, LL_MCODE_RUBBER, SND_STONE_RUBBER);
addCollisionSound(LL_MCODE_STONE, LL_MCODE_LIGHT, SND_STONE_PLASTIC);
addCollisionSound(LL_MCODE_METAL, LL_MCODE_METAL, SND_METAL_METAL);
addCollisionSound(LL_MCODE_METAL, LL_MCODE_GLASS, SND_METAL_GLASS);
addCollisionSound(LL_MCODE_METAL, LL_MCODE_WOOD, SND_METAL_WOOD);
addCollisionSound(LL_MCODE_METAL, LL_MCODE_FLESH, SND_METAL_FLESH);
addCollisionSound(LL_MCODE_METAL, LL_MCODE_PLASTIC, SND_METAL_PLASTIC);
addCollisionSound(LL_MCODE_METAL, LL_MCODE_LIGHT, SND_METAL_PLASTIC);
addCollisionSound(LL_MCODE_METAL, LL_MCODE_RUBBER, SND_METAL_RUBBER);
addCollisionSound(LL_MCODE_GLASS, LL_MCODE_GLASS, SND_GLASS_GLASS);
addCollisionSound(LL_MCODE_GLASS, LL_MCODE_WOOD, SND_GLASS_WOOD);
addCollisionSound(LL_MCODE_GLASS, LL_MCODE_FLESH, SND_GLASS_FLESH);
addCollisionSound(LL_MCODE_GLASS, LL_MCODE_PLASTIC, SND_GLASS_PLASTIC);
addCollisionSound(LL_MCODE_GLASS, LL_MCODE_RUBBER, SND_GLASS_RUBBER);
addCollisionSound(LL_MCODE_GLASS, LL_MCODE_LIGHT, SND_GLASS_PLASTIC);
addCollisionSound(LL_MCODE_WOOD, LL_MCODE_WOOD, SND_WOOD_WOOD);
addCollisionSound(LL_MCODE_WOOD, LL_MCODE_FLESH, SND_WOOD_FLESH);
addCollisionSound(LL_MCODE_WOOD, LL_MCODE_PLASTIC, SND_WOOD_PLASTIC);
addCollisionSound(LL_MCODE_WOOD, LL_MCODE_RUBBER, SND_WOOD_RUBBER);
addCollisionSound(LL_MCODE_WOOD, LL_MCODE_LIGHT, SND_WOOD_PLASTIC);
addCollisionSound(LL_MCODE_FLESH, LL_MCODE_FLESH, SND_FLESH_FLESH);
addCollisionSound(LL_MCODE_FLESH, LL_MCODE_PLASTIC, SND_FLESH_PLASTIC);
addCollisionSound(LL_MCODE_FLESH, LL_MCODE_RUBBER, SND_FLESH_RUBBER);
addCollisionSound(LL_MCODE_FLESH, LL_MCODE_LIGHT, SND_FLESH_PLASTIC);
addCollisionSound(LL_MCODE_RUBBER, LL_MCODE_RUBBER, SND_RUBBER_RUBBER);
addCollisionSound(LL_MCODE_RUBBER, LL_MCODE_PLASTIC, SND_RUBBER_PLASTIC);
addCollisionSound(LL_MCODE_RUBBER, LL_MCODE_LIGHT, SND_RUBBER_PLASTIC);
addCollisionSound(LL_MCODE_PLASTIC, LL_MCODE_PLASTIC, SND_PLASTIC_PLASTIC);
addCollisionSound(LL_MCODE_PLASTIC, LL_MCODE_LIGHT, SND_PLASTIC_PLASTIC);
addCollisionSound(LL_MCODE_LIGHT, LL_MCODE_LIGHT, SND_PLASTIC_PLASTIC);
}
// Sliding Sounds
mSlidingSoundMatrix = new LLUUID[LL_MCODE_END*LL_MCODE_END];
if (mSlidingSoundMatrix)
{
addSlidingSound(LL_MCODE_STONE, LL_MCODE_STONE, SND_SLIDE_STONE_STONE);
addSlidingSound(LL_MCODE_STONE, LL_MCODE_METAL, SND_SLIDE_STONE_STONE_01);
addSlidingSound(LL_MCODE_STONE, LL_MCODE_GLASS, SND_SLIDE_STONE_STONE_01);
addSlidingSound(LL_MCODE_STONE, LL_MCODE_WOOD, SND_SLIDE_STONE_WOOD);
addSlidingSound(LL_MCODE_STONE, LL_MCODE_FLESH, SND_SLIDE_STONE_STONE_01);
addSlidingSound(LL_MCODE_STONE, LL_MCODE_PLASTIC, SND_SLIDE_STONE_PLASTIC);
addSlidingSound(LL_MCODE_STONE, LL_MCODE_RUBBER, SND_SLIDE_STONE_RUBBER);
addSlidingSound(LL_MCODE_STONE, LL_MCODE_LIGHT, SND_SLIDE_STONE_PLASTIC);
addSlidingSound(LL_MCODE_METAL, LL_MCODE_METAL, SND_SLIDE_METAL_METAL);
addSlidingSound(LL_MCODE_METAL, LL_MCODE_GLASS, SND_SLIDE_METAL_GLASS);
addSlidingSound(LL_MCODE_METAL, LL_MCODE_WOOD, SND_SLIDE_METAL_WOOD);
addSlidingSound(LL_MCODE_METAL, LL_MCODE_FLESH, SND_SLIDE_METAL_FLESH);
addSlidingSound(LL_MCODE_METAL, LL_MCODE_PLASTIC, SND_SLIDE_STONE_STONE_01);
addSlidingSound(LL_MCODE_METAL, LL_MCODE_RUBBER, SND_SLIDE_METAL_RUBBER);
addSlidingSound(LL_MCODE_METAL, LL_MCODE_LIGHT, SND_SLIDE_STONE_STONE_01);
addSlidingSound(LL_MCODE_GLASS, LL_MCODE_GLASS, SND_SLIDE_STONE_STONE_01);
addSlidingSound(LL_MCODE_GLASS, LL_MCODE_WOOD, SND_SLIDE_STONE_STONE_01);
addSlidingSound(LL_MCODE_GLASS, LL_MCODE_FLESH, SND_SLIDE_STONE_STONE_01);
addSlidingSound(LL_MCODE_GLASS, LL_MCODE_PLASTIC, SND_SLIDE_STONE_STONE_01);
addSlidingSound(LL_MCODE_GLASS, LL_MCODE_RUBBER, SND_SLIDE_STONE_STONE_01);
addSlidingSound(LL_MCODE_GLASS, LL_MCODE_LIGHT, SND_SLIDE_STONE_STONE_01);
addSlidingSound(LL_MCODE_WOOD, LL_MCODE_WOOD, SND_SLIDE_WOOD_WOOD);
addSlidingSound(LL_MCODE_WOOD, LL_MCODE_FLESH, SND_SLIDE_WOOD_FLESH);
addSlidingSound(LL_MCODE_WOOD, LL_MCODE_PLASTIC, SND_SLIDE_WOOD_PLASTIC);
addSlidingSound(LL_MCODE_WOOD, LL_MCODE_RUBBER, SND_SLIDE_STONE_STONE_01);
addSlidingSound(LL_MCODE_WOOD, LL_MCODE_LIGHT, SND_SLIDE_WOOD_PLASTIC);
addSlidingSound(LL_MCODE_FLESH, LL_MCODE_FLESH, SND_SLIDE_FLESH_FLESH);
addSlidingSound(LL_MCODE_FLESH, LL_MCODE_PLASTIC, SND_SLIDE_STONE_STONE_01);
addSlidingSound(LL_MCODE_FLESH, LL_MCODE_RUBBER, SND_SLIDE_STONE_STONE_01);
addSlidingSound(LL_MCODE_FLESH, LL_MCODE_LIGHT, SND_SLIDE_STONE_STONE_01);
addSlidingSound(LL_MCODE_RUBBER, LL_MCODE_RUBBER, SND_SLIDE_STONE_STONE_01);
addSlidingSound(LL_MCODE_RUBBER, LL_MCODE_PLASTIC, SND_SLIDE_RUBBER_PLASTIC);
addSlidingSound(LL_MCODE_RUBBER, LL_MCODE_LIGHT, SND_SLIDE_RUBBER_PLASTIC);
addSlidingSound(LL_MCODE_PLASTIC, LL_MCODE_PLASTIC, SND_SLIDE_STONE_STONE_01);
addSlidingSound(LL_MCODE_PLASTIC, LL_MCODE_LIGHT, SND_SLIDE_STONE_STONE_01);
addSlidingSound(LL_MCODE_LIGHT, LL_MCODE_LIGHT, SND_SLIDE_STONE_STONE_01);
}
// Rolling Sounds
mRollingSoundMatrix = new LLUUID[LL_MCODE_END*LL_MCODE_END];
if (mRollingSoundMatrix)
{
addRollingSound(LL_MCODE_STONE, LL_MCODE_STONE, SND_ROLL_STONE_STONE);
addRollingSound(LL_MCODE_STONE, LL_MCODE_METAL, SND_SLIDE_STONE_STONE_01);
addRollingSound(LL_MCODE_STONE, LL_MCODE_GLASS, SND_SLIDE_STONE_STONE_01);
addRollingSound(LL_MCODE_STONE, LL_MCODE_WOOD, SND_ROLL_STONE_WOOD);
addRollingSound(LL_MCODE_STONE, LL_MCODE_FLESH, SND_SLIDE_STONE_STONE_01);
addRollingSound(LL_MCODE_STONE, LL_MCODE_PLASTIC, SND_ROLL_STONE_PLASTIC);
addRollingSound(LL_MCODE_STONE, LL_MCODE_RUBBER, SND_SLIDE_STONE_STONE_01);
addRollingSound(LL_MCODE_STONE, LL_MCODE_LIGHT, SND_ROLL_STONE_PLASTIC);
addRollingSound(LL_MCODE_METAL, LL_MCODE_METAL, SND_SLIDE_STONE_STONE_01);
addRollingSound(LL_MCODE_METAL, LL_MCODE_GLASS, SND_ROLL_METAL_GLASS);
addRollingSound(LL_MCODE_METAL, LL_MCODE_WOOD, SND_ROLL_METAL_WOOD);
addRollingSound(LL_MCODE_METAL, LL_MCODE_FLESH, SND_SLIDE_STONE_STONE_01);
addRollingSound(LL_MCODE_METAL, LL_MCODE_PLASTIC, SND_ROLL_METAL_WOOD);
addRollingSound(LL_MCODE_METAL, LL_MCODE_RUBBER, SND_SLIDE_STONE_STONE_01);
addRollingSound(LL_MCODE_METAL, LL_MCODE_LIGHT, SND_ROLL_METAL_WOOD);
addRollingSound(LL_MCODE_GLASS, LL_MCODE_GLASS, SND_SLIDE_STONE_STONE_01);
addRollingSound(LL_MCODE_GLASS, LL_MCODE_WOOD, SND_ROLL_GLASS_WOOD);
addRollingSound(LL_MCODE_GLASS, LL_MCODE_FLESH, SND_SLIDE_STONE_STONE_01);
addRollingSound(LL_MCODE_GLASS, LL_MCODE_PLASTIC, SND_SLIDE_STONE_STONE_01);
addRollingSound(LL_MCODE_GLASS, LL_MCODE_RUBBER, SND_SLIDE_STONE_STONE_01);
addRollingSound(LL_MCODE_GLASS, LL_MCODE_LIGHT, SND_SLIDE_STONE_STONE_01);
addRollingSound(LL_MCODE_WOOD, LL_MCODE_WOOD, SND_ROLL_WOOD_WOOD);
addRollingSound(LL_MCODE_WOOD, LL_MCODE_FLESH, SND_ROLL_WOOD_FLESH);
addRollingSound(LL_MCODE_WOOD, LL_MCODE_PLASTIC, SND_ROLL_WOOD_PLASTIC);
addRollingSound(LL_MCODE_WOOD, LL_MCODE_RUBBER, SND_SLIDE_STONE_STONE_01);
addRollingSound(LL_MCODE_WOOD, LL_MCODE_LIGHT, SND_ROLL_WOOD_PLASTIC);
addRollingSound(LL_MCODE_FLESH, LL_MCODE_FLESH, SND_SLIDE_STONE_STONE_01);
addRollingSound(LL_MCODE_FLESH, LL_MCODE_PLASTIC, SND_ROLL_FLESH_PLASTIC);
addRollingSound(LL_MCODE_FLESH, LL_MCODE_RUBBER, SND_SLIDE_STONE_STONE_01);
addRollingSound(LL_MCODE_FLESH, LL_MCODE_LIGHT, SND_ROLL_FLESH_PLASTIC);
addRollingSound(LL_MCODE_RUBBER, LL_MCODE_RUBBER, SND_SLIDE_STONE_STONE_01);
addRollingSound(LL_MCODE_RUBBER, LL_MCODE_PLASTIC, SND_SLIDE_STONE_STONE_01);
addRollingSound(LL_MCODE_RUBBER, LL_MCODE_LIGHT, SND_SLIDE_STONE_STONE_01);
addRollingSound(LL_MCODE_PLASTIC, LL_MCODE_PLASTIC, SND_ROLL_PLASTIC_PLASTIC);
addRollingSound(LL_MCODE_PLASTIC, LL_MCODE_LIGHT, SND_ROLL_PLASTIC_PLASTIC);
addRollingSound(LL_MCODE_LIGHT, LL_MCODE_LIGHT, SND_ROLL_PLASTIC_PLASTIC);
}
}
// <FS:Beq> FIRE-31628 Use OpenSim collision sounds when in OpenSim
#ifdef OPENSIM
void LLMaterialTable::replaceCollsionSounds(bool useOpenSim)
{
if(mCollisionSoundMatrix)
delete[] mCollisionSoundMatrix;
mCollisionSoundMatrix= new LLUUID[LL_MCODE_END*LL_MCODE_END];
if (mCollisionSoundMatrix)
{
if(useOpenSim)
{
addCollisionSound(LL_MCODE_STONE, LL_MCODE_FLESH, OPENSIM_SND_STONE_FLESH);
addCollisionSound(LL_MCODE_STONE, LL_MCODE_METAL, OPENSIM_SND_STONE_METAL);
addCollisionSound(LL_MCODE_STONE, LL_MCODE_GLASS, OPENSIM_SND_STONE_GLASS);
addCollisionSound(LL_MCODE_STONE, LL_MCODE_PLASTIC, OPENSIM_SND_STONE_PLASTIC);
addCollisionSound(LL_MCODE_STONE, LL_MCODE_RUBBER, OPENSIM_SND_STONE_RUBBER);
addCollisionSound(LL_MCODE_STONE, LL_MCODE_STONE, OPENSIM_SND_STONE_STONE);
addCollisionSound(LL_MCODE_STONE, LL_MCODE_WOOD, OPENSIM_SND_STONE_WOOD);
addCollisionSound(LL_MCODE_STONE, LL_MCODE_LIGHT, OPENSIM_SND_STONE_PLASTIC);
addCollisionSound(LL_MCODE_METAL, LL_MCODE_FLESH, OPENSIM_SND_METAL_FLESH);
addCollisionSound(LL_MCODE_METAL, LL_MCODE_GLASS, OPENSIM_SND_METAL_GLASS);
addCollisionSound(LL_MCODE_METAL, LL_MCODE_METAL, OPENSIM_SND_METAL_METAL);
addCollisionSound(LL_MCODE_METAL, LL_MCODE_PLASTIC, OPENSIM_SND_METAL_PLASTIC);
addCollisionSound(LL_MCODE_METAL, LL_MCODE_RUBBER, OPENSIM_SND_METAL_RUBBER);
addCollisionSound(LL_MCODE_METAL, LL_MCODE_WOOD, OPENSIM_SND_METAL_WOOD);
addCollisionSound(LL_MCODE_METAL, LL_MCODE_LIGHT, OPENSIM_SND_METAL_PLASTIC);
addCollisionSound(LL_MCODE_GLASS, LL_MCODE_FLESH, OPENSIM_SND_GLASS_FLESH);
addCollisionSound(LL_MCODE_GLASS, LL_MCODE_GLASS, OPENSIM_SND_GLASS_GLASS);
addCollisionSound(LL_MCODE_GLASS, LL_MCODE_PLASTIC, OPENSIM_SND_GLASS_PLASTIC);
addCollisionSound(LL_MCODE_GLASS, LL_MCODE_RUBBER, OPENSIM_SND_GLASS_RUBBER);
addCollisionSound(LL_MCODE_GLASS, LL_MCODE_WOOD, OPENSIM_SND_GLASS_WOOD);
addCollisionSound(LL_MCODE_GLASS, LL_MCODE_LIGHT, OPENSIM_SND_GLASS_PLASTIC);
addCollisionSound(LL_MCODE_WOOD, LL_MCODE_FLESH, OPENSIM_SND_WOOD_FLESH);
addCollisionSound(LL_MCODE_WOOD, LL_MCODE_PLASTIC, OPENSIM_SND_WOOD_PLASTIC);
addCollisionSound(LL_MCODE_WOOD, LL_MCODE_RUBBER, OPENSIM_SND_WOOD_RUBBER);
addCollisionSound(LL_MCODE_WOOD, LL_MCODE_WOOD, OPENSIM_SND_WOOD_WOOD);
addCollisionSound(LL_MCODE_WOOD, LL_MCODE_LIGHT, OPENSIM_SND_WOOD_PLASTIC);
addCollisionSound(LL_MCODE_FLESH, LL_MCODE_FLESH, OPENSIM_SND_FLESH_FLESH);
addCollisionSound(LL_MCODE_FLESH, LL_MCODE_PLASTIC, OPENSIM_SND_FLESH_PLASTIC);
addCollisionSound(LL_MCODE_FLESH, LL_MCODE_RUBBER, OPENSIM_SND_FLESH_RUBBER);
addCollisionSound(LL_MCODE_FLESH, LL_MCODE_LIGHT, OPENSIM_SND_FLESH_PLASTIC);
addCollisionSound(LL_MCODE_RUBBER, LL_MCODE_RUBBER, OPENSIM_SND_RUBBER_RUBBER);
addCollisionSound(LL_MCODE_RUBBER, LL_MCODE_LIGHT, OPENSIM_SND_RUBBER_PLASTIC);
addCollisionSound(LL_MCODE_PLASTIC, LL_MCODE_PLASTIC, OPENSIM_SND_PLASTIC_PLASTIC);
addCollisionSound(LL_MCODE_PLASTIC, LL_MCODE_RUBBER, OPENSIM_SND_PLASTIC_RUBBER);
addCollisionSound(LL_MCODE_PLASTIC, LL_MCODE_LIGHT, OPENSIM_SND_PLASTIC_PLASTIC);
addCollisionSound(LL_MCODE_LIGHT, LL_MCODE_LIGHT, OPENSIM_SND_PLASTIC_PLASTIC);
}
else
{
addCollisionSound(LL_MCODE_STONE, LL_MCODE_STONE, SND_STONE_STONE);
addCollisionSound(LL_MCODE_STONE, LL_MCODE_METAL, SND_STONE_METAL);
addCollisionSound(LL_MCODE_STONE, LL_MCODE_GLASS, SND_STONE_GLASS);
addCollisionSound(LL_MCODE_STONE, LL_MCODE_WOOD, SND_STONE_WOOD);
addCollisionSound(LL_MCODE_STONE, LL_MCODE_FLESH, SND_STONE_FLESH);
addCollisionSound(LL_MCODE_STONE, LL_MCODE_PLASTIC, SND_STONE_PLASTIC);
addCollisionSound(LL_MCODE_STONE, LL_MCODE_RUBBER, SND_STONE_RUBBER);
addCollisionSound(LL_MCODE_STONE, LL_MCODE_LIGHT, SND_STONE_PLASTIC);
addCollisionSound(LL_MCODE_METAL, LL_MCODE_METAL, SND_METAL_METAL);
addCollisionSound(LL_MCODE_METAL, LL_MCODE_GLASS, SND_METAL_GLASS);
addCollisionSound(LL_MCODE_METAL, LL_MCODE_WOOD, SND_METAL_WOOD);
addCollisionSound(LL_MCODE_METAL, LL_MCODE_FLESH, SND_METAL_FLESH);
addCollisionSound(LL_MCODE_METAL, LL_MCODE_PLASTIC, SND_METAL_PLASTIC);
addCollisionSound(LL_MCODE_METAL, LL_MCODE_LIGHT, SND_METAL_PLASTIC);
addCollisionSound(LL_MCODE_METAL, LL_MCODE_RUBBER, SND_METAL_RUBBER);
addCollisionSound(LL_MCODE_GLASS, LL_MCODE_GLASS, SND_GLASS_GLASS);
addCollisionSound(LL_MCODE_GLASS, LL_MCODE_WOOD, SND_GLASS_WOOD);
addCollisionSound(LL_MCODE_GLASS, LL_MCODE_FLESH, SND_GLASS_FLESH);
addCollisionSound(LL_MCODE_GLASS, LL_MCODE_PLASTIC, SND_GLASS_PLASTIC);
addCollisionSound(LL_MCODE_GLASS, LL_MCODE_RUBBER, SND_GLASS_RUBBER);
addCollisionSound(LL_MCODE_GLASS, LL_MCODE_LIGHT, SND_GLASS_PLASTIC);
addCollisionSound(LL_MCODE_WOOD, LL_MCODE_WOOD, SND_WOOD_WOOD);
addCollisionSound(LL_MCODE_WOOD, LL_MCODE_FLESH, SND_WOOD_FLESH);
addCollisionSound(LL_MCODE_WOOD, LL_MCODE_PLASTIC, SND_WOOD_PLASTIC);
addCollisionSound(LL_MCODE_WOOD, LL_MCODE_RUBBER, SND_WOOD_RUBBER);
addCollisionSound(LL_MCODE_WOOD, LL_MCODE_LIGHT, SND_WOOD_PLASTIC);
addCollisionSound(LL_MCODE_FLESH, LL_MCODE_FLESH, SND_FLESH_FLESH);
addCollisionSound(LL_MCODE_FLESH, LL_MCODE_PLASTIC, SND_FLESH_PLASTIC);
addCollisionSound(LL_MCODE_FLESH, LL_MCODE_RUBBER, SND_FLESH_RUBBER);
addCollisionSound(LL_MCODE_FLESH, LL_MCODE_LIGHT, SND_FLESH_PLASTIC);
addCollisionSound(LL_MCODE_RUBBER, LL_MCODE_RUBBER, SND_RUBBER_RUBBER);
addCollisionSound(LL_MCODE_RUBBER, LL_MCODE_PLASTIC, SND_RUBBER_PLASTIC);
addCollisionSound(LL_MCODE_RUBBER, LL_MCODE_LIGHT, SND_RUBBER_PLASTIC);
addCollisionSound(LL_MCODE_PLASTIC, LL_MCODE_PLASTIC, SND_PLASTIC_PLASTIC);
addCollisionSound(LL_MCODE_PLASTIC, LL_MCODE_LIGHT, SND_PLASTIC_PLASTIC);
addCollisionSound(LL_MCODE_LIGHT, LL_MCODE_LIGHT, SND_PLASTIC_PLASTIC);
}
}
}
#endif // OPENSIM
// </FS:Beq>
bool LLMaterialTable::add(U8 mcode, const std::string& name, const LLUUID &uuid)
{
LLMaterialInfo *infop;
infop = new LLMaterialInfo(mcode,name,uuid);
if (!infop) return false;
// Add at the end so the order in menus matches the order in this
// file. JNC 11.30.01
mMaterialInfoList.push_back(infop);
return true;
}
bool LLMaterialTable::addCollisionSound(U8 mcode, U8 mcode2, const LLUUID &uuid)
{
if (mCollisionSoundMatrix && (mcode < LL_MCODE_END) && (mcode2 < LL_MCODE_END))
{
mCollisionSoundMatrix[mcode * LL_MCODE_END + mcode2] = uuid;
if (mcode != mcode2)
{
mCollisionSoundMatrix[mcode2 * LL_MCODE_END + mcode] = uuid;
}
}
return true;
}
bool LLMaterialTable::addSlidingSound(U8 mcode, U8 mcode2, const LLUUID &uuid)
{
if (mSlidingSoundMatrix && (mcode < LL_MCODE_END) && (mcode2 < LL_MCODE_END))
{
mSlidingSoundMatrix[mcode * LL_MCODE_END + mcode2] = uuid;
if (mcode != mcode2)
{
mSlidingSoundMatrix[mcode2 * LL_MCODE_END + mcode] = uuid;
}
}
return true;
}
bool LLMaterialTable::addRollingSound(U8 mcode, U8 mcode2, const LLUUID &uuid)
{
if (mRollingSoundMatrix && (mcode < LL_MCODE_END) && (mcode2 < LL_MCODE_END))
{
mRollingSoundMatrix[mcode * LL_MCODE_END + mcode2] = uuid;
if (mcode != mcode2)
{
mRollingSoundMatrix[mcode2 * LL_MCODE_END + mcode] = uuid;
}
}
return true;
}
bool LLMaterialTable::addShatterSound(U8 mcode, const LLUUID &uuid)
{
for (info_list_t::iterator iter = mMaterialInfoList.begin();
iter != mMaterialInfoList.end(); ++iter)
{
LLMaterialInfo *infop = *iter;
if (mcode == infop->mMCode)
{
infop->mShatterSoundID = uuid;
return true;
}
}
return false;
}
bool LLMaterialTable::addDensity(U8 mcode, const F32 &density)
{
for (info_list_t::iterator iter = mMaterialInfoList.begin();
iter != mMaterialInfoList.end(); ++iter)
{
LLMaterialInfo *infop = *iter;
if (mcode == infop->mMCode)
{
infop->mDensity = density;
return true;
}
}
return false;
}
bool LLMaterialTable::addRestitution(U8 mcode, const F32 &restitution)
{
for (info_list_t::iterator iter = mMaterialInfoList.begin();
iter != mMaterialInfoList.end(); ++iter)
{
LLMaterialInfo *infop = *iter;
if (mcode == infop->mMCode)
{
infop->mRestitution = restitution;
return true;
}
}
return false;
}
bool LLMaterialTable::addFriction(U8 mcode, const F32 &friction)
{
for (info_list_t::iterator iter = mMaterialInfoList.begin();
iter != mMaterialInfoList.end(); ++iter)
{
LLMaterialInfo *infop = *iter;
if (mcode == infop->mMCode)
{
infop->mFriction = friction;
return true;
}
}
return false;
}
bool LLMaterialTable::addDamageAndEnergy(U8 mcode, const F32 &hp_mod, const F32 &damage_mod, const F32 &ep_mod)
{
for (info_list_t::iterator iter = mMaterialInfoList.begin();
iter != mMaterialInfoList.end(); ++iter)
{
LLMaterialInfo *infop = *iter;
if (mcode == infop->mMCode)
{
infop->mHPModifier = hp_mod;
infop->mDamageModifier = damage_mod;
infop->mEPModifier = ep_mod;
return true;
}
}
return false;
}
LLUUID LLMaterialTable::getDefaultTextureID(const std::string& name)
{
for (info_list_t::iterator iter = mMaterialInfoList.begin();
iter != mMaterialInfoList.end(); ++iter)
{
LLMaterialInfo *infop = *iter;
if (name == infop->mName)
{
return infop->mDefaultTextureID;
}
}
return LLUUID::null;
}
LLUUID LLMaterialTable::getDefaultTextureID(U8 mcode)
{
mcode &= LL_MCODE_MASK;
for (info_list_t::iterator iter = mMaterialInfoList.begin();
iter != mMaterialInfoList.end(); ++iter)
{
LLMaterialInfo *infop = *iter;
if (mcode == infop->mMCode)
{
return infop->mDefaultTextureID;
}
}
return LLUUID::null;
}
U8 LLMaterialTable::getMCode(const std::string& name)
{
for (info_list_t::iterator iter = mMaterialInfoList.begin();
iter != mMaterialInfoList.end(); ++iter)
{
LLMaterialInfo *infop = *iter;
if (name == infop->mName)
{
return infop->mMCode;
}
}
return 0;
}
std::string LLMaterialTable::getName(U8 mcode)
{
mcode &= LL_MCODE_MASK;
for (info_list_t::iterator iter = mMaterialInfoList.begin();
iter != mMaterialInfoList.end(); ++iter)
{
LLMaterialInfo *infop = *iter;
if (mcode == infop->mMCode)
{
return infop->mName;
}
}
return std::string();
}
LLUUID LLMaterialTable::getCollisionSoundUUID(U8 mcode, U8 mcode2)
{
mcode &= LL_MCODE_MASK;
mcode2 &= LL_MCODE_MASK;
//LL_INFOS() << "code 1: " << ((U32) mcode) << " code 2:" << ((U32) mcode2) << LL_ENDL;
if (mCollisionSoundMatrix && (mcode < LL_MCODE_END) && (mcode2 < LL_MCODE_END))
{
return(mCollisionSoundMatrix[mcode * LL_MCODE_END + mcode2]);
}
else
{
//LL_INFOS() << "Null Sound" << LL_ENDL;
return(SND_NULL);
}
}
bool LLMaterialTable::isCollisionSound(const LLUUID &uuid)
{
for (U8 i = 0; i < LL_MCODE_END; i++)
{
for (U8 j = 0; j < LL_MCODE_END; j++)
{
i &= LL_MCODE_MASK;
j &= LL_MCODE_MASK;
if (mCollisionSoundMatrix[i * LL_MCODE_END + j] == uuid)
{
return true;
}
}
}
return false;
}
LLUUID LLMaterialTable::getSlidingSoundUUID(U8 mcode, U8 mcode2)
{
mcode &= LL_MCODE_MASK;
mcode2 &= LL_MCODE_MASK;
if (mSlidingSoundMatrix && (mcode < LL_MCODE_END) && (mcode2 < LL_MCODE_END))
{
return(mSlidingSoundMatrix[mcode * LL_MCODE_END + mcode2]);
}
else
{
return(SND_NULL);
}
}
LLUUID LLMaterialTable::getRollingSoundUUID(U8 mcode, U8 mcode2)
{
mcode &= LL_MCODE_MASK;
mcode2 &= LL_MCODE_MASK;
if (mRollingSoundMatrix && (mcode < LL_MCODE_END) && (mcode2 < LL_MCODE_END))
{
return(mRollingSoundMatrix[mcode * LL_MCODE_END + mcode2]);
}
else
{
return(SND_NULL);
}
}
LLUUID LLMaterialTable::getGroundCollisionSoundUUID(U8 mcode)
{
// Create material appropriate sounds for collisions with the ground
// For now, simply return a single sound for all materials
return SND_STONE_DIRT_02;
}
LLUUID LLMaterialTable::getGroundSlidingSoundUUID(U8 mcode)
{
// Create material-specific sound for sliding on ground
// For now, just return a single sound
return SND_SLIDE_STONE_STONE_01;
}
LLUUID LLMaterialTable::getGroundRollingSoundUUID(U8 mcode)
{
// Create material-specific sound for rolling on ground
// For now, just return a single sound
return SND_SLIDE_STONE_STONE_01;
}
LLUUID LLMaterialTable::getCollisionParticleUUID(U8 mcode, U8 mcode2)
{
// Returns an appropriate UUID to use as sprite at collision betweeen objects
// For now, just return a single image
return IMG_SHOT;
}
LLUUID LLMaterialTable::getGroundCollisionParticleUUID(U8 mcode)
{
// Returns an appropriate
// For now, just return a single sound
return IMG_SMOKE_POOF;
}
F32 LLMaterialTable::getDensity(U8 mcode)
{
mcode &= LL_MCODE_MASK;
for (info_list_t::iterator iter = mMaterialInfoList.begin();
iter != mMaterialInfoList.end(); ++iter)
{
LLMaterialInfo *infop = *iter;
if (mcode == infop->mMCode)
{
return infop->mDensity;
}
}
return 0.f;
}
F32 LLMaterialTable::getRestitution(U8 mcode)
{
mcode &= LL_MCODE_MASK;
for (info_list_t::iterator iter = mMaterialInfoList.begin();
iter != mMaterialInfoList.end(); ++iter)
{
LLMaterialInfo *infop = *iter;
if (mcode == infop->mMCode)
{
return infop->mRestitution;
}
}
return LLMaterialTable::DEFAULT_RESTITUTION;
}
F32 LLMaterialTable::getFriction(U8 mcode)
{
mcode &= LL_MCODE_MASK;
for (info_list_t::iterator iter = mMaterialInfoList.begin();
iter != mMaterialInfoList.end(); ++iter)
{
LLMaterialInfo *infop = *iter;
if (mcode == infop->mMCode)
{
return infop->mFriction;
}
}
return LLMaterialTable::DEFAULT_FRICTION;
}
F32 LLMaterialTable::getHPMod(U8 mcode)
{
mcode &= LL_MCODE_MASK;
for (info_list_t::iterator iter = mMaterialInfoList.begin();
iter != mMaterialInfoList.end(); ++iter)
{
LLMaterialInfo *infop = *iter;
if (mcode == infop->mMCode)
{
return infop->mHPModifier;
}
}
return 1.f;
}
F32 LLMaterialTable::getDamageMod(U8 mcode)
{
mcode &= LL_MCODE_MASK;
for (info_list_t::iterator iter = mMaterialInfoList.begin();
iter != mMaterialInfoList.end(); ++iter)
{
LLMaterialInfo *infop = *iter;
if (mcode == infop->mMCode)
{
return infop->mDamageModifier;
}
}
return 1.f;
}
F32 LLMaterialTable::getEPMod(U8 mcode)
{
mcode &= LL_MCODE_MASK;
for (info_list_t::iterator iter = mMaterialInfoList.begin();
iter != mMaterialInfoList.end(); ++iter)
{
LLMaterialInfo *infop = *iter;
if (mcode == infop->mMCode)
{
return infop->mEPModifier;
}
}
return 1.f;
}
LLUUID LLMaterialTable::getShatterSoundUUID(U8 mcode)
{
mcode &= LL_MCODE_MASK;
for (info_list_t::iterator iter = mMaterialInfoList.begin();
iter != mMaterialInfoList.end(); ++iter)
{
LLMaterialInfo *infop = *iter;
if (mcode == infop->mMCode)
{
return infop->mShatterSoundID;
}
}
return SND_NULL;
}
+196
View File
@@ -0,0 +1,196 @@
/**
* @file llmaterialtable.h
* @brief Table of material information for the viewer UI
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#ifndef LL_LLMATERIALTABLE_H
#define LL_LLMATERIALTABLE_H
#include "lluuid.h"
#include "llstring.h"
#include <list>
class LLMaterialInfo;
const U32 LLMATERIAL_INFO_NAME_LENGTH = 256;
// We've moved toward more reasonable mass values for the Havok4 engine.
// The LEGACY_DEFAULT_OBJECT_DENSITY is used to maintain support for
// legacy scripts code (llGetMass()) and script energy consumption.
const F32 DEFAULT_OBJECT_DENSITY = 1000.0f; // per m^3
const F32 LEGACY_DEFAULT_OBJECT_DENSITY = 10.0f;
// Avatars density depends on the collision shape used. The approximate
// legacy volumes of avatars are:
// Body_Length Body_Width Body_Fat Leg_Length Volume(m^3)
// -------------------------------------------------------
// min | min | min | min | 0.123 |
// max | max | max | max | 0.208 |
//
// Either the avatar shape must be tweaked to match those volumes
// or the DEFAULT_AVATAR_DENSITY must be adjusted to achieve the
// legacy mass.
//
// The current density appears to be low because the mass and
// inertia are computed as if the avatar were a cylinder which
// has more volume than the actual collision shape of the avatar.
// See the physics engine mass properties code for more info.
const F32 DEFAULT_AVATAR_DENSITY = 445.3f; // was 444.24f;
class LLMaterialTable
{
public:
static const F32 FRICTION_MIN;
static const F32 FRICTION_GLASS;
static const F32 FRICTION_LIGHT;
static const F32 FRICTION_METAL;
static const F32 FRICTION_PLASTIC;
static const F32 FRICTION_WOOD;
static const F32 FRICTION_LAND;
static const F32 FRICTION_STONE;
static const F32 FRICTION_FLESH;
static const F32 FRICTION_RUBBER;
static const F32 FRICTION_MAX;
static const F32 RESTITUTION_MIN;
static const F32 RESTITUTION_LAND;
static const F32 RESTITUTION_FLESH;
static const F32 RESTITUTION_STONE;
static const F32 RESTITUTION_METAL;
static const F32 RESTITUTION_WOOD;
static const F32 RESTITUTION_GLASS;
static const F32 RESTITUTION_PLASTIC;
static const F32 RESTITUTION_LIGHT;
static const F32 RESTITUTION_RUBBER;
static const F32 RESTITUTION_MAX;
typedef std::list<LLMaterialInfo*> info_list_t;
info_list_t mMaterialInfoList;
LLUUID *mCollisionSoundMatrix;
LLUUID *mSlidingSoundMatrix;
LLUUID *mRollingSoundMatrix;
static const F32 DEFAULT_FRICTION;
static const F32 DEFAULT_RESTITUTION;
public:
LLMaterialTable();
LLMaterialTable(U8); // cheat with an overloaded constructor to build our basic table
~LLMaterialTable();
void initBasicTable();
void initTableTransNames(std::map<std::string, std::string> namemap);
bool add(U8 mcode, const std::string& name, const LLUUID &uuid);
bool addCollisionSound(U8 mcode, U8 mcode2, const LLUUID &uuid);
bool addSlidingSound(U8 mcode, U8 mcode2, const LLUUID &uuid);
bool addRollingSound(U8 mcode, U8 mcode2, const LLUUID &uuid);
bool addShatterSound(U8 mcode, const LLUUID &uuid);
bool addDensity(U8 mcode, const F32 &density);
bool addFriction(U8 mcode, const F32 &friction);
bool addRestitution(U8 mcode, const F32 &restitution);
bool addDamageAndEnergy(U8 mcode, const F32 &hp_mod, const F32 &damage_mod, const F32 &ep_mod);
// <FS:Beq> FIRE-31628 Use OpenSim collision sounds when in OpenSim
#ifdef OPENSIM
void replaceCollsionSounds(bool useOpenSim=false);
#endif
// </FS:Beq>
LLUUID getDefaultTextureID(const std::string& name); // LLUUID::null if not found
LLUUID getDefaultTextureID(U8 mcode); // LLUUID::null if not found
U8 getMCode(const std::string& name); // 0 if not found
std::string getName(U8 mcode);
F32 getDensity(U8 mcode); // kg/m^3, 0 if not found
F32 getFriction(U8 mcode); // physics values
F32 getRestitution(U8 mcode); // physics values
F32 getHPMod(U8 mcode);
F32 getDamageMod(U8 mcode);
F32 getEPMod(U8 mcode);
bool isCollisionSound(const LLUUID &uuid);
LLUUID getCollisionSoundUUID(U8 mcode, U8 mcode2);
LLUUID getSlidingSoundUUID(U8 mcode, U8 mcode2);
LLUUID getRollingSoundUUID(U8 mcode, U8 mcode2);
LLUUID getShatterSoundUUID(U8 mcode); // LLUUID::null if not found
LLUUID getGroundCollisionSoundUUID(U8 mcode);
LLUUID getGroundSlidingSoundUUID(U8 mcode);
LLUUID getGroundRollingSoundUUID(U8 mcode);
LLUUID getCollisionParticleUUID(U8 mcode, U8 mcode2);
LLUUID getGroundCollisionParticleUUID(U8 mcode);
static LLMaterialTable basic;
};
class LLMaterialInfo
{
public:
U8 mMCode;
std::string mName;
LLUUID mDefaultTextureID;
LLUUID mShatterSoundID;
F32 mDensity; // kg/m^3
F32 mFriction;
F32 mRestitution;
// damage and energy constants
F32 mHPModifier; // modifier on mass based HP total
F32 mDamageModifier; // modifier on KE based damage
F32 mEPModifier; // modifier on mass based EP total
LLMaterialInfo(U8 mcode, const std::string& name, const LLUUID &uuid)
{
init(mcode,name,uuid);
};
void init(U8 mcode, const std::string& name, const LLUUID &uuid)
{
mDensity = 1000.f; // default to 1000.0 (water)
mFriction = LLMaterialTable::DEFAULT_FRICTION;
mRestitution = LLMaterialTable::DEFAULT_RESTITUTION;
mHPModifier = 1.f;
mDamageModifier = 1.f;
mEPModifier = 1.f;
mMCode = mcode;
mName = name;
mDefaultTextureID = uuid;
};
~LLMaterialInfo()
{
};
};
#endif
+595
View File
@@ -0,0 +1,595 @@
/**
* @file llmediaentry.cpp
* @brief This is a single instance of media data related to the face of a prim
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "linden_common.h"
#include "llmediaentry.h"
#include "lllslconstants.h"
#include "llregex.h"
// LLSD key defines
// DO NOT REORDER OR REMOVE THESE!
// Some LLSD keys. Do not change!
#define MEDIA_ALT_IMAGE_ENABLE_KEY_STR "alt_image_enable"
#define MEDIA_CONTROLS_KEY_STR "controls"
#define MEDIA_CURRENT_URL_KEY_STR "current_url"
#define MEDIA_HOME_URL_KEY_STR "home_url"
#define MEDIA_AUTO_LOOP_KEY_STR "auto_loop"
#define MEDIA_AUTO_PLAY_KEY_STR "auto_play"
#define MEDIA_AUTO_SCALE_KEY_STR "auto_scale"
#define MEDIA_AUTO_ZOOM_KEY_STR "auto_zoom"
#define MEDIA_FIRST_CLICK_INTERACT_KEY_STR "first_click_interact"
#define MEDIA_WIDTH_PIXELS_KEY_STR "width_pixels"
#define MEDIA_HEIGHT_PIXELS_KEY_STR "height_pixels"
// "security" fields
#define MEDIA_WHITELIST_ENABLE_KEY_STR "whitelist_enable"
#define MEDIA_WHITELIST_KEY_STR "whitelist"
// "permissions" fields
#define MEDIA_PERMS_INTERACT_KEY_STR "perms_interact"
#define MEDIA_PERMS_CONTROL_KEY_STR "perms_control"
// "general" fields
const char* LLMediaEntry::ALT_IMAGE_ENABLE_KEY = MEDIA_ALT_IMAGE_ENABLE_KEY_STR;
const char* LLMediaEntry::CONTROLS_KEY = MEDIA_CONTROLS_KEY_STR;
const char* LLMediaEntry::CURRENT_URL_KEY = MEDIA_CURRENT_URL_KEY_STR;
const char* LLMediaEntry::HOME_URL_KEY = MEDIA_HOME_URL_KEY_STR;
const char* LLMediaEntry::AUTO_LOOP_KEY = MEDIA_AUTO_LOOP_KEY_STR;
const char* LLMediaEntry::AUTO_PLAY_KEY = MEDIA_AUTO_PLAY_KEY_STR;
const char* LLMediaEntry::AUTO_SCALE_KEY = MEDIA_AUTO_SCALE_KEY_STR;
const char* LLMediaEntry::AUTO_ZOOM_KEY = MEDIA_AUTO_ZOOM_KEY_STR;
const char* LLMediaEntry::FIRST_CLICK_INTERACT_KEY = MEDIA_FIRST_CLICK_INTERACT_KEY_STR;
const char* LLMediaEntry::WIDTH_PIXELS_KEY = MEDIA_WIDTH_PIXELS_KEY_STR;
const char* LLMediaEntry::HEIGHT_PIXELS_KEY = MEDIA_HEIGHT_PIXELS_KEY_STR;
// "security" fields
const char* LLMediaEntry::WHITELIST_ENABLE_KEY = MEDIA_WHITELIST_ENABLE_KEY_STR;
const char* LLMediaEntry::WHITELIST_KEY = MEDIA_WHITELIST_KEY_STR;
// "permissions" fields
const char* LLMediaEntry::PERMS_INTERACT_KEY = MEDIA_PERMS_INTERACT_KEY_STR;
const char* LLMediaEntry::PERMS_CONTROL_KEY = MEDIA_PERMS_CONTROL_KEY_STR;
#define DEFAULT_URL_PREFIX "http://"
// Constructor(s)
LLMediaEntry::LLMediaEntry() :
mAltImageEnable(false),
mControls(STANDARD),
mCurrentURL(""),
mHomeURL(""),
mAutoLoop(false),
mAutoPlay(false),
mAutoScale(false),
mAutoZoom(false),
mFirstClickInteract(false),
mWidthPixels(0),
mHeightPixels(0),
mWhiteListEnable(false),
// mWhiteList
mPermsInteract(PERM_ALL),
mPermsControl(PERM_ALL),
mMediaIDp(NULL)
{
}
LLMediaEntry::LLMediaEntry(const LLMediaEntry &rhs) :
mMediaIDp(NULL)
{
// "general" fields
mAltImageEnable = rhs.mAltImageEnable;
mControls = rhs.mControls;
mCurrentURL = rhs.mCurrentURL;
mHomeURL = rhs.mHomeURL;
mAutoLoop = rhs.mAutoLoop;
mAutoPlay = rhs.mAutoPlay;
mAutoScale = rhs.mAutoScale;
mAutoZoom = rhs.mAutoZoom;
mFirstClickInteract = rhs.mFirstClickInteract;
mWidthPixels = rhs.mWidthPixels;
mHeightPixels = rhs.mHeightPixels;
// "security" fields
mWhiteListEnable = rhs.mWhiteListEnable;
mWhiteList = rhs.mWhiteList;
// "permissions" fields
mPermsInteract = rhs.mPermsInteract;
mPermsControl = rhs.mPermsControl;
}
LLMediaEntry::~LLMediaEntry()
{
if (NULL != mMediaIDp)
{
delete mMediaIDp;
}
}
LLSD LLMediaEntry::asLLSD() const
{
LLSD sd;
asLLSD(sd);
return sd;
}
//
// LLSD functions
//
void LLMediaEntry::asLLSD(LLSD& sd) const
{
// "general" fields
sd[ALT_IMAGE_ENABLE_KEY] = mAltImageEnable;
sd[CONTROLS_KEY] = (LLSD::Integer)mControls;
sd[CURRENT_URL_KEY] = mCurrentURL;
sd[HOME_URL_KEY] = mHomeURL;
sd[AUTO_LOOP_KEY] = mAutoLoop;
sd[AUTO_PLAY_KEY] = mAutoPlay;
sd[AUTO_SCALE_KEY] = mAutoScale;
sd[AUTO_ZOOM_KEY] = mAutoZoom;
sd[FIRST_CLICK_INTERACT_KEY] = mFirstClickInteract;
sd[WIDTH_PIXELS_KEY] = mWidthPixels;
sd[HEIGHT_PIXELS_KEY] = mHeightPixels;
// "security" fields
sd[WHITELIST_ENABLE_KEY] = mWhiteListEnable;
sd.erase(WHITELIST_KEY);
for (U32 i=0; i<mWhiteList.size(); i++)
{
sd[WHITELIST_KEY].append(mWhiteList[i]);
}
// "permissions" fields
sd[PERMS_INTERACT_KEY] = mPermsInteract;
sd[PERMS_CONTROL_KEY] = mPermsControl;
}
// static
bool LLMediaEntry::checkLLSD(const LLSD& sd)
{
if (sd.isUndefined()) return true;
LLMediaEntry temp;
return temp.fromLLSDInternal(sd, true);
}
void LLMediaEntry::fromLLSD(const LLSD& sd)
{
(void)fromLLSDInternal(sd, true);
}
void LLMediaEntry::mergeFromLLSD(const LLSD& sd)
{
(void)fromLLSDInternal(sd, false);
}
// *NOTE: returns true if NO failures to set occurred, false otherwise.
// However, be aware that if a failure to set does occur, it does
// not stop setting fields from the LLSD!
bool LLMediaEntry::fromLLSDInternal(const LLSD& sd, bool overwrite)
{
// *HACK: we sort of cheat here and assume that status is a
// bit field. We "or" into status and instead of returning
// it, we return whether it finishes off as LSL_STATUS_OK or not.
U32 status = LSL_STATUS_OK;
// "general" fields
if ( overwrite || sd.has(ALT_IMAGE_ENABLE_KEY) )
{
status |= setAltImageEnable( sd[ALT_IMAGE_ENABLE_KEY] );
}
if ( overwrite || sd.has(CONTROLS_KEY) )
{
status |= setControls( (MediaControls)(LLSD::Integer)sd[CONTROLS_KEY] );
}
if ( overwrite || sd.has(CURRENT_URL_KEY) )
{
// Don't check whitelist
status |= setCurrentURLInternal( sd[CURRENT_URL_KEY], false );
}
if ( overwrite || sd.has(HOME_URL_KEY) )
{
status |= setHomeURL( sd[HOME_URL_KEY] );
}
if ( overwrite || sd.has(AUTO_LOOP_KEY) )
{
status |= setAutoLoop( sd[AUTO_LOOP_KEY] );
}
if ( overwrite || sd.has(AUTO_PLAY_KEY) )
{
status |= setAutoPlay( sd[AUTO_PLAY_KEY] );
}
if ( overwrite || sd.has(AUTO_SCALE_KEY) )
{
status |= setAutoScale( sd[AUTO_SCALE_KEY] );
}
if ( overwrite || sd.has(AUTO_ZOOM_KEY) )
{
status |= setAutoZoom( sd[AUTO_ZOOM_KEY] );
}
if ( overwrite || sd.has(FIRST_CLICK_INTERACT_KEY) )
{
status |= setFirstClickInteract( sd[FIRST_CLICK_INTERACT_KEY] );
}
if ( overwrite || sd.has(WIDTH_PIXELS_KEY) )
{
status |= setWidthPixels( (LLSD::Integer)sd[WIDTH_PIXELS_KEY] );
}
if ( overwrite || sd.has(HEIGHT_PIXELS_KEY) )
{
status |= setHeightPixels( (LLSD::Integer)sd[HEIGHT_PIXELS_KEY] );
}
// "security" fields
if ( overwrite || sd.has(WHITELIST_ENABLE_KEY) )
{
status |= setWhiteListEnable( sd[WHITELIST_ENABLE_KEY] );
}
if ( overwrite || sd.has(WHITELIST_KEY) )
{
status |= setWhiteList( sd[WHITELIST_KEY] );
}
// "permissions" fields
if ( overwrite || sd.has(PERMS_INTERACT_KEY) )
{
status |= setPermsInteract( 0xff & (LLSD::Integer)sd[PERMS_INTERACT_KEY] );
}
if ( overwrite || sd.has(PERMS_CONTROL_KEY) )
{
status |= setPermsControl( 0xff & (LLSD::Integer)sd[PERMS_CONTROL_KEY] );
}
return LSL_STATUS_OK == status;
}
LLMediaEntry& LLMediaEntry::operator=(const LLMediaEntry &rhs)
{
if (this != &rhs)
{
// "general" fields
mAltImageEnable = rhs.mAltImageEnable;
mControls = rhs.mControls;
mCurrentURL = rhs.mCurrentURL;
mHomeURL = rhs.mHomeURL;
mAutoLoop = rhs.mAutoLoop;
mAutoPlay = rhs.mAutoPlay;
mAutoScale = rhs.mAutoScale;
mAutoZoom = rhs.mAutoZoom;
mFirstClickInteract = rhs.mFirstClickInteract;
mWidthPixels = rhs.mWidthPixels;
mHeightPixels = rhs.mHeightPixels;
// "security" fields
mWhiteListEnable = rhs.mWhiteListEnable;
mWhiteList = rhs.mWhiteList;
// "permissions" fields
mPermsInteract = rhs.mPermsInteract;
mPermsControl = rhs.mPermsControl;
}
return *this;
}
bool LLMediaEntry::operator==(const LLMediaEntry &rhs) const
{
return (
// "general" fields
mAltImageEnable == rhs.mAltImageEnable &&
mControls == rhs.mControls &&
mCurrentURL == rhs.mCurrentURL &&
mHomeURL == rhs.mHomeURL &&
mAutoLoop == rhs.mAutoLoop &&
mAutoPlay == rhs.mAutoPlay &&
mAutoScale == rhs.mAutoScale &&
mAutoZoom == rhs.mAutoZoom &&
mFirstClickInteract == rhs.mFirstClickInteract &&
mWidthPixels == rhs.mWidthPixels &&
mHeightPixels == rhs.mHeightPixels &&
// "security" fields
mWhiteListEnable == rhs.mWhiteListEnable &&
mWhiteList == rhs.mWhiteList &&
// "permissions" fields
mPermsInteract == rhs.mPermsInteract &&
mPermsControl == rhs.mPermsControl
);
}
bool LLMediaEntry::operator!=(const LLMediaEntry &rhs) const
{
return (
// "general" fields
mAltImageEnable != rhs.mAltImageEnable ||
mControls != rhs.mControls ||
mCurrentURL != rhs.mCurrentURL ||
mHomeURL != rhs.mHomeURL ||
mAutoLoop != rhs.mAutoLoop ||
mAutoPlay != rhs.mAutoPlay ||
mAutoScale != rhs.mAutoScale ||
mAutoZoom != rhs.mAutoZoom ||
mFirstClickInteract != rhs.mFirstClickInteract ||
mWidthPixels != rhs.mWidthPixels ||
mHeightPixels != rhs.mHeightPixels ||
// "security" fields
mWhiteListEnable != rhs.mWhiteListEnable ||
mWhiteList != rhs.mWhiteList ||
// "permissions" fields
mPermsInteract != rhs.mPermsInteract ||
mPermsControl != rhs.mPermsControl
);
}
U32 LLMediaEntry::setWhiteList( const std::vector<std::string> &whitelist )
{
// *NOTE: This code is VERY similar to the setWhitelist below.
// IF YOU CHANGE THIS IMPLEMENTATION, BE SURE TO CHANGE THE OTHER!
size_t size = 0;
U32 count = 0;
// First count to make sure the size constraint is not violated
std::vector<std::string>::const_iterator iter = whitelist.begin();
std::vector<std::string>::const_iterator end = whitelist.end();
for ( ; iter < end; ++iter)
{
const std::string &entry = (*iter);
size += entry.length() + 1; // Include one for \0
count ++;
if (size > MAX_WHITELIST_SIZE || count > MAX_WHITELIST_COUNT)
{
return LSL_STATUS_BOUNDS_ERROR;
}
}
// Next clear the vector
mWhiteList.clear();
// Then re-iterate and copy entries
iter = whitelist.begin();
for ( ; iter < end; ++iter)
{
const std::string &entry = (*iter);
mWhiteList.push_back(entry);
}
return LSL_STATUS_OK;
}
U32 LLMediaEntry::setWhiteList( const LLSD &whitelist )
{
// If whitelist is undef, the whitelist is cleared
if (whitelist.isUndefined())
{
mWhiteList.clear();
return LSL_STATUS_OK;
}
// However, if the whitelist is an empty array, erase it.
if (whitelist.isArray())
{
// *NOTE: This code is VERY similar to the setWhitelist above.
// IF YOU CHANGE THIS IMPLEMENTATION, BE SURE TO CHANGE THE OTHER!
size_t size = 0;
U32 count = 0;
// First check to make sure the size and count constraints are not violated
LLSD::array_const_iterator iter = whitelist.beginArray();
LLSD::array_const_iterator end = whitelist.endArray();
for ( ; iter < end; ++iter)
{
const std::string &entry = (*iter).asString();
size += entry.length() + 1; // Include one for \0
count ++;
if (size > MAX_WHITELIST_SIZE || count > MAX_WHITELIST_COUNT)
{
return LSL_STATUS_BOUNDS_ERROR;
}
}
// Next clear the vector
mWhiteList.clear();
// Then re-iterate and copy entries
iter = whitelist.beginArray();
for ( ; iter < end; ++iter)
{
const std::string &entry = (*iter).asString();
mWhiteList.push_back(entry);
}
return LSL_STATUS_OK;
}
else
{
return LSL_STATUS_MALFORMED_PARAMS;
}
}
static void prefix_with(std::string &str, const char *chars, const char *prefix)
{
// Given string 'str', prefix all instances of any character in 'chars'
// with 'prefix'
size_t found = str.find_first_of(chars);
size_t prefix_len = strlen(prefix);
while (found != std::string::npos)
{
str.insert(found, prefix, prefix_len);
found = str.find_first_of(chars, found+prefix_len+1);
}
}
static bool pattern_match(const std::string &candidate_str, const std::string &pattern)
{
// If the pattern is empty, it matches
if (pattern.empty()) return true;
// 'pattern' is a glob pattern, we only accept '*' chars
// copy it
std::string expression = pattern;
// Escape perl's regexp chars with a backslash, except all "*" chars
prefix_with(expression, ".[{()\\+?|^$", "\\");
prefix_with(expression, "*", ".");
// case-insensitive matching:
boost::regex regexp(expression, boost::regex::perl|boost::regex::icase);
return ll_regex_match(candidate_str, regexp);
}
bool LLMediaEntry::checkCandidateUrl(const std::string& url) const
{
if (getWhiteListEnable())
{
return checkUrlAgainstWhitelist(url, getWhiteList());
}
else
{
return true;
}
}
// static
bool LLMediaEntry::checkUrlAgainstWhitelist(const std::string& url,
const std::vector<std::string> &whitelist)
{
bool passes = true;
// *NOTE: no entries? Don't check
if (whitelist.size() > 0)
{
passes = false;
// Case insensitive: the reason why we toUpper both this and the
// filter
std::string candidate_url = url;
// Use lluri to see if there is a path part in the candidate URL. No path? Assume "/"
LLURI candidate_uri(candidate_url);
std::vector<std::string>::const_iterator iter = whitelist.begin();
std::vector<std::string>::const_iterator end = whitelist.end();
for ( ; iter < end; ++iter )
{
std::string filter = *iter;
LLURI filter_uri(filter);
bool scheme_passes = pattern_match( candidate_uri.scheme(), filter_uri.scheme() );
if (filter_uri.scheme().empty())
{
filter_uri = LLURI(DEFAULT_URL_PREFIX + filter);
}
bool authority_passes = pattern_match( candidate_uri.authority(), filter_uri.authority() );
bool path_passes = pattern_match( candidate_uri.escapedPath(), filter_uri.escapedPath() );
if (scheme_passes && authority_passes && path_passes)
{
passes = true;
break;
}
}
}
return passes;
}
U32 LLMediaEntry::setStringFieldWithLimit( std::string &field, const std::string &value, U32 limit )
{
if ( value.length() > limit )
{
return LSL_STATUS_BOUNDS_ERROR;
}
else
{
field = value;
return LSL_STATUS_OK;
}
}
U32 LLMediaEntry::setControls(LLMediaEntry::MediaControls controls)
{
if (controls == STANDARD ||
controls == MINI)
{
mControls = controls;
return LSL_STATUS_OK;
}
return LSL_STATUS_BOUNDS_ERROR;
}
U32 LLMediaEntry::setPermsInteract( U8 val )
{
mPermsInteract = val & PERM_MASK;
return LSL_STATUS_OK;
}
U32 LLMediaEntry::setPermsControl( U8 val )
{
mPermsControl = val & PERM_MASK;
return LSL_STATUS_OK;
}
U32 LLMediaEntry::setCurrentURL(const std::string& current_url)
{
return setCurrentURLInternal( current_url, true );
}
U32 LLMediaEntry::setCurrentURLInternal(const std::string& current_url, bool check_whitelist)
{
if ( ! check_whitelist || checkCandidateUrl(current_url))
{
return setStringFieldWithLimit( mCurrentURL, current_url, MAX_URL_LENGTH );
}
else
{
return LSL_STATUS_WHITELIST_FAILED;
}
}
U32 LLMediaEntry::setHomeURL(const std::string& home_url)
{
return setStringFieldWithLimit( mHomeURL, home_url, MAX_URL_LENGTH );
}
U32 LLMediaEntry::setWidthPixels(U16 width)
{
if (width > MAX_WIDTH_PIXELS) return LSL_STATUS_BOUNDS_ERROR;
mWidthPixels = width;
return LSL_STATUS_OK;
}
U32 LLMediaEntry::setHeightPixels(U16 height)
{
if (height > MAX_HEIGHT_PIXELS) return LSL_STATUS_BOUNDS_ERROR;
mHeightPixels = height;
return LSL_STATUS_OK;
}
const LLUUID &LLMediaEntry::getMediaID() const
{
// Lazily generate media ID
if (NULL == mMediaIDp)
{
mMediaIDp = new LLUUID();
mMediaIDp->generate();
}
return *mMediaIDp;
}
+222
View File
@@ -0,0 +1,222 @@
/**
* @file llmediaentry.h
* @brief This is a single instance of media data related to the face of a prim
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#ifndef LL_LLMEDIAENTRY_H
#define LL_LLMEDIAENTRY_H
#include "llsd.h"
#include "llstring.h"
// For return values of set*
#include "lllslconstants.h"
class LLMediaEntry
{
public:
enum MediaControls {
STANDARD = 0,
MINI
};
// Constructors
LLMediaEntry();
LLMediaEntry(const LLMediaEntry &rhs);
LLMediaEntry &operator=(const LLMediaEntry &rhs);
virtual ~LLMediaEntry();
bool operator==(const LLMediaEntry &rhs) const;
bool operator!=(const LLMediaEntry &rhs) const;
// Render as LLSD
LLSD asLLSD() const;
void asLLSD(LLSD& sd) const;
operator LLSD() const { return asLLSD(); }
// Returns false iff the given LLSD contains fields that violate any bounds
// limits.
static bool checkLLSD(const LLSD& sd);
// This doesn't merge, it overwrites the data, so will use
// LLSD defaults if need be. Note: does not check limits!
// Use checkLLSD() above first to ensure the LLSD is valid.
void fromLLSD(const LLSD& sd);
// This merges data from the incoming LLSD into our fields.
// Note that it also does NOT check limits! Use checkLLSD() above first.
void mergeFromLLSD(const LLSD& sd);
// "general" fields
bool getAltImageEnable() const { return mAltImageEnable; }
MediaControls getControls() const { return mControls; }
std::string getCurrentURL() const { return mCurrentURL; }
std::string getHomeURL() const { return mHomeURL; }
bool getAutoLoop() const { return mAutoLoop; }
bool getAutoPlay() const { return mAutoPlay; }
bool getAutoScale() const { return mAutoScale; }
bool getAutoZoom() const { return mAutoZoom; }
bool getFirstClickInteract() const { return mFirstClickInteract; }
U16 getWidthPixels() const { return mWidthPixels; }
U16 getHeightPixels() const { return mHeightPixels; }
// "security" fields
bool getWhiteListEnable() const { return mWhiteListEnable; }
const std::vector<std::string> &getWhiteList() const { return mWhiteList; }
// "permissions" fields
U8 getPermsInteract() const { return mPermsInteract; }
U8 getPermsControl() const { return mPermsControl; }
// Setters. Those that return a U32 return a status error code
// See lllslconstants.h
// "general" fields
U32 setAltImageEnable(bool alt_image_enable) { mAltImageEnable = alt_image_enable; return LSL_STATUS_OK; }
U32 setControls(MediaControls controls);
U32 setCurrentURL(const std::string& current_url);
U32 setHomeURL(const std::string& home_url);
U32 setAutoLoop(bool auto_loop) { mAutoLoop = auto_loop; return LSL_STATUS_OK; }
U32 setAutoPlay(bool auto_play) { mAutoPlay = auto_play; return LSL_STATUS_OK; }
U32 setAutoScale(bool auto_scale) { mAutoScale = auto_scale; return LSL_STATUS_OK; }
U32 setAutoZoom(bool auto_zoom) { mAutoZoom = auto_zoom; return LSL_STATUS_OK; }
U32 setFirstClickInteract(bool first_click) { mFirstClickInteract = first_click; return LSL_STATUS_OK; }
U32 setWidthPixels(U16 width);
U32 setHeightPixels(U16 height);
// "security" fields
U32 setWhiteListEnable( bool whitelist_enable ) { mWhiteListEnable = whitelist_enable; return LSL_STATUS_OK; }
U32 setWhiteList( const std::vector<std::string> &whitelist );
U32 setWhiteList( const LLSD &whitelist ); // takes an LLSD array
// "permissions" fields
U32 setPermsInteract( U8 val );
U32 setPermsControl( U8 val );
const LLUUID& getMediaID() const;
// Helper function to check a candidate URL against the whitelist
// Returns true iff candidate URL passes (or if there is no whitelist), false otherwise
bool checkCandidateUrl(const std::string& url) const;
public:
// Static function to check a URL against a whitelist
// Returns true iff url passes the given whitelist
static bool checkUrlAgainstWhitelist(const std::string &url,
const std::vector<std::string> &whitelist);
public:
// LLSD key defines
// "general" fields
static const char* ALT_IMAGE_ENABLE_KEY;
static const char* CONTROLS_KEY;
static const char* CURRENT_URL_KEY;
static const char* HOME_URL_KEY;
static const char* AUTO_LOOP_KEY;
static const char* AUTO_PLAY_KEY;
static const char* AUTO_SCALE_KEY;
static const char* AUTO_ZOOM_KEY;
static const char* FIRST_CLICK_INTERACT_KEY;
static const char* WIDTH_PIXELS_KEY;
static const char* HEIGHT_PIXELS_KEY;
// "security" fields
static const char* WHITELIST_ENABLE_KEY;
static const char* WHITELIST_KEY;
// "permissions" fields
static const char* PERMS_INTERACT_KEY;
static const char* PERMS_CONTROL_KEY;
// Field enumerations & constants
// *NOTE: DO NOT change the order of these, and do not insert values
// in the middle!
// Add values to the end, and make sure to change PARAM_MAX_ID!
enum Fields {
ALT_IMAGE_ENABLE_ID = 0,
CONTROLS_ID = 1,
CURRENT_URL_ID = 2,
HOME_URL_ID = 3,
AUTO_LOOP_ID = 4,
AUTO_PLAY_ID = 5,
AUTO_SCALE_ID = 6,
AUTO_ZOOM_ID = 7,
FIRST_CLICK_INTERACT_ID = 8,
WIDTH_PIXELS_ID = 9,
HEIGHT_PIXELS_ID = 10,
WHITELIST_ENABLE_ID = 11,
WHITELIST_ID = 12,
PERMS_INTERACT_ID = 13,
PERMS_CONTROL_ID = 14,
PARAM_MAX_ID = PERMS_CONTROL_ID
};
// "permissions" values
// (e.g. (PERM_OWNER | PERM_GROUP) sets permissions on for OWNER and GROUP
static const U8 PERM_NONE = 0x0;
static const U8 PERM_OWNER = 0x1;
static const U8 PERM_GROUP = 0x2;
static const U8 PERM_ANYONE = 0x4;
static const U8 PERM_ALL = PERM_OWNER|PERM_GROUP|PERM_ANYONE;
static const U8 PERM_MASK = PERM_OWNER|PERM_GROUP|PERM_ANYONE;
// Limits (in bytes)
static const U32 MAX_URL_LENGTH = 1024;
static const U32 MAX_WHITELIST_SIZE = 1024;
static const U32 MAX_WHITELIST_COUNT = 64;
static const U16 MAX_WIDTH_PIXELS = 2048;
static const U16 MAX_HEIGHT_PIXELS = 2048;
private:
U32 setStringFieldWithLimit( std::string &field, const std::string &value, U32 limit );
U32 setCurrentURLInternal( const std::string &url, bool check_whitelist);
bool fromLLSDInternal(const LLSD &sd, bool overwrite);
private:
// "general" fields
bool mAltImageEnable;
MediaControls mControls;
std::string mCurrentURL;
std::string mHomeURL;
bool mAutoLoop;
bool mAutoPlay;
bool mAutoScale;
bool mAutoZoom;
bool mFirstClickInteract;
U16 mWidthPixels;
U16 mHeightPixels;
// "security" fields
bool mWhiteListEnable;
std::vector<std::string> mWhiteList;
// "permissions" fields
U8 mPermsInteract;
U8 mPermsControl;
mutable LLUUID *mMediaIDp; // temporary id assigned to media on the viewer
};
#endif
File diff suppressed because it is too large Load Diff
+440
View File
@@ -0,0 +1,440 @@
/**
* @file llmodel.h
* @brief Model handling class definitions
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#ifndef LL_LLMODEL_H
#define LL_LLMODEL_H
#include "llpointer.h"
#include "llvolume.h"
#include "v4math.h"
#include "m4math.h"
#include <queue>
#include <boost/align/aligned_allocator.hpp>
#include "lljoint.h"
class daeElement;
class domMesh;
#define MAX_MODEL_FACES 8
LL_ALIGN_PREFIX(16)
class LLMeshSkinInfo : public LLRefCount
{
LL_ALIGN_NEW
public:
LLMeshSkinInfo();
LLMeshSkinInfo(LLSD& data);
LLMeshSkinInfo(const LLUUID& mesh_id, LLSD& data);
void fromLLSD(LLSD& data);
LLSD asLLSD(bool include_joints, bool lock_scale_if_joint_position) const;
void updateHash();
U32 sizeBytes() const;
LLUUID mMeshID;
std::vector<std::string> mJointNames;
mutable std::vector<S32> mJointNums;
typedef std::vector<LLMatrix4a> matrix_list_t;
matrix_list_t mInvBindMatrix;
// bones/joints position overrides
matrix_list_t mAlternateBindMatrix;
// cached multiply of mBindShapeMatrix and mInvBindMatrix
matrix_list_t mBindPoseMatrix;
LL_ALIGN_16(LLMatrix4a mBindShapeMatrix);
float mPelvisOffset;
bool mLockScaleIfJointPosition;
bool mInvalidJointsScrubbed;
bool mJointNumsInitialized;
U64 mHash = 0;
} LL_ALIGN_POSTFIX(16);
LL_ALIGN_PREFIX(16)
class LLModel : public LLVolume
{
LL_ALIGN_NEW
public:
enum
{
LOD_IMPOSTOR = 0,
LOD_LOW,
LOD_MEDIUM,
LOD_HIGH,
LOD_PHYSICS,
NUM_LODS
};
enum EModelStatus
{
NO_ERRORS = 0,
VERTEX_NUMBER_OVERFLOW, //vertex number is >= 65535.
BAD_ELEMENT,
INVALID_STATUS
} ;
//convex_hull_decomposition is a vector of convex hulls
//each convex hull is a set of points
typedef std::vector<std::vector<LLVector3> > convex_hull_decomposition;
typedef std::vector<LLVector3> hull;
class PhysicsMesh
{
public:
std::vector<LLVector3> mPositions;
std::vector<LLVector3> mNormals;
~PhysicsMesh() {}
void clear()
{
mPositions.clear();
mNormals.clear();
}
bool empty() const
{
return mPositions.empty();
}
U32 sizeBytes() const
{
U32 res = sizeof(std::vector<LLVector3>) * 2;
res += sizeof(LLVector3) * static_cast<U32>(mPositions.size());
res += sizeof(LLVector3) * static_cast<U32>(mNormals.size());
return res;
}
};
class Decomposition
{
public:
Decomposition() { }
Decomposition(LLSD& data);
~Decomposition() { }
void fromLLSD(LLSD& data);
LLSD asLLSD() const;
bool hasHullList() const;
U32 sizeBytes() const;
void merge(const Decomposition* rhs);
LLUUID mMeshID;
LLModel::convex_hull_decomposition mHull;
LLModel::hull mBaseHull;
std::vector<LLModel::PhysicsMesh> mMesh;
LLModel::PhysicsMesh mBaseHullMesh;
LLModel::PhysicsMesh mPhysicsShapeMesh;
};
LLModel(const LLVolumeParams& params, F32 detail);
~LLModel();
bool loadModel(std::istream& is);
bool loadSkinInfo(LLSD& header, std::istream& is);
bool loadDecomposition(LLSD& header, std::istream& is);
static LLSD writeModel(
std::ostream& ostr,
LLModel* physics,
LLModel* high,
LLModel* medium,
LLModel* low,
LLModel* imposotr,
const LLModel::Decomposition& decomp,
bool upload_skin,
bool upload_joints,
bool lock_scale_if_joint_position,
bool nowrite = false,
bool as_slm = false,
int submodel_id = 0);
static LLSD writeModelToStream(
std::ostream& ostr,
LLSD& mdl,
bool nowrite = false, bool as_slm = false);
void ClearFacesAndMaterials() { mVolumeFaces.clear(); mMaterialList.clear(); }
std::string getName() const;
EModelStatus getStatus() const {return mStatus;}
static std::string getStatusString(U32 status) ;
void setNumVolumeFaces(S32 count);
void setVolumeFaceData(
S32 f,
LLStrider<LLVector3> pos,
LLStrider<LLVector3> norm,
LLStrider<LLVector2> tc,
LLStrider<U16> ind,
U32 num_verts,
U32 num_indices);
void generateNormals(F32 angle_cutoff);
void addFace(const LLVolumeFace& face);
void sortVolumeFacesByMaterialName();
void normalizeVolumeFaces();
void trimVolumeFacesToSize(U32 new_count = LL_SCULPT_MESH_MAX_FACES, LLVolume::face_list_t* remainder = NULL);
void remapVolumeFaces();
void optimizeVolumeFaces();
void offsetMesh( const LLVector3& pivotPoint );
void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out) const;
LLVector3 getTransformedCenter(const LLMatrix4& mat);
//reorder face list based on mMaterialList in this and reference so
//order matches that of reference (material ordering touchup)
// bool matchMaterialOrder(LLModel* ref, int& refFaceCnt, int& modelFaceCnt ); // <FS:Beq/> FIRE-30965 error handling improvements (function relocated)
bool isMaterialListSubset( LLModel* ref );
bool needToAddFaces( LLModel* ref, int& refFaceCnt, int& modelFaceCnt );
typedef std::vector<std::string> material_list;
material_list mMaterialList;
material_list& getMaterialList() { return mMaterialList; }
//data used for skin weights
class JointWeight
{
public:
S32 mJointIdx;
F32 mWeight;
JointWeight()
{
mJointIdx = 0;
mWeight = 0.f;
}
JointWeight(S32 idx, F32 weight)
: mJointIdx(idx), mWeight(weight)
{
}
bool operator<(const JointWeight& rhs) const
{
if (mWeight == rhs.mWeight)
{
return mJointIdx < rhs.mJointIdx;
}
return mWeight < rhs.mWeight;
}
};
struct CompareWeightGreater
{
bool operator()(const JointWeight& lhs, const JointWeight& rhs)
{
return rhs < lhs; // strongest = first
}
};
//Are the doubles the same w/in epsilon specified tolerance
bool areEqual( double a, double b )
{
const float epsilon = 1e-5f;
return fabs(a - b) < epsilon;
}
//Make sure that we return false for any values that are within the tolerance for equivalence
bool jointPositionalLookup( const LLVector3& a, const LLVector3& b )
{
const float epsilon = 1e-5f;
return (a - b).length() < epsilon;
}
//copy of position array for this model -- mPosition[idx].mV[X,Y,Z]
std::vector<LLVector3> mPosition;
//map of positions to skin weights --- mSkinWeights[pos].mV[0..4] == <joint_index>.<weight>
//joint_index corresponds to mJointList
typedef std::vector<JointWeight> weight_list;
typedef std::map<LLVector3, weight_list > weight_map;
weight_map mSkinWeights;
//get list of weight influences closest to given position
weight_list& getJointInfluences(const LLVector3& pos);
LLMeshSkinInfo mSkinInfo;
std::string mRequestedLabel; // name requested in UI, if any.
std::string mLabel; // name computed from dae.
LLVector3 mNormalizedScale;
LLVector3 mNormalizedTranslation;
float mPelvisOffset;
// convex hull decomposition
S32 mDecompID;
void setConvexHullDecomposition(
const convex_hull_decomposition& decomp);
void updateHullCenters();
LLVector3 mCenterOfHullCenters;
std::vector<LLVector3> mHullCenter;
U32 mHullPoints;
//ID for storing this model in a .slm file
S32 mLocalID;
Decomposition mPhysics;
EModelStatus mStatus ;
// A model/object can only have 8 faces, spillover faces will
// be moved to new model/object and assigned a submodel id.
int mSubmodelID;
} LL_ALIGN_POSTFIX(16);
typedef std::vector<LLPointer<LLModel> > model_list;
typedef std::queue<LLPointer<LLModel> > model_queue;
class LLModelMaterialBase
{
public:
std::string mDiffuseMapFilename;
std::string mDiffuseMapLabel;
std::string mBinding;
LLColor4 mDiffuseColor;
bool mFullbright;
LLModelMaterialBase()
: mFullbright(false)
{
mDiffuseColor.set(1,1,1,1);
}
};
class LLImportMaterial : public LLModelMaterialBase
{
public:
friend class LLMeshUploadThread;
friend class LLModelPreview;
bool operator<(const LLImportMaterial &params) const;
LLImportMaterial() : LLModelMaterialBase()
{
mDiffuseColor.set(1,1,1,1);
}
LLImportMaterial(LLSD& data);
virtual ~LLImportMaterial();
LLSD asLLSD();
const LLUUID& getDiffuseMap() const { return mDiffuseMapID; }
void setDiffuseMap(const LLUUID& texId) { mDiffuseMapID = texId; }
protected:
LLUUID mDiffuseMapID;
void* mOpaqueData{ nullptr }; // allow refs to viewer/platform-specific structs for each material
// currently only stores an LLPointer< LLViewerFetchedTexture > > to
// maintain refs to textures associated with each material for free
// ref counting.
};
typedef std::map<std::string, LLImportMaterial> material_map;
class LLModelInstanceBase
{
public:
LLPointer<LLModel> mModel;
LLPointer<LLModel> mLOD[LLModel::NUM_LODS];
LLUUID mMeshID;
LLMatrix4 mTransform;
material_map mMaterial;
LLModelInstanceBase(LLModel* model, const LLMatrix4& transform, const material_map& materials)
: mModel(model), mTransform(transform), mMaterial(materials)
{
}
LLModelInstanceBase()
: mModel(NULL)
{
}
virtual ~LLModelInstanceBase()
{
mModel = NULL;
for (int j = 0; j < LLModel::NUM_LODS; ++j)
{
mLOD[j] = NULL;
}
};
};
typedef std::vector<LLModelInstanceBase> model_instance_list;
class LLModelInstance : public LLModelInstanceBase
{
public:
std::string mLabel;
LLUUID mMeshID;
S32 mLocalMeshID;
LLModelInstance(LLModel* model, const std::string& label, const LLMatrix4& transform, const material_map& materials)
: LLModelInstanceBase(model, transform, materials), mLabel(label)
{
mLocalMeshID = -1;
}
LLModelInstance(LLSD& data);
~LLModelInstance() {}
LLSD asLLSD();
};
#define LL_DEGENERACY_TOLERANCE 1e-7f
inline F32 dot3fpu(const LLVector4a& a, const LLVector4a& b)
{
volatile F32 p0 = a[0] * b[0];
volatile F32 p1 = a[1] * b[1];
volatile F32 p2 = a[2] * b[2];
return p0 + p1 + p2;
}
bool ll_is_degenerate(const LLVector4a& a, const LLVector4a& b, const LLVector4a& c, F32 tolerance = LL_DEGENERACY_TOLERANCE);
bool validate_face(const LLVolumeFace& face);
bool validate_model(const LLModel* mdl);
#endif //LL_LLMODEL_H
+502
View File
@@ -0,0 +1,502 @@
/**
* @file llmodelloader.cpp
* @brief LLModelLoader class implementation
*
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "llmodelloader.h"
#include "llapp.h"
#include "llsdserialize.h"
#include "lljoint.h"
#include "llcallbacklist.h"
#include "llmatrix4a.h"
#include <boost/bind.hpp>
#include "../llxml/llcontrol.h"
std::list<LLModelLoader*> LLModelLoader::sActiveLoaderList;
static void stretch_extents(const LLModel* model, const LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, bool& first_transform)
{
LLVector4a box[] =
{
LLVector4a(-1, 1,-1),
LLVector4a(-1, 1, 1),
LLVector4a(-1,-1,-1),
LLVector4a(-1,-1, 1),
LLVector4a( 1, 1,-1),
LLVector4a( 1, 1, 1),
LLVector4a( 1,-1,-1),
LLVector4a( 1,-1, 1),
};
for (S32 j = 0; j < model->getNumVolumeFaces(); ++j)
{
const LLVolumeFace& face = model->getVolumeFace(j);
LLVector4a center;
center.setAdd(face.mExtents[0], face.mExtents[1]);
center.mul(0.5f);
LLVector4a size;
size.setSub(face.mExtents[1],face.mExtents[0]);
size.mul(0.5f);
for (U32 i = 0; i < 8; i++)
{
LLVector4a t;
t.setMul(size, box[i]);
t.add(center);
LLVector4a v;
mat.affineTransform(t, v);
if (first_transform)
{
first_transform = false;
min = max = v;
}
else
{
update_min_max(min, max, v);
}
}
}
}
void LLModelLoader::stretch_extents(const LLModel* model, const LLMatrix4& mat)
{
LLVector4a mina, maxa;
LLMatrix4a mata;
mata.loadu(mat);
mina.load3(mExtents[0].mV);
maxa.load3(mExtents[1].mV);
::stretch_extents(model, mata, mina, maxa, mFirstTransform);
mExtents[0].set(mina.getF32ptr());
mExtents[1].set(maxa.getF32ptr());
}
//-----------------------------------------------------------------------------
// LLModelLoader
//-----------------------------------------------------------------------------
LLModelLoader::LLModelLoader(
std::string filename,
S32 lod,
load_callback_t load_cb,
joint_lookup_func_t joint_lookup_func,
texture_load_func_t texture_load_func,
state_callback_t state_cb,
void* opaque_userdata,
JointTransformMap& jointTransformMap,
JointNameSet& jointsFromNodes,
JointMap& legalJointNamesMap,
U32 maxJointsPerMesh)
: mJointList( jointTransformMap )
, mJointsFromNode( jointsFromNodes )
, LLThread("Model Loader")
, mFilename(filename)
, mLod(lod)
, mTrySLM(false)
, mFirstTransform(true)
, mNumOfFetchingTextures(0)
, mLoadCallback(load_cb)
, mJointLookupFunc(joint_lookup_func)
, mTextureLoadFunc(texture_load_func)
, mStateCallback(state_cb)
, mOpaqueData(opaque_userdata)
, mRigValidJointUpload(true)
, mLegacyRigFlags(0)
, mNoNormalize(false)
, mNoOptimize(false)
, mCacheOnlyHitIfRigged(false)
, mMaxJointsPerMesh(maxJointsPerMesh)
, mJointMap(legalJointNamesMap)
{
assert_main_thread();
sActiveLoaderList.push_back(this) ;
mWarningsArray = LLSD::emptyArray();
}
LLModelLoader::~LLModelLoader()
{
assert_main_thread();
sActiveLoaderList.remove(this);
}
void LLModelLoader::run()
{
mWarningsArray.clear();
doLoadModel();
doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this));
}
// static
bool LLModelLoader::getSLMFilename(const std::string& model_filename, std::string& slm_filename)
{
slm_filename = model_filename;
std::string::size_type i = model_filename.rfind(".");
if (i != std::string::npos)
{
slm_filename.resize(i, '\0');
slm_filename.append(".slm");
return true;
}
else
{
return false;
}
}
bool LLModelLoader::doLoadModel()
{
//first, look for a .slm file of the same name that was modified later
//than the specified model file
if (mTrySLM)
{
std::string slm_filename;
if (getSLMFilename(mFilename, slm_filename))
{
llstat slm_status;
if (LLFile::stat(slm_filename, &slm_status) == 0)
{ //slm file exists
llstat model_file_status;
if (LLFile::stat(mFilename, &model_file_status) != 0 ||
model_file_status.st_mtime < slm_status.st_mtime)
{
if (loadFromSLM(slm_filename))
{ //slm successfully loaded, if this fails, fall through and
//try loading from model file
mLod = -1; //successfully loading from an slm implicitly sets all
//LoDs
return true;
}
}
}
}
}
return OpenFile(mFilename);
}
void LLModelLoader::setLoadState(U32 state)
{
mStateCallback(state, mOpaqueData);
}
extern std::string stripSuffix(std::string); // <FS:Beq/> mesh loader suffix configuration
bool LLModelLoader::loadFromSLM(const std::string& filename)
{
//only need to populate mScene with data from slm
llstat stat;
if (LLFile::stat(filename, &stat))
{ //file does not exist
return false;
}
S32 file_size = (S32) stat.st_size;
llifstream ifstream(filename.c_str(), std::ifstream::in | std::ifstream::binary);
LLSD data;
LLSDSerialize::fromBinary(data, ifstream, file_size);
ifstream.close();
//build model list for each LoD
model_list model[LLModel::NUM_LODS];
if (data["version"].asInteger() != SLM_SUPPORTED_VERSION)
{ //unsupported version
return false;
}
LLSD& mesh = data["mesh"];
LLVolumeParams volume_params;
volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
{
for (U32 i = 0; i < mesh.size(); ++i)
{
std::stringstream str(mesh[i].asString());
LLPointer<LLModel> loaded_model = new LLModel(volume_params, (F32) lod);
if (loaded_model->loadModel(str))
{
loaded_model->mLocalID = i;
model[lod].push_back(loaded_model);
if (lod == LLModel::LOD_HIGH)
{
if (!loaded_model->mSkinInfo.mJointNames.empty())
{
//check to see if rig is valid
critiqueRigForUploadApplicability( loaded_model->mSkinInfo.mJointNames );
}
else if (mCacheOnlyHitIfRigged)
{
return false;
}
}
}
}
}
if (model[LLModel::LOD_HIGH].empty())
{ //failed to load high lod
return false;
}
//load instance list
model_instance_list instance_list;
LLSD& instance = data["instance"];
for (U32 i = 0; i < instance.size(); ++i)
{
//deserialize instance list
instance_list.push_back(LLModelInstance(instance[i]));
//match up model instance pointers
S32 idx = instance_list[i].mLocalMeshID;
std::string instance_label = instance_list[i].mLabel;
for (U32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
{
if (!model[lod].empty())
{
if (idx >= model[lod].size())
{
instance_list[i].mLOD[lod] = model[lod].front();
continue;
}
if (model[lod][idx]
&& model[lod][idx]->mLabel.empty()
&& !instance_label.empty())
{
// restore model names
// <FS:Beq> This is going to get confusing here. We are juggling internal LOD names, with potentially overridden user ones.
// std::string name = instance_label;
std::string name = stripSuffix(instance_label);
// </FS:Beq>
switch (lod)
{
case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break;
case LLModel::LOD_LOW: name += "_LOD1"; break;
case LLModel::LOD_MEDIUM: name += "_LOD2"; break;
case LLModel::LOD_PHYSICS: name += "_PHYS"; break;
case LLModel::LOD_HIGH: break;
}
model[lod][idx]->mLabel = name;
}
instance_list[i].mLOD[lod] = model[lod][idx];
}
}
if (!instance_list[i].mModel)
instance_list[i].mModel = model[LLModel::LOD_HIGH][idx];
}
// Set name for UI to use
std::string name = data["name"];
if (!name.empty())
{
model[LLModel::LOD_HIGH][0]->mRequestedLabel = name;
}
//convert instance_list to mScene
mFirstTransform = true;
for (U32 i = 0; i < instance_list.size(); ++i)
{
LLModelInstance& cur_instance = instance_list[i];
mScene[cur_instance.mTransform].push_back(cur_instance);
stretch_extents(cur_instance.mModel, cur_instance.mTransform);
}
setLoadState( DONE );
return true;
}
//static
bool LLModelLoader::isAlive(LLModelLoader* loader)
{
if(!loader)
{
return false ;
}
std::list<LLModelLoader*>::iterator iter = sActiveLoaderList.begin() ;
for(; iter != sActiveLoaderList.end() && (*iter) != loader; ++iter) ;
return *iter == loader ;
}
void LLModelLoader::loadModelCallback()
{
if (!LLApp::isExiting())
{
mLoadCallback(mScene, mModelList, mLod, mOpaqueData);
}
while (!isStopped())
{ //wait until this thread is stopped before deleting self
apr_sleep(100);
}
//double check if "this" is valid before deleting it, in case it is aborted during running.
if(!isAlive(this))
{
return ;
}
delete this;
}
//-----------------------------------------------------------------------------
// critiqueRigForUploadApplicability()
//-----------------------------------------------------------------------------
void LLModelLoader::critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset )
{
//Determines the following use cases for a rig:
//1. It is suitable for upload with skin weights & joint positions, or
//2. It is suitable for upload as standard av with just skin weights
bool isJointPositionUploadOK = isRigSuitableForJointPositionUpload( jointListFromAsset );
U32 legacy_rig_flags = determineRigLegacyFlags( jointListFromAsset );
// It's OK that both could end up being true.
// Both start out as true and are forced to false if any mesh in
// the model file is not vald by that criterion. Note that a file
// can contain multiple meshes.
if ( !isJointPositionUploadOK )
{
// This starts out true, becomes false if false for any loaded
// mesh.
setRigValidForJointPositionUpload( false );
}
legacy_rig_flags |= getLegacyRigFlags();
// This starts as 0, changes if any loaded mesh has issues
setLegacyRigFlags(legacy_rig_flags);
}
//-----------------------------------------------------------------------------
// determineRigLegacyFlags()
//-----------------------------------------------------------------------------
U32 LLModelLoader::determineRigLegacyFlags( const std::vector<std::string> &jointListFromAsset )
{
//No joints in asset
if ( jointListFromAsset.size() == 0 )
{
return false;
}
// Too many joints in asset
if (jointListFromAsset.size()>mMaxJointsPerMesh)
{
LL_WARNS() << "Rigged to " << jointListFromAsset.size() << " joints, max is " << mMaxJointsPerMesh << LL_ENDL;
LL_WARNS() << "Skinning disabled due to too many joints" << LL_ENDL;
LLSD args;
args["Message"] = "TooManyJoint";
args["[JOINTS]"] = LLSD::Integer(jointListFromAsset.size());
args["[MAX]"] = LLSD::Integer(mMaxJointsPerMesh);
mWarningsArray.append(args);
return LEGACY_RIG_FLAG_TOO_MANY_JOINTS;
}
// Unknown joints in asset
S32 unknown_joint_count = 0;
for (std::vector<std::string>::const_iterator it = jointListFromAsset.begin();
it != jointListFromAsset.end(); ++it)
{
if (mJointMap.find(*it)==mJointMap.end())
{
LL_WARNS() << "Rigged to unrecognized joint name " << *it << LL_ENDL;
LLSD args;
args["Message"] = "UnrecognizedJoint";
args["[NAME]"] = *it;
mWarningsArray.append(args);
unknown_joint_count++;
}
}
if (unknown_joint_count>0)
{
LL_WARNS() << "Skinning disabled due to unknown joints" << LL_ENDL;
LLSD args;
args["Message"] = "UnknownJoints";
args["[COUNT]"] = LLSD::Integer(unknown_joint_count);
mWarningsArray.append(args);
return LEGACY_RIG_FLAG_UNKNOWN_JOINT;
}
return LEGACY_RIG_OK;
}
//-----------------------------------------------------------------------------
// isRigSuitableForJointPositionUpload()
//-----------------------------------------------------------------------------
bool LLModelLoader::isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset )
{
return true;
}
//called in the main thread
void LLModelLoader::loadTextures()
{
bool is_paused = isPaused() ;
pause() ; //pause the loader
for(scene::iterator iter = mScene.begin(); iter != mScene.end(); ++iter)
{
for(U32 i = 0 ; i < iter->second.size(); i++)
{
for(std::map<std::string, LLImportMaterial>::iterator j = iter->second[i].mMaterial.begin();
j != iter->second[i].mMaterial.end(); ++j)
{
LLImportMaterial& material = j->second;
if(!material.mDiffuseMapFilename.empty())
{
mNumOfFetchingTextures += mTextureLoadFunc(material, mOpaqueData);
}
}
}
}
if(!is_paused)
{
unpause() ;
}
}
+219
View File
@@ -0,0 +1,219 @@
/**
* @file llmodelloader.h
* @brief LLModelLoader class definition
*
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#ifndef LL_LLMODELLOADER_H
#define LL_LLMODELLOADER_H
#include "llmodel.h"
#include "llthread.h"
#include <boost/function.hpp>
#include <list>
class LLJoint;
typedef std::map<std::string, LLMatrix4> JointTransformMap;
typedef std::map<std::string, LLMatrix4>::iterator JointTransformMapIt;
typedef std::map<std::string, std::string, std::less<>> JointMap;
typedef std::deque<std::string> JointNameSet;
const S32 SLM_SUPPORTED_VERSION = 3;
const S32 NUM_LOD = 4;
const U32 LEGACY_RIG_OK = 0;
const U32 LEGACY_RIG_FLAG_TOO_MANY_JOINTS = 1;
const U32 LEGACY_RIG_FLAG_UNKNOWN_JOINT = 2;
class LLModelLoader : public LLThread
{
public:
typedef std::map<std::string, LLImportMaterial> material_map;
typedef std::vector<LLPointer<LLModel>> model_list;
typedef std::vector<LLModelInstance> model_instance_list;
typedef std::map<LLMatrix4, model_instance_list> scene;
// Callback with loaded model data and loaded LoD
//
typedef boost::function<void (scene&, model_list&, S32, void*)> load_callback_t;
// Function to provide joint lookup by name
// (within preview avi skeleton, for example)
//
typedef boost::function<LLJoint* (const std::string&, void*)> joint_lookup_func_t;
// Func to load and associate material with all it's textures,
// returned value is the number of textures loaded
// intentionally non-const so func can modify material to
// store platform-specific data
//
typedef boost::function<U32 (LLImportMaterial&, void*)> texture_load_func_t;
// Callback to inform client of state changes
// during loading process (errors will be reported
// as state changes here as well)
//
typedef boost::function<void (U32, void*)> state_callback_t;
typedef enum
{
STARTING = 0,
READING_FILE,
CREATING_FACES,
GENERATING_VERTEX_BUFFERS,
GENERATING_LOD,
DONE,
WARNING_BIND_SHAPE_ORIENTATION,
ERROR_PARSING, //basically loading failed
ERROR_MATERIALS_NOT_A_SUBSET, // <FS:Beq/> FIRE-30965 - better error differentiation
ERROR_PASSWORD_REQUIRED,
ERROR_NEED_MORE_MEMORY,
ERROR_INVALID_FILE,
ERROR_LOADER_SETUP,
ERROR_INVALID_PARAMETERS,
ERROR_OUT_OF_RANGE,
ERROR_FILE_VERSION_INVALID,
ERROR_LOD_MODEL_MISMATCH, // <FS:Beq/> clean up and improve error reporting
ERROR_HIGH_LOD_MODEL_MISSING, // <FS:Beq/> clean up and improve error reporting
ERROR_MODEL // this error should always be last in this list, error code is passed as ERROR_MODEL+error_code
} eLoadState;
U32 mState;
std::string mFilename;
S32 mLod;
LLMatrix4 mTransform;
bool mFirstTransform;
LLVector3 mExtents[2];
bool mTrySLM;
bool mCacheOnlyHitIfRigged; // ignore cached SLM if it does not contain rig info (and we want rig info)
model_list mModelList;
scene mScene;
typedef std::queue<LLPointer<LLModel> > model_queue;
//queue of models that need a physics rep
model_queue mPhysicsQ;
//map of avatar joints as named in COLLADA assets to internal joint names
JointMap mJointMap;
JointTransformMap& mJointList;
JointNameSet& mJointsFromNode;
U32 mMaxJointsPerMesh;
LLModelLoader(
std::string filename,
S32 lod,
LLModelLoader::load_callback_t load_cb,
LLModelLoader::joint_lookup_func_t joint_lookup_func,
LLModelLoader::texture_load_func_t texture_load_func,
LLModelLoader::state_callback_t state_cb,
void* opaque_userdata,
JointTransformMap& jointTransformMap,
JointNameSet& jointsFromNodes,
JointMap& legalJointNamesMap,
U32 maxJointsPerMesh);
virtual ~LLModelLoader();
virtual void setNoNormalize() { mNoNormalize = true; }
virtual void setNoOptimize() { mNoOptimize = true; }
virtual void run();
static bool getSLMFilename(const std::string& model_filename, std::string& slm_filename);
// Will try SLM or derived class OpenFile as appropriate
//
virtual bool doLoadModel();
// Derived classes need to provide their parsing of files here
//
virtual bool OpenFile(const std::string& filename) = 0;
bool loadFromSLM(const std::string& filename);
void loadModelCallback();
void loadTextures() ; // called in the main thread.
void setLoadState(U32 state);
void stretch_extents(const LLModel* model, const LLMatrix4& mat);
S32 mNumOfFetchingTextures ; // updated in the main thread
bool areTexturesReady() { return !mNumOfFetchingTextures; } // called in the main thread.
bool verifyCount( int expected, int result );
//Determines the viability of an asset to be used as an avatar rig (w or w/o joint upload caps)
void critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset );
//Determines if a rig is a legacy from the joint list
U32 determineRigLegacyFlags( const std::vector<std::string> &jointListFromAsset );
//Determines if a rig is suitable for upload
bool isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset );
const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; }
void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; }
const bool isLegacyRigValid(void) const { return mLegacyRigFlags == 0; }
U32 getLegacyRigFlags() const { return mLegacyRigFlags; }
void setLegacyRigFlags( U32 rigFlags ) { mLegacyRigFlags = rigFlags; }
//-----------------------------------------------------------------------------
// isNodeAJoint()
//-----------------------------------------------------------------------------
bool isNodeAJoint(const char* name)
{
return name != NULL && mJointMap.find(name) != mJointMap.end();
}
const LLSD logOut() const { return mWarningsArray; }
void clearLog() { mWarningsArray.clear(); }
protected:
LLModelLoader::load_callback_t mLoadCallback;
LLModelLoader::joint_lookup_func_t mJointLookupFunc;
LLModelLoader::texture_load_func_t mTextureLoadFunc;
LLModelLoader::state_callback_t mStateCallback;
void* mOpaqueData;
bool mRigValidJointUpload;
U32 mLegacyRigFlags;
bool mNoNormalize;
bool mNoOptimize;
JointTransformMap mJointTransformMap;
LLSD mWarningsArray; // preview floater will pull logs from here
static std::list<LLModelLoader*> sActiveLoaderList;
static bool isAlive(LLModelLoader* loader);
};
#endif // LL_LLMODELLOADER_H
File diff suppressed because it is too large Load Diff
+806
View File
@@ -0,0 +1,806 @@
/**
* @file llprimitive.h
* @brief LLPrimitive base class
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#ifndef LL_LLPRIMITIVE_H
#define LL_LLPRIMITIVE_H
#include "lluuid.h"
#include "v3math.h"
#include "xform.h"
#include "message.h"
#include "llpointer.h"
#include "llvolume.h"
#include "lltextureentry.h"
#include "llprimtexturelist.h"
// Moved to stdtypes.h --JC
// typedef U8 LLPCode;
class LLMessageSystem;
class LLVolumeParams;
class LLColor4;
class LLColor3;
class LLMaterialID;
class LLTextureEntry;
class LLDataPacker;
class LLVolumeMgr;
enum LLGeomType // NOTE: same vals as GL Ids
{
LLInvalid = 0,
LLLineLoop = 2,
LLLineStrip = 3,
LLTriangles = 4,
LLTriStrip = 5,
LLTriFan = 6,
LLQuads = 7,
LLQuadStrip = 8
};
class LLVolume;
/**
* exported constants
*/
extern const F32 OBJECT_CUT_MIN;
extern const F32 OBJECT_CUT_MAX;
extern const F32 OBJECT_CUT_INC;
extern const F32 OBJECT_MIN_CUT_INC;
extern const F32 OBJECT_ROTATION_PRECISION;
extern const F32 OBJECT_TWIST_MIN;
extern const F32 OBJECT_TWIST_MAX;
extern const F32 OBJECT_TWIST_INC;
// This is used for linear paths,
// since twist is used in a slightly different manner.
extern const F32 OBJECT_TWIST_LINEAR_MIN;
extern const F32 OBJECT_TWIST_LINEAR_MAX;
extern const F32 OBJECT_TWIST_LINEAR_INC;
// <AW: opensim-limits>
//extern const F32 OBJECT_MIN_HOLE_SIZE;
extern const F32 SL_OBJECT_MAX_HOLLOW_SIZE;
extern const F32 OS_OBJECT_MAX_HOLLOW_SIZE;
extern const F32 SL_OBJECT_MIN_HOLE_SIZE;
extern const F32 OS_OBJECT_MIN_HOLE_SIZE;
// </AW: opensim-limits>
extern const F32 OBJECT_MAX_HOLE_SIZE_X;
extern const F32 OBJECT_MAX_HOLE_SIZE_Y;
// Revolutions parameters.
extern const F32 OBJECT_REV_MIN;
extern const F32 OBJECT_REV_MAX;
extern const F32 OBJECT_REV_INC;
extern const LLUUID SCULPT_DEFAULT_TEXTURE;
//============================================================================
// TomY: Base class for things that pack & unpack themselves
class LLNetworkData
{
public:
// Extra parameter IDs
enum
{
PARAMS_FLEXIBLE = 0x10,
PARAMS_LIGHT = 0x20,
PARAMS_SCULPT = 0x30,
PARAMS_LIGHT_IMAGE = 0x40,
PARAMS_RESERVED = 0x50, // Used on server-side
PARAMS_MESH = 0x60,
PARAMS_EXTENDED_MESH = 0x70,
PARAMS_RENDER_MATERIAL = 0x80,
PARAMS_REFLECTION_PROBE = 0x90,
};
public:
U16 mType;
virtual ~LLNetworkData() {};
virtual bool pack(LLDataPacker &dp) const = 0;
virtual bool unpack(LLDataPacker &dp) = 0;
virtual bool operator==(const LLNetworkData& data) const = 0;
virtual void copy(const LLNetworkData& data) = 0;
static bool isValid(U16 param_type, U32 size);
};
extern const F32 LIGHT_MIN_RADIUS;
extern const F32 LIGHT_DEFAULT_RADIUS;
extern const F32 LIGHT_MAX_RADIUS;
extern const F32 LIGHT_MIN_FALLOFF;
extern const F32 LIGHT_DEFAULT_FALLOFF;
extern const F32 LIGHT_MAX_FALLOFF;
extern const F32 LIGHT_MIN_CUTOFF;
extern const F32 LIGHT_DEFAULT_CUTOFF;
extern const F32 LIGHT_MAX_CUTOFF;
class LLLightParams : public LLNetworkData
{
private:
LLColor4 mColor; // linear color (not gamma corrected), alpha = intensity
F32 mRadius;
F32 mFalloff;
F32 mCutoff;
public:
LLLightParams();
/*virtual*/ bool pack(LLDataPacker &dp) const;
/*virtual*/ bool unpack(LLDataPacker &dp);
/*virtual*/ bool operator==(const LLNetworkData& data) const;
/*virtual*/ void copy(const LLNetworkData& data);
// LLSD implementations here are provided by Eddy Stryker.
// NOTE: there are currently unused in protocols
LLSD asLLSD() const;
operator LLSD() const { return asLLSD(); }
bool fromLLSD(LLSD& sd);
// set the color by gamma corrected color value
// color - gamma corrected color value (directly taken from an on-screen color swatch)
void setSRGBColor(const LLColor4& color) { setLinearColor(linearColor4(color)); }
// set the color by linear color value
// color - linear color value (value as it appears in shaders)
void setLinearColor(const LLColor4& color) { mColor = color; mColor.clamp(); }
void setRadius(F32 radius) { mRadius = llclamp(radius, LIGHT_MIN_RADIUS, LIGHT_MAX_RADIUS); }
void setFalloff(F32 falloff) { mFalloff = llclamp(falloff, LIGHT_MIN_FALLOFF, LIGHT_MAX_FALLOFF); }
void setCutoff(F32 cutoff) { mCutoff = llclamp(cutoff, LIGHT_MIN_CUTOFF, LIGHT_MAX_CUTOFF); }
// get the linear space color of this light. This value can be fed directly to shaders
LLColor4 getLinearColor() const { return mColor; }
// get the sRGB (gamma corrected) color of this light, this is the value that should be displayed in the UI
LLColor4 getSRGBColor() const { return srgbColor4(mColor); }
F32 getRadius() const { return mRadius; }
F32 getFalloff() const { return mFalloff; }
F32 getCutoff() const { return mCutoff; }
};
extern const F32 REFLECTION_PROBE_MIN_AMBIANCE;
extern const F32 REFLECTION_PROBE_MAX_AMBIANCE;
extern const F32 REFLECTION_PROBE_DEFAULT_AMBIANCE;
extern const F32 REFLECTION_PROBE_MIN_CLIP_DISTANCE;
extern const F32 REFLECTION_PROBE_MAX_CLIP_DISTANCE;
extern const F32 REFLECTION_PROBE_DEFAULT_CLIP_DISTANCE;
class LLReflectionProbeParams : public LLNetworkData
{
public:
enum EFlags : U8
{
FLAG_BOX_VOLUME = 0x01, // use a box influence volume
FLAG_DYNAMIC = 0x02, // render dynamic objects (avatars) into this Reflection Probe
FLAG_MIRROR = 0x04, // This probe is used for reflections on realtime mirrors.
};
protected:
F32 mAmbiance = REFLECTION_PROBE_DEFAULT_AMBIANCE;
F32 mClipDistance = REFLECTION_PROBE_DEFAULT_CLIP_DISTANCE;
U8 mFlags = 0;
public:
LLReflectionProbeParams();
/*virtual*/ bool pack(LLDataPacker& dp) const;
/*virtual*/ bool unpack(LLDataPacker& dp);
/*virtual*/ bool operator==(const LLNetworkData& data) const;
/*virtual*/ void copy(const LLNetworkData& data);
// LLSD implementations here are provided by Eddy Stryker.
// NOTE: there are currently unused in protocols
LLSD asLLSD() const;
operator LLSD() const { return asLLSD(); }
bool fromLLSD(LLSD& sd);
void setAmbiance(F32 ambiance) { mAmbiance = llclamp(ambiance, REFLECTION_PROBE_MIN_AMBIANCE, REFLECTION_PROBE_MAX_AMBIANCE); }
void setClipDistance(F32 distance) { mClipDistance = llclamp(distance, REFLECTION_PROBE_MIN_CLIP_DISTANCE, REFLECTION_PROBE_MAX_CLIP_DISTANCE); }
void setIsBox(bool is_box);
void setIsDynamic(bool is_dynamic);
void setIsMirror(bool is_mirror);
F32 getAmbiance() const { return mAmbiance; }
F32 getClipDistance() const { return mClipDistance; }
bool getIsBox() const { return (mFlags & FLAG_BOX_VOLUME) != 0; }
bool getIsDynamic() const { return (mFlags & FLAG_DYNAMIC) != 0; }
bool getIsMirror() const { return (mFlags & FLAG_MIRROR) != 0; }
};
//-------------------------------------------------
// This structure is also used in the part of the
// code that creates new flexible objects.
//-------------------------------------------------
// These were made into enums so that they could be used as fixed size
// array bounds.
enum EFlexibleObjectConst
{
// "Softness" => [0,3], increments of 1
// Represents powers of 2: 0 -> 1, 3 -> 8
FLEXIBLE_OBJECT_MIN_SECTIONS = 0,
FLEXIBLE_OBJECT_DEFAULT_NUM_SECTIONS = 2,
FLEXIBLE_OBJECT_MAX_SECTIONS = 3
};
// "Tension" => [0,10], increments of 0.1
extern const F32 FLEXIBLE_OBJECT_MIN_TENSION;
extern const F32 FLEXIBLE_OBJECT_DEFAULT_TENSION;
extern const F32 FLEXIBLE_OBJECT_MAX_TENSION;
// "Drag" => [0,10], increments of 0.1
extern const F32 FLEXIBLE_OBJECT_MIN_AIR_FRICTION;
extern const F32 FLEXIBLE_OBJECT_DEFAULT_AIR_FRICTION;
extern const F32 FLEXIBLE_OBJECT_MAX_AIR_FRICTION;
// "Gravity" = [-10,10], increments of 0.1
extern const F32 FLEXIBLE_OBJECT_MIN_GRAVITY;
extern const F32 FLEXIBLE_OBJECT_DEFAULT_GRAVITY;
extern const F32 FLEXIBLE_OBJECT_MAX_GRAVITY;
// "Wind" = [0,10], increments of 0.1
extern const F32 FLEXIBLE_OBJECT_MIN_WIND_SENSITIVITY;
extern const F32 FLEXIBLE_OBJECT_DEFAULT_WIND_SENSITIVITY;
extern const F32 FLEXIBLE_OBJECT_MAX_WIND_SENSITIVITY;
extern const F32 FLEXIBLE_OBJECT_MAX_INTERNAL_TENSION_FORCE;
extern const F32 FLEXIBLE_OBJECT_DEFAULT_LENGTH;
extern const bool FLEXIBLE_OBJECT_DEFAULT_USING_COLLISION_SPHERE;
extern const bool FLEXIBLE_OBJECT_DEFAULT_RENDERING_COLLISION_SPHERE;
class LLFlexibleObjectData : public LLNetworkData
{
protected:
S32 mSimulateLOD; // 2^n = number of simulated sections
F32 mGravity;
F32 mAirFriction; // higher is more stable, but too much looks like it's underwater
F32 mWindSensitivity; // interacts with tension, air friction, and gravity
F32 mTension; //interacts in complex ways with other parameters
LLVector3 mUserForce; // custom user-defined force vector
//bool mUsingCollisionSphere;
//bool mRenderingCollisionSphere;
public:
void setSimulateLOD(S32 lod) { mSimulateLOD = llclamp(lod, (S32)FLEXIBLE_OBJECT_MIN_SECTIONS, (S32)FLEXIBLE_OBJECT_MAX_SECTIONS); }
void setGravity(F32 gravity) { mGravity = llclamp(gravity, FLEXIBLE_OBJECT_MIN_GRAVITY, FLEXIBLE_OBJECT_MAX_GRAVITY); }
void setAirFriction(F32 friction) { mAirFriction = llclamp(friction, FLEXIBLE_OBJECT_MIN_AIR_FRICTION, FLEXIBLE_OBJECT_MAX_AIR_FRICTION); }
void setWindSensitivity(F32 wind) { mWindSensitivity = llclamp(wind, FLEXIBLE_OBJECT_MIN_WIND_SENSITIVITY, FLEXIBLE_OBJECT_MAX_WIND_SENSITIVITY); }
void setTension(F32 tension) { mTension = llclamp(tension, FLEXIBLE_OBJECT_MIN_TENSION, FLEXIBLE_OBJECT_MAX_TENSION); }
void setUserForce(LLVector3 &force) { mUserForce = force; }
S32 getSimulateLOD() const { return mSimulateLOD; }
F32 getGravity() const { return mGravity; }
F32 getAirFriction() const { return mAirFriction; }
F32 getWindSensitivity() const { return mWindSensitivity; }
F32 getTension() const { return mTension; }
LLVector3 getUserForce() const { return mUserForce; }
//------ the constructor for the structure ------------
LLFlexibleObjectData();
bool pack(LLDataPacker &dp) const;
bool unpack(LLDataPacker &dp);
bool operator==(const LLNetworkData& data) const;
void copy(const LLNetworkData& data);
LLSD asLLSD() const;
operator LLSD() const { return asLLSD(); }
bool fromLLSD(LLSD& sd);
};// end of attributes structure
class LLSculptParams : public LLNetworkData
{
protected:
LLUUID mSculptTexture;
U8 mSculptType;
public:
LLSculptParams();
/*virtual*/ bool pack(LLDataPacker &dp) const;
/*virtual*/ bool unpack(LLDataPacker &dp);
/*virtual*/ bool operator==(const LLNetworkData& data) const;
/*virtual*/ void copy(const LLNetworkData& data);
LLSD asLLSD() const;
operator LLSD() const { return asLLSD(); }
bool fromLLSD(LLSD& sd);
void setSculptTexture(const LLUUID& texture_id, U8 sculpt_type);
LLUUID getSculptTexture() const { return mSculptTexture; }
U8 getSculptType() const { return mSculptType; }
};
class LLLightImageParams : public LLNetworkData
{
protected:
LLUUID mLightTexture;
LLVector3 mParams;
public:
LLLightImageParams();
/*virtual*/ bool pack(LLDataPacker &dp) const;
/*virtual*/ bool unpack(LLDataPacker &dp);
/*virtual*/ bool operator==(const LLNetworkData& data) const;
/*virtual*/ void copy(const LLNetworkData& data);
LLSD asLLSD() const;
operator LLSD() const { return asLLSD(); }
bool fromLLSD(LLSD& sd);
void setLightTexture(const LLUUID& id) { mLightTexture = id; }
LLUUID getLightTexture() const { return mLightTexture; }
bool isLightSpotlight() const { return mLightTexture.notNull(); }
void setParams(const LLVector3& params) { mParams = params; }
LLVector3 getParams() const { return mParams; }
};
class LLExtendedMeshParams : public LLNetworkData
{
protected:
U32 mFlags;
public:
static const U32 ANIMATED_MESH_ENABLED_FLAG = 0x1 << 0;
LLExtendedMeshParams();
/*virtual*/ bool pack(LLDataPacker &dp) const;
/*virtual*/ bool unpack(LLDataPacker &dp);
/*virtual*/ bool operator==(const LLNetworkData& data) const;
/*virtual*/ void copy(const LLNetworkData& data);
LLSD asLLSD() const;
operator LLSD() const { return asLLSD(); }
bool fromLLSD(LLSD& sd);
void setFlags(const U32& flags) { mFlags = flags; }
U32 getFlags() const { return mFlags; }
};
class LLRenderMaterialParams : public LLNetworkData
{
private:
struct Entry
{
U8 te_idx;
LLUUID id;
};
std::vector< Entry > mEntries;
public:
LLRenderMaterialParams();
bool pack(LLDataPacker& dp) const override;
bool unpack(LLDataPacker& dp) override;
bool operator==(const LLNetworkData& data) const override;
void copy(const LLNetworkData& data) override;
void setMaterial(U8 te_idx, const LLUUID& id);
const LLUUID& getMaterial(U8 te_idx) const;
bool isEmpty() { return mEntries.empty(); }
};
// This code is not naming-standards compliant. Leaving it like this for
// now to make the connection to code in
// bool packTEMessage(LLDataPacker &dp) const;
// more obvious. This should be refactored to remove the duplication, at which
// point we can fix the names as well.
// - Vir
struct LLTEContents
{
static const U32 MAX_TES = 45;
LLUUID image_data[MAX_TES];
LLColor4U colors[MAX_TES];
F32 scale_s[MAX_TES];
F32 scale_t[MAX_TES];
S16 offset_s[MAX_TES];
S16 offset_t[MAX_TES];
S16 image_rot[MAX_TES];
U8 bump[MAX_TES];
U8 media_flags[MAX_TES];
U8 glow[MAX_TES];
LLMaterialID material_ids[MAX_TES];
static const U32 MAX_TE_BUFFER = 4096;
U8 packed_buffer[MAX_TE_BUFFER];
U32 size;
U32 face_count;
};
class LLPrimitive : public LLXform
{
public:
// HACK for removing LLPrimitive's dependency on gVolumeMgr global.
// If a different LLVolumeManager is instantiated and set early enough
// then the LLPrimitive class will use it instead of gVolumeMgr.
static LLVolumeMgr* getVolumeManager() { return sVolumeManager; }
static void setVolumeManager( LLVolumeMgr* volume_manager);
static bool cleanupVolumeManager();
// these flags influence how the RigidBody representation is built
static const U32 PRIM_FLAG_PHANTOM = 0x1 << 0;
static const U32 PRIM_FLAG_VOLUME_DETECT = 0x1 << 1;
static const U32 PRIM_FLAG_DYNAMIC = 0x1 << 2;
static const U32 PRIM_FLAG_AVATAR = 0x1 << 3;
static const U32 PRIM_FLAG_SCULPT = 0x1 << 4;
// not used yet, but soon
static const U32 PRIM_FLAG_COLLISION_CALLBACK = 0x1 << 5;
static const U32 PRIM_FLAG_CONVEX = 0x1 << 6;
static const U32 PRIM_FLAG_DEFAULT_VOLUME = 0x1 << 7;
static const U32 PRIM_FLAG_SITTING = 0x1 << 8;
static const U32 PRIM_FLAG_SITTING_ON_GROUND = 0x1 << 9; // Set along with PRIM_FLAG_SITTING
LLPrimitive();
virtual ~LLPrimitive();
void clearTextureList();
static LLPrimitive *createPrimitive(LLPCode p_code);
void init_primitive(LLPCode p_code);
void setPCode(const LLPCode pcode);
const LLVolume *getVolumeConst() const { return mVolumep; } // HACK for Windoze confusion about ostream operator in LLVolume
LLVolume *getVolume() const { return mVolumep; }
virtual bool setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume = false);
// Modify texture entry properties
inline bool validTE(const U8 te_num) const;
LLTextureEntry* getTE( const U8 te_num ) const;
LLTextureEntry& getTEref( const U8 te_num ) const;
virtual void setNumTEs(const U8 num_tes);
virtual void setAllTESelected(bool sel);
virtual void setAllTETextures(const LLUUID &tex_id);
virtual void setTE(const U8 index, const LLTextureEntry& te);
virtual S32 setTEColor(const U8 te, const LLColor4 &color);
virtual S32 setTEColor(const U8 te, const LLColor3 &color);
virtual S32 setTEAlpha(const U8 te, const F32 alpha);
virtual S32 setTETexture(const U8 te, const LLUUID &tex_id);
virtual S32 setTEScale (const U8 te, const F32 s, const F32 t);
virtual S32 setTEScaleS(const U8 te, const F32 s);
virtual S32 setTEScaleT(const U8 te, const F32 t);
virtual S32 setTEOffset (const U8 te, const F32 s, const F32 t);
virtual S32 setTEOffsetS(const U8 te, const F32 s);
virtual S32 setTEOffsetT(const U8 te, const F32 t);
virtual S32 setTERotation(const U8 te, const F32 r);
virtual S32 setTEBumpShinyFullbright(const U8 te, const U8 bump);
virtual S32 setTEBumpShiny(const U8 te, const U8 bump);
virtual S32 setTEMediaTexGen(const U8 te, const U8 media);
virtual S32 setTEBumpmap(const U8 te, const U8 bump);
virtual S32 setTETexGen(const U8 te, const U8 texgen);
virtual S32 setTEShiny(const U8 te, const U8 shiny);
virtual S32 setTEFullbright(const U8 te, const U8 fullbright);
virtual S32 setTEMediaFlags(const U8 te, const U8 flags);
virtual S32 setTEGlow(const U8 te, const F32 glow);
virtual S32 setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID);
virtual S32 setTEMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams);
virtual bool setMaterial(const U8 material); // returns true if material changed
virtual void setTESelected(const U8 te, bool sel);
LLMaterialPtr getTEMaterialParams(const U8 index);
void copyTEs(const LLPrimitive *primitive);
S32 packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_face_index, EMsgVariableType type) const;
bool packTEMessage(LLMessageSystem *mesgsys) const;
bool packTEMessage(LLDataPacker &dp) const;
S32 unpackTEMessage(LLMessageSystem* mesgsys, char const* block_name, const S32 block_num); // Variable num of blocks
S32 unpackTEMessage(LLDataPacker &dp);
S32 parseTEMessage(LLMessageSystem* mesgsys, char const* block_name, const S32 block_num, LLTEContents& tec);
S32 applyParsedTEMessage(LLTEContents& tec);
#ifdef CHECK_FOR_FINITE
inline void setPosition(const LLVector3& pos);
inline void setPosition(const F32 x, const F32 y, const F32 z);
inline void addPosition(const LLVector3& pos);
inline void setAngularVelocity(const LLVector3& avel);
inline void setAngularVelocity(const F32 x, const F32 y, const F32 z);
inline void setVelocity(const LLVector3& vel);
inline void setVelocity(const F32 x, const F32 y, const F32 z);
inline void setVelocityX(const F32 x);
inline void setVelocityY(const F32 y);
inline void setVelocityZ(const F32 z);
inline void addVelocity(const LLVector3& vel);
inline void setAcceleration(const LLVector3& accel);
inline void setAcceleration(const F32 x, const F32 y, const F32 z);
#else
// Don't override the base LLXForm operators.
// Special case for setPosition. If not check-for-finite, fall through to LLXform method.
// void setPosition(F32 x, F32 y, F32 z)
// void setPosition(LLVector3)
void setAngularVelocity(const LLVector3& avel) { mAngularVelocity = avel; }
void setAngularVelocity(const F32 x, const F32 y, const F32 z) { mAngularVelocity.setVec(x,y,z); }
void setVelocity(const LLVector3& vel) { mVelocity = vel; }
void setVelocity(const F32 x, const F32 y, const F32 z) { mVelocity.setVec(x,y,z); }
void setVelocityX(const F32 x) { mVelocity.mV[VX] = x; }
void setVelocityY(const F32 y) { mVelocity.mV[VY] = y; }
void setVelocityZ(const F32 z) { mVelocity.mV[VZ] = z; }
void addVelocity(const LLVector3& vel) { mVelocity += vel; }
void setAcceleration(const LLVector3& accel) { mAcceleration = accel; }
void setAcceleration(const F32 x, const F32 y, const F32 z) { mAcceleration.setVec(x,y,z); }
#endif
LLPCode getPCode() const { return mPrimitiveCode; }
std::string getPCodeString() const { return pCodeToString(mPrimitiveCode); }
const LLVector3& getAngularVelocity() const { return mAngularVelocity; }
const LLVector3& getVelocity() const { return mVelocity; }
const LLVector3& getAcceleration() const { return mAcceleration; }
U8 getNumTEs() const { return mTextureList.size(); }
U8 getExpectedNumTEs() const;
U8 getMaterial() const { return mMaterial; }
void setVolumeType(const U8 code);
U8 getVolumeType();
// clears existing textures
// copies the contents of other_list into mEntryList
void copyTextureList(const LLPrimTextureList& other_list);
// clears existing textures
// takes the contents of other_list and clears other_list
void takeTextureList(LLPrimTextureList& other_list);
inline bool isAvatar() const;
inline bool isSittingAvatar() const;
inline bool isSittingAvatarOnGround() const;
inline bool hasBumpmap() const { return mNumBumpmapTEs > 0;}
void setFlags(U32 flags) { mMiscFlags = flags; }
void addFlags(U32 flags) { mMiscFlags |= flags; }
void removeFlags(U32 flags) { mMiscFlags &= ~flags; }
U32 getFlags() const { return mMiscFlags; }
bool checkFlags(U32 flags) const { return (mMiscFlags & flags) != 0; }
static std::string pCodeToString(const LLPCode pcode);
static LLPCode legacyToPCode(const U8 legacy);
static U8 pCodeToLegacy(const LLPCode pcode);
static bool getTESTAxes(const U8 face, U32* s_axis, U32* t_axis);
bool hasRenderMaterialParams() const;
inline static bool isPrimitive(const LLPCode pcode);
inline static bool isApp(const LLPCode pcode);
private:
void updateNumBumpmap(const U8 index, const U8 bump);
protected:
LLPCode mPrimitiveCode; // Primitive code
LLVector3 mVelocity; // how fast are we moving?
LLVector3 mAcceleration; // are we under constant acceleration?
LLVector3 mAngularVelocity; // angular velocity
LLPointer<LLVolume> mVolumep;
LLPrimTextureList mTextureList; // list of texture GUIDs, scales, offsets
U8 mMaterial; // Material code
U8 mNumTEs; // # of faces on the primitve
U8 mNumBumpmapTEs; // number of bumpmap TEs.
U32 mMiscFlags; // home for misc bools
public:
static LLVolumeMgr* sVolumeManager;
enum
{
NO_LOD = -1
};
};
inline bool LLPrimitive::isAvatar() const
{
return LL_PCODE_LEGACY_AVATAR == mPrimitiveCode;
}
inline bool LLPrimitive::isSittingAvatar() const
{
// this is only used server-side
return isAvatar() && checkFlags(PRIM_FLAG_SITTING | PRIM_FLAG_SITTING_ON_GROUND);
}
inline bool LLPrimitive::isSittingAvatarOnGround() const
{
// this is only used server-side
return isAvatar() && checkFlags(PRIM_FLAG_SITTING_ON_GROUND);
}
// static
inline bool LLPrimitive::isPrimitive(const LLPCode pcode)
{
LLPCode base_type = pcode & LL_PCODE_BASE_MASK;
if (base_type && (base_type < LL_PCODE_APP))
{
return true;
}
return false;
}
// static
inline bool LLPrimitive::isApp(const LLPCode pcode)
{
LLPCode base_type = pcode & LL_PCODE_BASE_MASK;
return (base_type == LL_PCODE_APP);
}
#ifdef CHECK_FOR_FINITE
// Special case for setPosition. If not check-for-finite, fall through to LLXform method.
void LLPrimitive::setPosition(const F32 x, const F32 y, const F32 z)
{
if (llfinite(x) && llfinite(y) && llfinite(z))
{
LLXform::setPosition(x, y, z);
}
else
{
LL_ERRS() << "Non Finite in LLPrimitive::setPosition(x,y,z) for " << pCodeToString(mPrimitiveCode) << LL_ENDL;
}
}
// Special case for setPosition. If not check-for-finite, fall through to LLXform method.
void LLPrimitive::setPosition(const LLVector3& pos)
{
if (pos.isFinite())
{
LLXform::setPosition(pos);
}
else
{
LL_ERRS() << "Non Finite in LLPrimitive::setPosition(LLVector3) for " << pCodeToString(mPrimitiveCode) << LL_ENDL;
}
}
void LLPrimitive::setAngularVelocity(const LLVector3& avel)
{
if (avel.isFinite())
{
mAngularVelocity = avel;
}
else
{
LL_ERRS() << "Non Finite in LLPrimitive::setAngularVelocity" << LL_ENDL;
}
}
void LLPrimitive::setAngularVelocity(const F32 x, const F32 y, const F32 z)
{
if (llfinite(x) && llfinite(y) && llfinite(z))
{
mAngularVelocity.setVec(x,y,z);
}
else
{
LL_ERRS() << "Non Finite in LLPrimitive::setAngularVelocity" << LL_ENDL;
}
}
void LLPrimitive::setVelocity(const LLVector3& vel)
{
if (vel.isFinite())
{
mVelocity = vel;
}
else
{
LL_ERRS() << "Non Finite in LLPrimitive::setVelocity(LLVector3) for " << pCodeToString(mPrimitiveCode) << LL_ENDL;
}
}
void LLPrimitive::setVelocity(const F32 x, const F32 y, const F32 z)
{
if (llfinite(x) && llfinite(y) && llfinite(z))
{
mVelocity.setVec(x,y,z);
}
else
{
LL_ERRS() << "Non Finite in LLPrimitive::setVelocity(F32,F32,F32) for " << pCodeToString(mPrimitiveCode) << LL_ENDL;
}
}
void LLPrimitive::setVelocityX(const F32 x)
{
if (llfinite(x))
{
mVelocity.mV[VX] = x;
}
else
{
LL_ERRS() << "Non Finite in LLPrimitive::setVelocityX" << LL_ENDL;
}
}
void LLPrimitive::setVelocityY(const F32 y)
{
if (llfinite(y))
{
mVelocity.mV[VY] = y;
}
else
{
LL_ERRS() << "Non Finite in LLPrimitive::setVelocityY" << LL_ENDL;
}
}
void LLPrimitive::setVelocityZ(const F32 z)
{
if (llfinite(z))
{
mVelocity.mV[VZ] = z;
}
else
{
LL_ERRS() << "Non Finite in LLPrimitive::setVelocityZ" << LL_ENDL;
}
}
void LLPrimitive::addVelocity(const LLVector3& vel)
{
if (vel.isFinite())
{
mVelocity += vel;
}
else
{
LL_ERRS() << "Non Finite in LLPrimitive::addVelocity" << LL_ENDL;
}
}
void LLPrimitive::setAcceleration(const LLVector3& accel)
{
if (accel.isFinite())
{
mAcceleration = accel;
}
else
{
LL_ERRS() << "Non Finite in LLPrimitive::setAcceleration(LLVector3) for " << pCodeToString(mPrimitiveCode) << LL_ENDL;
}
}
void LLPrimitive::setAcceleration(const F32 x, const F32 y, const F32 z)
{
if (llfinite(x) && llfinite(y) && llfinite(z))
{
mAcceleration.setVec(x,y,z);
}
else
{
LL_ERRS() << "Non Finite in LLPrimitive::setAcceleration(F32,F32,F32) for " << pCodeToString(mPrimitiveCode) << LL_ENDL;
}
}
#endif // CHECK_FOR_FINITE
inline bool LLPrimitive::validTE(const U8 te_num) const
{
return (mNumTEs && te_num < mNumTEs);
}
#endif
+393
View File
@@ -0,0 +1,393 @@
/**
* @file llprimlinkinfo.h
* @author andrew@lindenlab.com
* @brief A template for determining which prims in a set are linkable
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#ifndef LL_PRIM_LINK_INFO_H
#define LL_PRIM_LINK_INFO_H
// system includes
#include <iostream>
#include <map>
#include <list>
#include <vector>
// common includes
#include "stdtypes.h"
#include "v3math.h"
#include "llquaternion.h"
#include "llsphere.h"
const F32 MAX_OBJECT_SPAN = 54.f; // max distance from outside edge of an object to the farthest edge
const F32 OBJECT_SPAN_BONUS = 2.f; // infinitesimally small prims can always link up to this distance
const S32 MAX_PRIMS_PER_OBJECT = 256;
template < typename DATA_TYPE >
class LLPrimLinkInfo
{
public:
LLPrimLinkInfo();
LLPrimLinkInfo( DATA_TYPE data, const LLSphere& sphere );
~LLPrimLinkInfo();
void set( DATA_TYPE data, const LLSphere& sphere );
void append( DATA_TYPE data, const LLSphere& sphere );
void getData( std::list< DATA_TYPE >& data_list ) const;
F32 getDiameter() const;
LLVector3 getCenter() const;
// returns 'true' if this info can link with other_info
bool canLink( const LLPrimLinkInfo< DATA_TYPE >& other_info );
S32 getPrimCount() const { return mDataMap.size(); }
void mergeLinkableSet( typename std::list< LLPrimLinkInfo < DATA_TYPE > >& unlinked );
void transform(const LLVector3& position, const LLQuaternion& rotation);
private:
// returns number of merges made
S32 merge(LLPrimLinkInfo< DATA_TYPE >& other_info);
// returns number of collapses made
static S32 collapse(typename std::list< LLPrimLinkInfo < DATA_TYPE > >& unlinked );
void computeBoundingSphere();
// Internal utility to encapsulate the link rules
F32 get_max_linkable_span(const LLSphere& first, const LLSphere& second);
F32 get_span(const LLSphere& first, const LLSphere& second);
private:
std::map< DATA_TYPE, LLSphere > mDataMap;
LLSphere mBoundingSphere;
};
template < typename DATA_TYPE >
LLPrimLinkInfo< DATA_TYPE >::LLPrimLinkInfo()
: mBoundingSphere( LLVector3(0.f, 0.f, 0.f), 0.f )
{
}
template < typename DATA_TYPE >
LLPrimLinkInfo< DATA_TYPE >::LLPrimLinkInfo( DATA_TYPE data, const LLSphere& sphere)
: mBoundingSphere(sphere)
{
mDataMap[data] = sphere;
}
template < typename DATA_TYPE >
LLPrimLinkInfo< DATA_TYPE >::~LLPrimLinkInfo()
{
mDataMap.clear();
}
template < typename DATA_TYPE >
void LLPrimLinkInfo< DATA_TYPE>::set( DATA_TYPE data, const LLSphere& sphere )
{
if (!mDataMap.empty())
{
mDataMap.clear();
}
mDataMap[data] = sphere;
mBoundingSphere = sphere;
}
template < typename DATA_TYPE >
void LLPrimLinkInfo< DATA_TYPE>::append( DATA_TYPE data, const LLSphere& sphere )
{
mDataMap[data] = sphere;
if (!mBoundingSphere.contains(sphere))
{
computeBoundingSphere();
}
}
template < typename DATA_TYPE >
void LLPrimLinkInfo< DATA_TYPE >::getData( std::list< DATA_TYPE >& data_list) const
{
typename std::map< DATA_TYPE, LLSphere >::const_iterator map_itr;
for (map_itr = mDataMap.begin(); map_itr != mDataMap.end(); ++map_itr)
{
data_list.push_back(map_itr->first);
}
}
template < typename DATA_TYPE >
F32 LLPrimLinkInfo< DATA_TYPE >::getDiameter() const
{
return 2.f * mBoundingSphere.getRadius();
}
template < typename DATA_TYPE >
LLVector3 LLPrimLinkInfo< DATA_TYPE >::getCenter() const
{
return mBoundingSphere.getCenter();
}
template < typename DATA_TYPE >
F32 LLPrimLinkInfo< DATA_TYPE >::get_max_linkable_span(const LLSphere& first, const LLSphere& second)
{
F32 max_span = 3.f * (first.getRadius() + second.getRadius()) + OBJECT_SPAN_BONUS;
if (max_span > MAX_OBJECT_SPAN)
{
max_span = MAX_OBJECT_SPAN;
}
return max_span;
}
template < typename DATA_TYPE >
F32 LLPrimLinkInfo< DATA_TYPE >::get_span(const LLSphere& first, const LLSphere& second)
{
F32 span = (first.getCenter() - second.getCenter()).length()
+ first.getRadius() + second.getRadius();
return span;
}
// static
// returns 'true' if this info can link with any part of other_info
template < typename DATA_TYPE >
bool LLPrimLinkInfo< DATA_TYPE >::canLink(const LLPrimLinkInfo& other_info)
{
F32 max_span = get_max_linkable_span(mBoundingSphere, other_info.mBoundingSphere);
F32 span = get_span(mBoundingSphere, other_info.mBoundingSphere);
if (span <= max_span)
{
// The entire other_info fits inside the max span.
return TRUE;
}
else if (span > max_span + 2.f * other_info.mBoundingSphere.getRadius())
{
// there is no way any piece of other_info could link with this one
return FALSE;
}
// there may be a piece of other_info that is linkable
typename std::map< DATA_TYPE, LLSphere >::const_iterator map_itr;
for (map_itr = other_info.mDataMap.begin(); map_itr != other_info.mDataMap.end(); ++map_itr)
{
const LLSphere& other_sphere = (*map_itr).second;
max_span = get_max_linkable_span(mBoundingSphere, other_sphere);
span = get_span(mBoundingSphere, other_sphere);
if (span <= max_span)
{
// found one piece that is linkable
return TRUE;
}
}
return FALSE;
}
// merges elements of 'unlinked'
// returns number of links made (NOT final prim count, NOR linked prim count)
// and removes any linkable infos from 'unlinked'
template < typename DATA_TYPE >
void LLPrimLinkInfo< DATA_TYPE >::mergeLinkableSet(std::list< LLPrimLinkInfo< DATA_TYPE > > & unlinked)
{
bool linked_something = true;
while (linked_something)
{
linked_something = false;
typename std::list< LLPrimLinkInfo< DATA_TYPE > >::iterator other_itr = unlinked.begin();
while ( other_itr != unlinked.end()
&& getPrimCount() < MAX_PRIMS_PER_OBJECT )
{
S32 merge_count = merge(*other_itr);
if (merge_count > 0)
{
linked_something = true;
}
if (0 == (*other_itr).getPrimCount())
{
unlinked.erase(other_itr++);
}
else
{
++other_itr;
}
}
if (!linked_something
&& unlinked.size() > 1)
{
S32 collapse_count = collapse(unlinked);
if (collapse_count > 0)
{
linked_something = true;
}
}
}
}
// transforms all of the spheres into a new reference frame
template < typename DATA_TYPE >
void LLPrimLinkInfo< DATA_TYPE >::transform(const LLVector3& position, const LLQuaternion& rotation)
{
typename std::map< DATA_TYPE, LLSphere >::iterator map_itr;
for (map_itr = mDataMap.begin(); map_itr != mDataMap.end(); ++map_itr)
{
(*map_itr).second.setCenter((*map_itr).second.getCenter() * rotation + position);
}
mBoundingSphere.setCenter(mBoundingSphere.getCenter() * rotation + position);
}
// private
// returns number of links made
template < typename DATA_TYPE >
S32 LLPrimLinkInfo< DATA_TYPE >::merge(LLPrimLinkInfo& other_info)
{
S32 link_count = 0;
// F32 other_radius = other_info.mBoundingSphere.getRadius();
// other_info.computeBoundingSphere();
// if ( other_radius != other_info.mBoundingSphere.getRadius() )
// {
// LL_INFOS() << "Other bounding sphere changed!!" << LL_ENDL;
// }
// F32 this_radius = mBoundingSphere.getRadius();
// computeBoundingSphere();
// if ( this_radius != mBoundingSphere.getRadius() )
// {
// LL_INFOS() << "This bounding sphere changed!!" << LL_ENDL;
// }
F32 max_span = get_max_linkable_span(mBoundingSphere, other_info.mBoundingSphere);
// F32 center_dist = (mBoundingSphere.getCenter() - other_info.mBoundingSphere.getCenter()).length();
// LL_INFOS() << "objects are " << center_dist << "m apart" << LL_ENDL;
F32 span = get_span(mBoundingSphere, other_info.mBoundingSphere);
F32 span_limit = max_span + (2.f * other_info.mBoundingSphere.getRadius());
if (span > span_limit)
{
// there is no way any piece of other_info could link with this one
// LL_INFOS() << "span too large: " << span << " vs. " << span_limit << LL_ENDL;
return 0;
}
bool completely_linkable = (span <= max_span) ? true : false;
typename std::map< DATA_TYPE, LLSphere >::iterator map_itr = other_info.mDataMap.begin();
while (map_itr != other_info.mDataMap.end()
&& getPrimCount() < MAX_PRIMS_PER_OBJECT )
{
DATA_TYPE other_data = (*map_itr).first;
LLSphere& other_sphere = (*map_itr).second;
if (!completely_linkable)
{
max_span = get_max_linkable_span(mBoundingSphere, other_sphere);
F32 span = get_span(mBoundingSphere, other_sphere);
if (span > max_span)
{
++map_itr;
continue;
}
}
mDataMap[other_data] = other_sphere;
++link_count;
if (!mBoundingSphere.contains(other_sphere) )
{
computeBoundingSphere();
}
// remove from the other info
other_info.mDataMap.erase(map_itr++);
}
if (link_count > 0 && other_info.getPrimCount() > 0)
{
other_info.computeBoundingSphere();
}
return link_count;
}
// links any linkable elements of unlinked
template < typename DATA_TYPE >
S32 LLPrimLinkInfo< DATA_TYPE >::collapse(std::list< LLPrimLinkInfo< DATA_TYPE > > & unlinked)
{
S32 link_count = 0;
bool linked_something = true;
while (linked_something)
{
linked_something = false;
typename std::list< LLPrimLinkInfo< DATA_TYPE > >::iterator this_itr = unlinked.begin();
typename std::list< LLPrimLinkInfo< DATA_TYPE > >::iterator other_itr = this_itr;
++other_itr;
while ( other_itr != unlinked.end() )
{
S32 merge_count = (*this_itr).merge(*other_itr);
if (merge_count > 0)
{
linked_something = true;
link_count += merge_count;
}
if (0 == (*other_itr).getPrimCount())
{
unlinked.erase(other_itr++);
}
else
{
++other_itr;
}
}
}
return link_count;
}
template < typename DATA_TYPE >
void LLPrimLinkInfo< DATA_TYPE >::computeBoundingSphere()
{
std::vector< LLSphere > sphere_list;
typename std::map< DATA_TYPE, LLSphere >::const_iterator map_itr;
for (map_itr = mDataMap.begin(); map_itr != mDataMap.end(); ++map_itr)
{
sphere_list.push_back(map_itr->second);
}
mBoundingSphere = LLSphere::getBoundingSphere(sphere_list);
}
#endif
+450
View File
@@ -0,0 +1,450 @@
/**
* @file lltexturelist.cpp
* @brief LLPrimTextureList (virtual) base class
*
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "linden_common.h"
#include "llprimtexturelist.h"
#include "llmaterialid.h"
#include "lltextureentry.h"
// static
//int (TMyClass::*pt2Member)(float, char, char) = NULL; // C++
LLTextureEntry* (*LLPrimTextureList::sNewTextureEntryCallback)() = &(LLTextureEntry::newTextureEntry);
// static
void LLPrimTextureList::setNewTextureEntryCallback( LLTextureEntry* (*callback)() )
{
if (callback)
{
LLPrimTextureList::sNewTextureEntryCallback = callback;
}
else
{
LLPrimTextureList::sNewTextureEntryCallback = &(LLTextureEntry::newTextureEntry);
}
}
// static
// call this to get a new texture entry
LLTextureEntry* LLPrimTextureList::newTextureEntry()
{
return (*sNewTextureEntryCallback)();
}
LLPrimTextureList::LLPrimTextureList()
{
}
// virtual
LLPrimTextureList::~LLPrimTextureList()
{
clear();
}
void LLPrimTextureList::clear()
{
texture_list_t::iterator itr = mEntryList.begin();
while (itr != mEntryList.end())
{
delete (*itr);
(*itr) = NULL;
++itr;
}
mEntryList.clear();
}
// clears current entries
// copies contents of other_list
// this is somewhat expensive, so it must be called explicitly
void LLPrimTextureList::copy(const LLPrimTextureList& other_list)
{
// compare the sizes
auto this_size = mEntryList.size();
auto other_size = other_list.mEntryList.size();
if (this_size > other_size)
{
// remove the extra entries
for (size_t index = this_size; index > other_size; --index)
{
delete mEntryList[index-1];
}
mEntryList.resize(other_size);
this_size = other_size;
}
size_t index = 0;
// copy for the entries that already exist
for ( ; index < this_size; ++index)
{
delete mEntryList[index];
mEntryList[index] = other_list.getTexture(static_cast<U8>(index))->newCopy();
}
// add new entires if needed
for ( ; index < other_size; ++index)
{
mEntryList.push_back( other_list.getTexture(static_cast<U8>(index))->newCopy());
}
}
// clears current copies
// takes contents of other_list
// clears other_list
void LLPrimTextureList::take(LLPrimTextureList& other_list)
{
clear();
mEntryList = other_list.mEntryList;
other_list.mEntryList.clear();
}
// virtual
// copies LLTextureEntry 'te'
// returns TEM_CHANGE_TEXTURE if successful, otherwise TEM_CHANGE_NONE
S32 LLPrimTextureList::copyTexture(const U8 index, const LLTextureEntry& te)
{
if (size_t(index) >= mEntryList.size())
{
auto current_size = mEntryList.size();
LL_WARNS() << "ignore copy of index = " << S32(index) << " into texture entry list of size = " << current_size << LL_ENDL;
return TEM_CHANGE_NONE;
}
// we're changing an existing entry
llassert(mEntryList[index]);
delete (mEntryList[index]);
mEntryList[index] = te.newCopy();
return TEM_CHANGE_TEXTURE;
}
// virtual
// takes ownership of LLTextureEntry* 'te'
// returns TEM_CHANGE_TEXTURE if successful, otherwise TEM_CHANGE_NONE
// IMPORTANT! -- if you use this function you must check the return value
S32 LLPrimTextureList::takeTexture(const U8 index, LLTextureEntry* te)
{
if (S32(index) >= mEntryList.size())
{
return TEM_CHANGE_NONE;
}
// we're changing an existing entry
llassert(mEntryList[index]);
delete (mEntryList[index]);
mEntryList[index] = te;
return TEM_CHANGE_TEXTURE;
}
// returns pointer to texture at 'index' slot
LLTextureEntry* LLPrimTextureList::getTexture(const U8 index) const
{
if (index < mEntryList.size())
{
return mEntryList[index];
}
return NULL;
}
LLTextureEntry& LLPrimTextureList::getTextureRef( const U8 index ) const
{
if( index >= mEntryList.size() )
{
LL_ERRS() << "Texture index out of bounds, index: " << (U32)index << " mEntryList.size(): " << mEntryList.size() << LL_ENDL;
}
return *mEntryList[ index ];
}
//virtual
//S32 setTE(const U8 index, const LLTextureEntry& te) = 0;
S32 LLPrimTextureList::setID(const U8 index, const LLUUID& id)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setID(id);
}
return TEM_CHANGE_NONE;
}
S32 LLPrimTextureList::setColor(const U8 index, const LLColor3& color)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setColor(color);
}
return TEM_CHANGE_NONE;
}
S32 LLPrimTextureList::setColor(const U8 index, const LLColor4& color)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setColor(color);
}
return TEM_CHANGE_NONE;
}
S32 LLPrimTextureList::setAlpha(const U8 index, const F32 alpha)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setAlpha(alpha);
}
return TEM_CHANGE_NONE;
}
S32 LLPrimTextureList::setScale(const U8 index, const F32 s, const F32 t)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setScale(s, t);
}
return TEM_CHANGE_NONE;
}
S32 LLPrimTextureList::setScaleS(const U8 index, const F32 s)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setScaleS(s);
}
return TEM_CHANGE_NONE;
}
S32 LLPrimTextureList::setScaleT(const U8 index, const F32 t)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setScaleT(t);
}
return TEM_CHANGE_NONE;
}
S32 LLPrimTextureList::setOffset(const U8 index, const F32 s, const F32 t)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setOffset(s, t);
}
return TEM_CHANGE_NONE;
}
S32 LLPrimTextureList::setOffsetS(const U8 index, const F32 s)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setOffsetS(s);
}
return TEM_CHANGE_NONE;
}
S32 LLPrimTextureList::setOffsetT(const U8 index, const F32 t)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setOffsetT(t);
}
return TEM_CHANGE_NONE;
}
S32 LLPrimTextureList::setRotation(const U8 index, const F32 r)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setRotation(r);
}
return TEM_CHANGE_NONE;
}
S32 LLPrimTextureList::setBumpShinyFullbright(const U8 index, const U8 bump)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setBumpShinyFullbright(bump);
}
return TEM_CHANGE_NONE;
}
S32 LLPrimTextureList::setMediaTexGen(const U8 index, const U8 media)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setMediaTexGen(media);
}
return TEM_CHANGE_NONE;
}
S32 LLPrimTextureList::setBumpMap(const U8 index, const U8 bump)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setBumpmap(bump);
}
return TEM_CHANGE_NONE;
}
S32 LLPrimTextureList::setBumpShiny(const U8 index, const U8 bump_shiny)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setBumpShiny(bump_shiny);
}
return TEM_CHANGE_NONE;
}
S32 LLPrimTextureList::setTexGen(const U8 index, const U8 texgen)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setTexGen(texgen);
}
return TEM_CHANGE_NONE;
}
S32 LLPrimTextureList::setShiny(const U8 index, const U8 shiny)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setShiny(shiny);
}
return TEM_CHANGE_NONE;
}
S32 LLPrimTextureList::setFullbright(const U8 index, const U8 fullbright)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setFullbright(fullbright);
}
return TEM_CHANGE_NONE;
}
S32 LLPrimTextureList::setMediaFlags(const U8 index, const U8 media_flags)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setMediaFlags(media_flags);
}
return TEM_CHANGE_NONE;
}
S32 LLPrimTextureList::setGlow(const U8 index, const F32 glow)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setGlow(glow);
}
return TEM_CHANGE_NONE;
}
S32 LLPrimTextureList::setMaterialID(const U8 index, const LLMaterialID& pMaterialID)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setMaterialID(pMaterialID);
}
return TEM_CHANGE_NONE;
}
S32 LLPrimTextureList::setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams)
{
if (index < mEntryList.size())
{
return mEntryList[index]->setMaterialParams(pMaterialParams);
}
return TEM_CHANGE_NONE;
}
LLMaterialPtr LLPrimTextureList::getMaterialParams(const U8 index)
{
if (index < mEntryList.size())
{
return mEntryList[index]->getMaterialParams();
}
return LLMaterialPtr();
}
S32 LLPrimTextureList::size() const
{
return static_cast<S32>(mEntryList.size());
}
// sets the size of the mEntryList container
void LLPrimTextureList::setSize(S32 new_size)
{
if (new_size < 0)
{
new_size = 0;
}
auto current_size = mEntryList.size();
if (new_size > current_size)
{
mEntryList.resize(new_size);
for (size_t index = current_size; index < new_size; ++index)
{
if (current_size > 0
&& mEntryList[current_size - 1])
{
// copy the last valid entry for the new one
mEntryList[index] = mEntryList[current_size - 1]->newCopy();
}
else
{
// no valid enries to copy, so we new one up
LLTextureEntry* new_entry = LLPrimTextureList::newTextureEntry();
mEntryList[index] = new_entry;
}
}
}
else if (new_size < current_size)
{
for (size_t index = current_size-1; index >= new_size; --index)
{
delete mEntryList[index];
}
mEntryList.resize(new_size);
}
}
void LLPrimTextureList::setAllIDs(const LLUUID& id)
{
texture_list_t::iterator itr = mEntryList.begin();
while (itr != mEntryList.end())
{
(*itr)->setID(id);
++itr;
}
}
+128
View File
@@ -0,0 +1,128 @@
/**
* @file llprimtexturelist.h
* @brief LLPrimTextureList (virtual) base class
*
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#ifndef LL_LLPRIMTEXTURELIST_H
#define LL_LLPRIMTEXTURELIST_H
#include <vector>
#include "lluuid.h"
#include "v3color.h"
#include "v4color.h"
#include "llmaterial.h"
class LLTextureEntry;
class LLMaterialID;
// this is a list of LLTextureEntry*'s because in practice the list's elements
// are of some derived class: LLFooTextureEntry
typedef std::vector<LLTextureEntry*> texture_list_t;
class LLPrimTextureList
{
public:
// the LLPrimTextureList needs to know what type of LLTextureEntry
// to generate when it needs a new one, so we may need to set a
// callback for generating it, (or else use the base class default:
// static LLPrimTextureEntry::newTextureEntry() )
//typedef LLTextureEntry* (__stdcall *NewTextureEntryFunction)();
//static NewTextureEntryFunction sNewTextureEntryCallback;
static LLTextureEntry* newTextureEntry();
static void setNewTextureEntryCallback( LLTextureEntry* (*callback)() );
static LLTextureEntry* (*sNewTextureEntryCallback)();
LLPrimTextureList();
virtual ~LLPrimTextureList();
void clear();
// clears current entries
// copies contents of other_list
// this is somewhat expensive, so it must be called explicitly
void copy(const LLPrimTextureList& other_list);
// clears current copies
// takes contents of other_list
// clears other_list
void take(LLPrimTextureList& other_list);
// copies LLTextureEntry 'te'
// returns TEM_CHANGE_TEXTURE if successful, otherwise TEM_CHANGE_NONE
S32 copyTexture(const U8 index, const LLTextureEntry& te);
// takes ownership of LLTextureEntry* 'te'
// returns TEM_CHANGE_TEXTURE if successful, otherwise TEM_CHANGE_NONE
// IMPORTANT! -- if you use this function you must check the return value
S32 takeTexture(const U8 index, LLTextureEntry* te);
// // copies contents of 'entry' and stores it in 'index' slot
// void copyTexture(const U8 index, const LLTextureEntry* entry);
// returns pointer to texture at 'index' slot
LLTextureEntry* getTexture( const U8 index ) const;
LLTextureEntry& getTextureRef( const U8 index ) const;
S32 setID(const U8 index, const LLUUID& id);
S32 setColor(const U8 index, const LLColor3& color);
S32 setColor(const U8 index, const LLColor4& color);
S32 setAlpha(const U8 index, const F32 alpha);
S32 setScale(const U8 index, const F32 s, const F32 t);
S32 setScaleS(const U8 index, const F32 s);
S32 setScaleT(const U8 index, const F32 t);
S32 setOffset(const U8 index, const F32 s, const F32 t);
S32 setOffsetS(const U8 index, const F32 s);
S32 setOffsetT(const U8 index, const F32 t);
S32 setRotation(const U8 index, const F32 r);
S32 setBumpShinyFullbright(const U8 index, const U8 bump);
S32 setMediaTexGen(const U8 index, const U8 media);
S32 setBumpMap(const U8 index, const U8 bump);
S32 setBumpShiny(const U8 index, const U8 bump_shiny);
S32 setTexGen(const U8 index, const U8 texgen);
S32 setShiny(const U8 index, const U8 shiny);
S32 setFullbright(const U8 index, const U8 t);
S32 setMediaFlags(const U8 index, const U8 media_flags);
S32 setGlow(const U8 index, const F32 glow);
S32 setMaterialID(const U8 index, const LLMaterialID& pMaterialID);
S32 setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams);
LLMaterialPtr getMaterialParams(const U8 index);
S32 size() const;
// void forceResize(S32 new_size);
void setSize(S32 new_size);
void setAllIDs(const LLUUID& id);
protected:
texture_list_t mEntryList;
private:
LLPrimTextureList(const LLPrimTextureList& other_list)
{
// private so that it can't be used
}
};
#endif
+239
View File
@@ -0,0 +1,239 @@
/**
* @file lltextureanim.cpp
* @brief LLTextureAnim base class
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "linden_common.h"
#include "lltextureanim.h"
#include "message.h"
#include "lldatapacker.h"
const S32 TA_BLOCK_SIZE = 16;
LLTextureAnim::LLTextureAnim()
{
reset();
}
LLTextureAnim::~LLTextureAnim()
{
}
void LLTextureAnim::reset()
{
mMode = 0;
mFace = -1;
mSizeX = 4;
mSizeY = 4;
mStart = 0.f;
mLength = 0.f;
mRate = 1.f;
}
bool LLTextureAnim::equals(const LLTextureAnim &other) const
{
if (mMode != other.mMode)
{
return false;
}
if (mFace != other.mFace)
{
return false;
}
if (mSizeX != other.mSizeX)
{
return false;
}
if (mSizeY != other.mSizeY)
{
return false;
}
if (mStart != other.mStart)
{
return false;
}
if (mLength != other.mLength)
{
return false;
}
if (mRate != other.mRate)
{
return false;
}
return true;
}
void LLTextureAnim::packTAMessage(LLMessageSystem *mesgsys) const
{
U8 data[TA_BLOCK_SIZE];
data[0] = mMode;
data[1] = mFace;
data[2] = mSizeX;
data[3] = mSizeY;
htolememcpy(data + 4, &mStart, MVT_F32, sizeof(F32));
htolememcpy(data + 8, &mLength, MVT_F32, sizeof(F32));
htolememcpy(data + 12, &mRate, MVT_F32, sizeof(F32));
mesgsys->addBinaryDataFast(_PREHASH_TextureAnim, data, TA_BLOCK_SIZE);
}
void LLTextureAnim::packTAMessage(LLDataPacker &dp) const
{
U8 data[TA_BLOCK_SIZE];
data[0] = mMode;
data[1] = mFace;
data[2] = mSizeX;
data[3] = mSizeY;
htolememcpy(data + 4, &mStart, MVT_F32, sizeof(F32));
htolememcpy(data + 8, &mLength, MVT_F32, sizeof(F32));
htolememcpy(data + 12, &mRate, MVT_F32, sizeof(F32));
dp.packBinaryData(data, TA_BLOCK_SIZE, "TextureAnimation");
}
void LLTextureAnim::unpackTAMessage(LLMessageSystem *mesgsys, const S32 block_num)
{
S32 size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_TextureAnim);
if (size != TA_BLOCK_SIZE)
{
if (size)
{
LL_WARNS() << "Bad size " << size << " for TA block, ignoring." << LL_ENDL;
}
mMode = 0;
return;
}
U8 data[TA_BLOCK_SIZE];
mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextureAnim, data, TA_BLOCK_SIZE, block_num);
mMode = data[0];
mFace = data[1];
if (mMode & LLTextureAnim::SMOOTH)
{
mSizeX = llmax((U8)0, data[2]);
mSizeY = llmax((U8)0, data[3]);
}
else
{
mSizeX = llmax((U8)1, data[2]);
mSizeY = llmax((U8)1, data[3]);
}
htolememcpy(&mStart, data + 4, MVT_F32, sizeof(F32));
htolememcpy(&mLength, data + 8, MVT_F32, sizeof(F32));
htolememcpy(&mRate, data + 12, MVT_F32, sizeof(F32));
}
void LLTextureAnim::unpackTAMessage(LLDataPacker &dp)
{
S32 size;
U8 data[TA_BLOCK_SIZE];
dp.unpackBinaryData(data, size, "TextureAnimation");
if (size != TA_BLOCK_SIZE)
{
if (size)
{
LL_WARNS() << "Bad size " << size << " for TA block, ignoring." << LL_ENDL;
}
mMode = 0;
return;
}
mMode = data[0];
mFace = data[1];
mSizeX = data[2];
mSizeY = data[3];
htolememcpy(&mStart, data + 4, MVT_F32, sizeof(F32));
htolememcpy(&mLength, data + 8, MVT_F32, sizeof(F32));
htolememcpy(&mRate, data + 12, MVT_F32, sizeof(F32));
}
LLSD LLTextureAnim::asLLSD() const
{
LLSD sd;
sd["mode"] = mMode;
sd["face"] = mFace;
sd["sizeX"] = mSizeX;
sd["sizeY"] = mSizeY;
sd["start"] = mStart;
sd["length"] = mLength;
sd["rate"] = mRate;
return sd;
}
bool LLTextureAnim::fromLLSD(LLSD& sd)
{
const char *w;
w = "mode";
if (sd.has(w))
{
mMode = (U8)sd[w].asInteger();
} else goto fail;
w = "face";
if (sd.has(w))
{
mFace = (S8)sd[w].asInteger();
} else goto fail;
w = "sizeX";
if (sd.has(w))
{
mSizeX = (U8)sd[w].asInteger();
} else goto fail;
w = "sizeY";
if (sd.has(w))
{
mSizeY = (U8)sd[w].asInteger();
} else goto fail;
w = "start";
if (sd.has(w))
{
mStart = (F32)sd[w].asReal();
} else goto fail;
w = "length";
if (sd.has(w))
{
mLength = (F32)sd[w].asReal();
} else goto fail;
w = "rate";
if (sd.has(w))
{
mRate = (F32)sd[w].asReal();
} else goto fail;
return true;
fail:
return false;
}
+72
View File
@@ -0,0 +1,72 @@
/**
* @file lltextureanim.h
* @brief LLTextureAnim base class
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#ifndef LL_LLTEXTUREANIM_H
#define LL_LLTEXTUREANIM_H
#include "stdtypes.h"
#include "llsd.h"
class LLMessageSystem;
class LLDataPacker;
class LLTextureAnim
{
public:
LLTextureAnim();
virtual ~LLTextureAnim();
virtual void reset();
void packTAMessage(LLMessageSystem *mesgsys) const;
void packTAMessage(LLDataPacker &dp) const;
void unpackTAMessage(LLMessageSystem *mesgsys, const S32 block_num);
void unpackTAMessage(LLDataPacker &dp);
bool equals(const LLTextureAnim &other) const;
LLSD asLLSD() const;
operator LLSD() const { return asLLSD(); }
bool fromLLSD(LLSD& sd);
enum
{
ON = 0x01,
LOOP = 0x02,
REVERSE = 0x04,
PING_PONG = 0x08,
SMOOTH = 0x10,
ROTATE = 0x20,
SCALE = 0x40,
};
public:
U8 mMode;
S8 mFace;
U8 mSizeX;
U8 mSizeY;
F32 mStart;
F32 mLength;
F32 mRate; // Rate in frames per second.
};
#endif
+800
View File
@@ -0,0 +1,800 @@
/**
* @file lltextureentry.cpp
* @brief LLTextureEntry base class
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "linden_common.h"
#include "lluuid.h"
#include "llmediaentry.h"
#include "lltextureentry.h"
#include "llmaterialid.h"
#include "llsdutil_math.h"
#include "v4color.h"
const U8 DEFAULT_BUMP_CODE = 0; // no bump or shininess
const LLTextureEntry LLTextureEntry::null;
// Some LLSD keys. Do not change these!
#define OBJECT_ID_KEY_STR "object_id"
#define TEXTURE_INDEX_KEY_STR "texture_index"
#define OBJECT_MEDIA_VERSION_KEY_STR "object_media_version"
#define OBJECT_MEDIA_DATA_KEY_STR "object_media_data"
#define TEXTURE_MEDIA_DATA_KEY_STR "media_data"
/*static*/ const char* LLTextureEntry::OBJECT_ID_KEY = OBJECT_ID_KEY_STR;
/*static*/ const char* LLTextureEntry::OBJECT_MEDIA_DATA_KEY = OBJECT_MEDIA_DATA_KEY_STR;
/*static*/ const char* LLTextureEntry::MEDIA_VERSION_KEY = OBJECT_MEDIA_VERSION_KEY_STR;
/*static*/ const char* LLTextureEntry::TEXTURE_INDEX_KEY = TEXTURE_INDEX_KEY_STR;
/*static*/ const char* LLTextureEntry::TEXTURE_MEDIA_DATA_KEY = TEXTURE_MEDIA_DATA_KEY_STR;
static const std::string MEDIA_VERSION_STRING_PREFIX = "x-mv:";
// static
LLTextureEntry* LLTextureEntry::newTextureEntry()
{
return new LLTextureEntry();
}
//===============================================================
LLTextureEntry::LLTextureEntry()
: mMediaEntry(NULL)
, mSelected(false)
, mMaterialUpdatePending(false)
{
init(LLUUID::null,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE);
}
LLTextureEntry::LLTextureEntry(const LLUUID& tex_id)
: mMediaEntry(NULL)
, mSelected(false)
, mMaterialUpdatePending(false)
{
init(tex_id,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE);
}
LLTextureEntry::LLTextureEntry(const LLTextureEntry &rhs)
: mMediaEntry(NULL)
, mSelected(false)
, mMaterialUpdatePending(false)
{
*this = rhs;
}
LLTextureEntry &LLTextureEntry::operator=(const LLTextureEntry &rhs)
{
if (this != &rhs)
{
mID = rhs.mID;
mScaleS = rhs.mScaleS;
mScaleT = rhs.mScaleT;
mOffsetS = rhs.mOffsetS;
mOffsetT = rhs.mOffsetT;
mRotation = rhs.mRotation;
mColor = rhs.mColor;
mBump = rhs.mBump;
mMediaFlags = rhs.mMediaFlags;
mGlow = rhs.mGlow;
mMaterialID = rhs.mMaterialID;
mMaterial = rhs.mMaterial;
if (mMediaEntry != NULL) {
delete mMediaEntry;
}
if (rhs.mMediaEntry != NULL) {
// Make a copy
mMediaEntry = new LLMediaEntry(*rhs.mMediaEntry);
}
else {
mMediaEntry = NULL;
}
mMaterialID = rhs.mMaterialID;
if (mGLTFMaterial)
{
mGLTFMaterial->removeTextureEntry(this);
}
mGLTFMaterial = rhs.mGLTFMaterial;
if (mGLTFMaterial)
{
mGLTFMaterial->addTextureEntry(this);
}
if (rhs.mGLTFMaterialOverrides.notNull())
{
mGLTFMaterialOverrides = new LLGLTFMaterial(*rhs.mGLTFMaterialOverrides);
}
else
{
mGLTFMaterialOverrides = nullptr;
}
}
return *this;
}
void LLTextureEntry::init(const LLUUID& tex_id, F32 scale_s, F32 scale_t, F32 offset_s, F32 offset_t, F32 rotation, U8 bump)
{
setID(tex_id);
mScaleS = scale_s;
mScaleT = scale_t;
mOffsetS = offset_s;
mOffsetT = offset_t;
mRotation = rotation;
mBump = bump;
mMediaFlags = 0x0;
mGlow = 0;
mMaterialID.clear();
setColor(LLColor4(1.f, 1.f, 1.f, 1.f));
if (mMediaEntry != NULL) {
delete mMediaEntry;
}
mMediaEntry = NULL;
}
LLTextureEntry::~LLTextureEntry()
{
if(mMediaEntry)
{
delete mMediaEntry;
mMediaEntry = NULL;
}
if (mGLTFMaterial)
{
mGLTFMaterial->removeTextureEntry(this);
mGLTFMaterial = NULL;
}
}
bool LLTextureEntry::operator!=(const LLTextureEntry &rhs) const
{
if (mID != rhs.mID) return(true);
if (mScaleS != rhs.mScaleS) return(true);
if (mScaleT != rhs.mScaleT) return(true);
if (mOffsetS != rhs.mOffsetS) return(true);
if (mOffsetT != rhs.mOffsetT) return(true);
if (mRotation != rhs.mRotation) return(true);
if (mColor != rhs.mColor) return (true);
if (mBump != rhs.mBump) return (true);
if (mMediaFlags != rhs.mMediaFlags) return (true);
if (mGlow != rhs.mGlow) return (true);
if (mMaterialID != rhs.mMaterialID) return (true);
return(false);
}
bool LLTextureEntry::operator==(const LLTextureEntry &rhs) const
{
if (mID != rhs.mID) return(false);
if (mScaleS != rhs.mScaleS) return(false);
if (mScaleT != rhs.mScaleT) return(false);
if (mOffsetS != rhs.mOffsetS) return(false);
if (mOffsetT != rhs.mOffsetT) return(false);
if (mRotation != rhs.mRotation) return(false);
if (mColor != rhs.mColor) return (false);
if (mBump != rhs.mBump) return (false);
if (mMediaFlags != rhs.mMediaFlags) return false;
if (mGlow != rhs.mGlow) return false;
if (mMaterialID != rhs.mMaterialID) return (false);
return(true);
}
LLSD LLTextureEntry::asLLSD() const
{
LLSD sd;
asLLSD(sd);
return sd;
}
void LLTextureEntry::asLLSD(LLSD& sd) const
{
LL_PROFILE_ZONE_SCOPED;
sd["imageid"] = mID;
sd["colors"] = ll_sd_from_color4(mColor);
sd["scales"] = mScaleS;
sd["scalet"] = mScaleT;
sd["offsets"] = mOffsetS;
sd["offsett"] = mOffsetT;
sd["imagerot"] = mRotation;
sd["bump"] = getBumpShiny();
sd["fullbright"] = getFullbright();
sd["media_flags"] = mMediaFlags;
if (hasMedia()) {
LLSD mediaData;
if (NULL != getMediaData()) {
getMediaData()->asLLSD(mediaData);
}
sd[TEXTURE_MEDIA_DATA_KEY] = mediaData;
}
sd["glow"] = mGlow;
if (mGLTFMaterialOverrides.notNull())
{
sd["gltf_override"] = mGLTFMaterialOverrides->asJSON();
}
}
bool LLTextureEntry::fromLLSD(const LLSD& sd)
{
LL_PROFILE_ZONE_SCOPED;
const char *w, *x;
w = "imageid";
if (sd.has(w))
{
setID( sd[w] );
} else goto fail;
w = "colors";
if (sd.has(w))
{
setColor( ll_color4_from_sd(sd["colors"]) );
} else goto fail;
w = "scales";
x = "scalet";
if (sd.has(w) && sd.has(x))
{
setScale( (F32)sd[w].asReal(), (F32)sd[x].asReal() );
} else goto fail;
w = "offsets";
x = "offsett";
if (sd.has(w) && sd.has(x))
{
setOffset( (F32)sd[w].asReal(), (F32)sd[x].asReal() );
} else goto fail;
w = "imagerot";
if (sd.has(w))
{
setRotation( (F32)sd[w].asReal() );
} else goto fail;
w = "bump";
if (sd.has(w))
{
setBumpShiny( sd[w].asInteger() );
} else goto fail;
w = "fullbright";
if (sd.has(w))
{
setFullbright( sd[w].asInteger() );
} else goto fail;
w = "media_flags";
if (sd.has(w))
{
setMediaTexGen( sd[w].asInteger() );
} else goto fail;
// If the "has media" flag doesn't match the fact that
// media data exists, updateMediaData will "fix" it
// by either clearing or setting the flag
w = TEXTURE_MEDIA_DATA_KEY;
if (hasMedia() != sd.has(w))
{
LL_WARNS() << "LLTextureEntry::fromLLSD: media_flags (" << hasMedia() <<
") does not match presence of media_data (" << sd.has(w) << "). Fixing." << LL_ENDL;
}
updateMediaData(sd[w]);
w = "glow";
if (sd.has(w))
{
setGlow((F32)sd[w].asReal() );
}
w = "gltf_override";
if (sd.has(w))
{
if (mGLTFMaterialOverrides.isNull())
{
mGLTFMaterialOverrides = new LLGLTFMaterial();
}
std::string warn_msg, error_msg;
if (!mGLTFMaterialOverrides->fromJSON(sd[w].asString(), warn_msg, error_msg))
{
LL_WARNS() << llformat("Failed to parse GLTF json: %s -- %s", warn_msg.c_str(), error_msg.c_str()) << LL_ENDL;
LL_WARNS() << sd[w].asString() << LL_ENDL;
mGLTFMaterialOverrides = nullptr;
}
}
return true;
fail:
return false;
}
// virtual
// override this method for each derived class
LLTextureEntry* LLTextureEntry::newBlank() const
{
return new LLTextureEntry();
}
// virtual
LLTextureEntry* LLTextureEntry::newCopy() const
{
return new LLTextureEntry(*this);
}
S32 LLTextureEntry::setID(const LLUUID &tex_id)
{
if (mID != tex_id)
{
mID = tex_id;
return TEM_CHANGE_TEXTURE;
}
return TEM_CHANGE_NONE;
}
S32 LLTextureEntry::setScale(F32 s, F32 t)
{
S32 retval = 0;
if ( (mScaleS != s)
||(mScaleT != t))
{
mScaleS = s;
mScaleT = t;
retval = TEM_CHANGE_TEXTURE;
}
return retval;
}
S32 LLTextureEntry::setScaleS(F32 s)
{
S32 retval = TEM_CHANGE_NONE;
if (mScaleS != s)
{
mScaleS = s;
retval = TEM_CHANGE_TEXTURE;
}
return retval;
}
S32 LLTextureEntry::setScaleT(F32 t)
{
S32 retval = TEM_CHANGE_NONE;
if (mScaleT != t)
{
mScaleT = t;
retval = TEM_CHANGE_TEXTURE;
}
return retval;
}
S32 LLTextureEntry::setColor(const LLColor4 &color)
{
if (mColor != color)
{
mColor = color;
return TEM_CHANGE_COLOR;
}
return TEM_CHANGE_NONE;
}
S32 LLTextureEntry::setColor(const LLColor3 &color)
{
if (mColor != color)
{
// This preserves alpha.
mColor.setVec(color);
return TEM_CHANGE_COLOR;
}
return TEM_CHANGE_NONE;
}
S32 LLTextureEntry::setAlpha(const F32 alpha)
{
if (mColor.mV[VALPHA] != alpha)
{
mColor.mV[VALPHA] = alpha;
return TEM_CHANGE_COLOR;
}
return TEM_CHANGE_NONE;
}
S32 LLTextureEntry::setOffset(F32 s, F32 t)
{
S32 retval = 0;
if ( (mOffsetS != s)
||(mOffsetT != t))
{
mOffsetS = s;
mOffsetT = t;
retval = TEM_CHANGE_TEXTURE;
}
return retval;
}
S32 LLTextureEntry::setOffsetS(F32 s)
{
S32 retval = 0;
if (mOffsetS != s)
{
mOffsetS = s;
retval = TEM_CHANGE_TEXTURE;
}
return retval;
}
S32 LLTextureEntry::setOffsetT(F32 t)
{
S32 retval = 0;
if (mOffsetT != t)
{
mOffsetT = t;
retval = TEM_CHANGE_TEXTURE;
}
return retval;
}
S32 LLTextureEntry::setRotation(F32 theta)
{
if (mRotation != theta && llfinite(theta))
{
mRotation = theta;
return TEM_CHANGE_TEXTURE;
}
return TEM_CHANGE_NONE;
}
S32 LLTextureEntry::setBumpShinyFullbright(U8 bump)
{
if (mBump != bump)
{
mBump = bump;
return TEM_CHANGE_TEXTURE;
}
return TEM_CHANGE_NONE;
}
S32 LLTextureEntry::setMediaTexGen(U8 media)
{
S32 result = TEM_CHANGE_NONE;
result |= setTexGen(media & TEM_TEX_GEN_MASK);
result |= setMediaFlags(media & TEM_MEDIA_MASK);
return result;
}
S32 LLTextureEntry::setBumpmap(U8 bump)
{
bump &= TEM_BUMP_MASK;
if (getBumpmap() != bump)
{
mBump &= ~TEM_BUMP_MASK;
mBump |= bump;
return TEM_CHANGE_TEXTURE;
}
return TEM_CHANGE_NONE;
}
S32 LLTextureEntry::setFullbright(U8 fullbright)
{
fullbright &= TEM_FULLBRIGHT_MASK;
if (getFullbright() != fullbright)
{
mBump &= ~(TEM_FULLBRIGHT_MASK<<TEM_FULLBRIGHT_SHIFT);
mBump |= fullbright << TEM_FULLBRIGHT_SHIFT;
return TEM_CHANGE_TEXTURE;
}
return TEM_CHANGE_NONE;
}
S32 LLTextureEntry::setShiny(U8 shiny)
{
shiny &= TEM_SHINY_MASK;
if (getShiny() != shiny)
{
mBump &= ~(TEM_SHINY_MASK<<TEM_SHINY_SHIFT);
mBump |= shiny << TEM_SHINY_SHIFT;
return TEM_CHANGE_TEXTURE;
}
return TEM_CHANGE_NONE;
}
S32 LLTextureEntry::setBumpShiny(U8 bump_shiny)
{
bump_shiny &= TEM_BUMP_SHINY_MASK;
if (getBumpShiny() != bump_shiny)
{
mBump &= ~TEM_BUMP_SHINY_MASK;
mBump |= bump_shiny;
return TEM_CHANGE_TEXTURE;
}
return TEM_CHANGE_NONE;
}
void LLTextureEntry::setGLTFMaterial(LLGLTFMaterial* material, bool local_origin)
{
if (material != getGLTFMaterial())
{
// assert on precondtion:
// whether or not mGLTFMaterial is null, any existing override should have been cleared
// before calling setGLTFMaterial
// NOTE: if you're hitting this assert, try to make sure calling code is using LLViewerObject::setRenderMaterialID
//llassert(!local_origin || getGLTFMaterialOverride() == nullptr || getGLTFMaterialOverride()->isClearedForBaseMaterial());
if (mGLTFMaterial)
{
// Local materials have to keep track
// due to update mechanics
mGLTFMaterial->removeTextureEntry(this);
}
mGLTFMaterial = material;
if (mGLTFMaterial)
{
mGLTFMaterial->addTextureEntry(this);
}
if (mGLTFMaterial == nullptr)
{
setGLTFRenderMaterial(nullptr);
}
}
}
S32 LLTextureEntry::setGLTFMaterialOverride(LLGLTFMaterial* mat)
{
llassert(mat == nullptr || getGLTFMaterial() != nullptr); // if override is not null, base material must not be null
if (mat == mGLTFMaterialOverrides)
{
return TEM_CHANGE_NONE;
}
mGLTFMaterialOverrides = mat;
return TEM_CHANGE_TEXTURE;
}
S32 LLTextureEntry::setBaseMaterial()
{
S32 changed = TEM_CHANGE_NONE;
if (mGLTFMaterialOverrides)
{
if (mGLTFMaterialOverrides->setBaseMaterial())
{
changed = TEM_CHANGE_TEXTURE;
}
if (LLGLTFMaterial::sDefault == *mGLTFMaterialOverrides)
{
mGLTFMaterialOverrides = nullptr;
changed = TEM_CHANGE_TEXTURE;
}
}
return changed;
}
LLGLTFMaterial* LLTextureEntry::getGLTFRenderMaterial() const
{
if (mGLTFRenderMaterial.notNull())
{
return mGLTFRenderMaterial;
}
llassert(getGLTFMaterialOverride() == nullptr || getGLTFMaterialOverride()->isClearedForBaseMaterial());
return getGLTFMaterial();
}
S32 LLTextureEntry::setGLTFRenderMaterial(LLGLTFMaterial* mat)
{
if (mGLTFRenderMaterial != mat)
{
mGLTFRenderMaterial = mat;
return TEM_CHANGE_TEXTURE;
}
return TEM_CHANGE_NONE;
}
S32 LLTextureEntry::setMediaFlags(U8 media_flags)
{
media_flags &= TEM_MEDIA_MASK;
if (getMediaFlags() != media_flags)
{
mMediaFlags &= ~TEM_MEDIA_MASK;
mMediaFlags |= media_flags;
// Special code for media handling
if( hasMedia() && mMediaEntry == NULL)
{
mMediaEntry = new LLMediaEntry;
}
else if ( ! hasMedia() && mMediaEntry != NULL)
{
delete mMediaEntry;
mMediaEntry = NULL;
}
return TEM_CHANGE_MEDIA;
}
return TEM_CHANGE_NONE;
}
S32 LLTextureEntry::setTexGen(U8 tex_gen)
{
tex_gen &= TEM_TEX_GEN_MASK;
if (getTexGen() != tex_gen)
{
mMediaFlags &= ~TEM_TEX_GEN_MASK;
mMediaFlags |= tex_gen;
return TEM_CHANGE_TEXTURE;
}
return TEM_CHANGE_NONE;
}
S32 LLTextureEntry::setGlow(F32 glow)
{
if (mGlow != glow)
{
mGlow = glow;
return TEM_CHANGE_TEXTURE;
}
return TEM_CHANGE_NONE;
}
S32 LLTextureEntry::setMaterialID(const LLMaterialID& pMaterialID)
{
if ( (mMaterialID != pMaterialID) || (mMaterialUpdatePending && !mSelected) )
{
if (mSelected)
{
mMaterialUpdatePending = true;
mMaterialID = pMaterialID;
return TEM_CHANGE_TEXTURE;
}
mMaterialUpdatePending = false;
mMaterialID = pMaterialID;
return TEM_CHANGE_TEXTURE;
}
return TEM_CHANGE_NONE;
}
S32 LLTextureEntry::setMaterialParams(const LLMaterialPtr pMaterialParams)
{
if (mSelected)
{
mMaterialUpdatePending = true;
}
mMaterial = pMaterialParams;
return TEM_CHANGE_TEXTURE;
}
void LLTextureEntry::setMediaData(const LLMediaEntry &media_entry)
{
mMediaFlags |= MF_HAS_MEDIA;
if (NULL != mMediaEntry)
{
delete mMediaEntry;
}
mMediaEntry = new LLMediaEntry(media_entry);
}
bool LLTextureEntry::updateMediaData(const LLSD& media_data)
{
if (media_data.isUndefined())
{
// clear the media data
clearMediaData();
return false;
}
else {
mMediaFlags |= MF_HAS_MEDIA;
if (mMediaEntry == NULL)
{
mMediaEntry = new LLMediaEntry;
}
// *NOTE: this will *clobber* all of the fields in mMediaEntry
// with whatever fields are present (or not present) in media_data!
mMediaEntry->fromLLSD(media_data);
return true;
}
}
void LLTextureEntry::clearMediaData()
{
mMediaFlags &= ~MF_HAS_MEDIA;
if (mMediaEntry != NULL) {
delete mMediaEntry;
}
mMediaEntry = NULL;
}
void LLTextureEntry::mergeIntoMediaData(const LLSD& media_fields)
{
mMediaFlags |= MF_HAS_MEDIA;
if (mMediaEntry == NULL)
{
mMediaEntry = new LLMediaEntry;
}
// *NOTE: this will *merge* the data in media_fields
// with the data in our media entry
mMediaEntry->mergeFromLLSD(media_fields);
}
//static
std::string LLTextureEntry::touchMediaVersionString(const std::string &in_version, const LLUUID &agent_id)
{
// XXX TODO: make media version string binary (base64-encoded?)
// Media "URL" is a representation of a version and the last-touched agent
// x-mv:nnnnn/agent-id
// where "nnnnn" is version number
// *NOTE: not the most efficient code in the world...
U32 current_version = getVersionFromMediaVersionString(in_version) + 1;
const size_t MAX_VERSION_LEN = 10; // 2^32 fits in 10 decimal digits
char buf[MAX_VERSION_LEN+1];
snprintf(buf, (int)MAX_VERSION_LEN+1, "%0*u", (int)MAX_VERSION_LEN, current_version); // added int cast to fix warning/breakage on mac.
return MEDIA_VERSION_STRING_PREFIX + buf + "/" + agent_id.asString();
}
//static
U32 LLTextureEntry::getVersionFromMediaVersionString(const std::string &version_string)
{
U32 version = 0;
if (!version_string.empty())
{
size_t found = version_string.find(MEDIA_VERSION_STRING_PREFIX);
if (found != std::string::npos)
{
found = version_string.find_first_of("/", found);
std::string v = version_string.substr(MEDIA_VERSION_STRING_PREFIX.length(), found);
version = strtoul(v.c_str(),NULL,10);
}
}
return version;
}
//static
LLUUID LLTextureEntry::getAgentIDFromMediaVersionString(const std::string &version_string)
{
LLUUID id;
if (!version_string.empty())
{
size_t found = version_string.find(MEDIA_VERSION_STRING_PREFIX);
if (found != std::string::npos)
{
found = version_string.find_first_of("/", found);
if (found != std::string::npos)
{
std::string v = version_string.substr(found + 1);
id.set(v);
}
}
}
return id;
}
//static
bool LLTextureEntry::isMediaVersionString(const std::string &version_string)
{
return std::string::npos != version_string.find(MEDIA_VERSION_STRING_PREFIX);
}
+261
View File
@@ -0,0 +1,261 @@
/**
* @file lltextureentry.h
* @brief LLTextureEntry base class
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#ifndef LL_LLTEXTUREENTRY_H
#define LL_LLTEXTUREENTRY_H
#include "lluuid.h"
#include "v4color.h"
#include "llsd.h"
#include "llmaterialid.h"
#include "llmaterial.h"
#include "llgltfmaterial.h"
// These bits are used while unpacking TEM messages to tell which aspects of
// the texture entry changed.
const S32 TEM_CHANGE_NONE = 0x0;
const S32 TEM_CHANGE_COLOR = 0x1;
const S32 TEM_CHANGE_TEXTURE = 0x2;
const S32 TEM_CHANGE_MEDIA = 0x4;
const S32 TEM_INVALID = 0x8;
const S32 TEM_BUMPMAP_COUNT = 32;
// The Bump Shiny Fullbright values are bits in an eight bit field:
// +----------+
// | SSFBBBBB | S = Shiny, F = Fullbright, B = Bumpmap
// | 76543210 |
// +----------+
const S32 TEM_BUMP_MASK = 0x1f; // 5 bits
const S32 TEM_FULLBRIGHT_MASK = 0x01; // 1 bit
const S32 TEM_SHINY_MASK = 0x03; // 2 bits
const S32 TEM_BUMP_SHINY_MASK = (0xc0 | 0x1f);
const S32 TEM_FULLBRIGHT_SHIFT = 5;
const S32 TEM_SHINY_SHIFT = 6;
// The Media Tex Gen values are bits in a bit field:
// +----------+
// | .....TTM | M = Media Flags (web page), T = LLTextureEntry::eTexGen, . = unused
// | 76543210 |
// +----------+
const S32 TEM_MEDIA_MASK = 0x01;
const S32 TEM_TEX_GEN_MASK = 0x06;
const S32 TEM_TEX_GEN_SHIFT = 1;
// forward declarations
class LLMediaEntry;
class LLTextureEntry
{
public:
static LLTextureEntry* newTextureEntry();
typedef enum e_texgen
{
TEX_GEN_DEFAULT = 0x00,
TEX_GEN_PLANAR = 0x02,
TEX_GEN_SPHERICAL = 0x04,
TEX_GEN_CYLINDRICAL = 0x06
} eTexGen;
LLTextureEntry();
LLTextureEntry(const LLUUID& tex_id);
LLTextureEntry(const LLTextureEntry &rhs);
LLTextureEntry &operator=(const LLTextureEntry &rhs);
virtual ~LLTextureEntry();
bool operator==(const LLTextureEntry &rhs) const;
bool operator!=(const LLTextureEntry &rhs) const;
// Added to allow use with std::map
//
bool operator <(const LLTextureEntry &rhs) const;
LLSD asLLSD() const;
void asLLSD(LLSD& sd) const;
operator LLSD() const { return asLLSD(); }
bool fromLLSD(const LLSD& sd);
virtual LLTextureEntry* newBlank() const;
virtual LLTextureEntry* newCopy() const;
void init(const LLUUID& tex_id, F32 scale_s, F32 scale_t, F32 offset_s, F32 offset_t, F32 rotation, U8 bump);
bool hasPendingMaterialUpdate() const { return mMaterialUpdatePending; }
bool isSelected() const { return mSelected; }
bool setSelected(bool sel) { bool prev_sel = mSelected; mSelected = sel; return prev_sel; }
// These return a TEM_ flag from above to indicate if something changed.
S32 setID (const LLUUID &tex_id);
S32 setColor(const LLColor4 &color);
S32 setColor(const LLColor3 &color);
S32 setAlpha(const F32 alpha);
S32 setScale(F32 s, F32 t);
S32 setScaleS(F32 s);
S32 setScaleT(F32 t);
S32 setOffset(F32 s, F32 t);
S32 setOffsetS(F32 s);
S32 setOffsetT(F32 t);
S32 setRotation(F32 theta);
S32 setBumpmap(U8 bump);
S32 setFullbright(U8 bump);
S32 setShiny(U8 bump);
S32 setBumpShiny(U8 bump);
S32 setBumpShinyFullbright(U8 bump);
S32 setMediaFlags(U8 media_flags);
S32 setTexGen(U8 texGen);
S32 setMediaTexGen(U8 media);
S32 setGlow(F32 glow);
S32 setMaterialID(const LLMaterialID& pMaterialID);
S32 setMaterialParams(const LLMaterialPtr pMaterialParams);
virtual const LLUUID &getID() const { return mID; }
const LLColor4 &getColor() const { return mColor; }
const F32 getAlpha() const { return mColor.mV[VALPHA]; }
void getScale(F32 *s, F32 *t) const { *s = mScaleS; *t = mScaleT; }
F32 getScaleS() const { return mScaleS; }
F32 getScaleT() const { return mScaleT; }
void getOffset(F32 *s, F32 *t) const { *s = mOffsetS; *t = mOffsetT; }
F32 getOffsetS() const { return mOffsetS; }
F32 getOffsetT() const { return mOffsetT; }
F32 getRotation() const { return mRotation; }
void getRotation(F32 *theta) const { *theta = mRotation; }
U8 getBumpmap() const { return mBump & TEM_BUMP_MASK; }
U8 getFullbright() const { return (mBump>>TEM_FULLBRIGHT_SHIFT) & TEM_FULLBRIGHT_MASK; }
U8 getShiny() const { return (mBump>>TEM_SHINY_SHIFT) & TEM_SHINY_MASK; }
U8 getBumpShiny() const { return mBump & TEM_BUMP_SHINY_MASK; }
U8 getBumpShinyFullbright() const { return mBump; }
U8 getMediaFlags() const { return mMediaFlags & TEM_MEDIA_MASK; }
LLTextureEntry::e_texgen getTexGen() const { return LLTextureEntry::e_texgen(mMediaFlags & TEM_TEX_GEN_MASK); }
U8 getMediaTexGen() const { return mMediaFlags; }
F32 getGlow() const { return mGlow; }
const LLMaterialID& getMaterialID() const { return mMaterialID; };
const LLMaterialPtr getMaterialParams() const { return mMaterial; };
// *NOTE: it is possible for hasMedia() to return true, but getMediaData() to return NULL.
// CONVERSELY, it is also possible for hasMedia() to return false, but getMediaData()
// to NOT return NULL.
bool hasMedia() const { return (bool)(mMediaFlags & MF_HAS_MEDIA); }
LLMediaEntry* getMediaData() const { return mMediaEntry; }
// Completely change the media data on this texture entry.
void setMediaData(const LLMediaEntry &media_entry);
// Returns true if media data was updated, false if it was cleared
bool updateMediaData(const LLSD& media_data);
// Clears media data, and sets the media flags bit to 0
void clearMediaData();
// Merges the given LLSD of media fields with this media entry.
// Only those fields that are set that match the keys in
// LLMediaEntry will be affected. If no fields are set or if
// the LLSD is undefined, this is a no-op.
void mergeIntoMediaData(const LLSD& media_fields);
// Takes a media version string (an empty string or a previously-returned string)
// and returns a "touched" string, touched by agent_id
static std::string touchMediaVersionString(const std::string &in_version, const LLUUID &agent_id);
// Given a media version string, return the version
static U32 getVersionFromMediaVersionString(const std::string &version_string);
// Given a media version string, return the UUID of the agent
static LLUUID getAgentIDFromMediaVersionString(const std::string &version_string);
// Return whether or not the given string is actually a media version
static bool isMediaVersionString(const std::string &version_string);
// Media flags
enum { MF_NONE = 0x0, MF_HAS_MEDIA = 0x1 };
// GLTF asset
void setGLTFMaterial(LLGLTFMaterial* material, bool local_origin = true);
LLGLTFMaterial* getGLTFMaterial() const { return mGLTFMaterial; }
// GLTF override
LLGLTFMaterial* getGLTFMaterialOverride() const { return mGLTFMaterialOverrides; }
S32 setGLTFMaterialOverride(LLGLTFMaterial* mat);
// Clear most overrides so the render material better matches the material
// ID (preserve transforms). If the overrides become passthrough, set the
// overrides to nullptr.
S32 setBaseMaterial();
// GLTF render material
// nuanced behavior here -- if there is no render material, fall back to getGLTFMaterial, but ONLY for the getter, not the setter
LLGLTFMaterial* getGLTFRenderMaterial() const;
S32 setGLTFRenderMaterial(LLGLTFMaterial* mat);
public:
F32 mScaleS; // S, T offset
F32 mScaleT; // S, T offset
F32 mOffsetS; // S, T offset
F32 mOffsetT; // S, T offset
F32 mRotation; // anti-clockwise rotation in rad about the bottom left corner
static const LLTextureEntry null;
// LLSD key defines
static const char* OBJECT_ID_KEY;
static const char* OBJECT_MEDIA_DATA_KEY;
static const char* MEDIA_VERSION_KEY;
static const char* TEXTURE_INDEX_KEY;
static const char* TEXTURE_MEDIA_DATA_KEY;
protected:
bool mSelected;
LLUUID mID; // Texture GUID
LLColor4 mColor;
U8 mBump; // Bump map, shiny, and fullbright
U8 mMediaFlags; // replace with web page, movie, etc.
F32 mGlow;
bool mMaterialUpdatePending;
LLMaterialID mMaterialID;
LLMaterialPtr mMaterial;
// Reference to GLTF material asset state
// On the viewer, this should be the same LLGLTFMaterial instance that exists in LLGLTFMaterialList
LLPointer<LLGLTFMaterial> mGLTFMaterial;
// GLTF material parameter overrides -- the viewer will use this data to override material parameters
// set by the asset and store the results in mRenderGLTFMaterial
LLPointer<LLGLTFMaterial> mGLTFMaterialOverrides;
// GLTF material to use for rendering -- will always be an LLFetchedGLTFMaterial
LLPointer<LLGLTFMaterial> mGLTFRenderMaterial;
// Note the media data is not sent via the same message structure as the rest of the TE
LLMediaEntry* mMediaEntry; // The media data for the face
// NOTE: when adding new data to this class, in addition to adding it to the serializers asLLSD/fromLLSD and the
// message packers (e.g. LLPrimitive::packTEMessage) you must also implement its copy in LLPrimitive::copyTEs()
};
#endif
+61
View File
@@ -0,0 +1,61 @@
/**
* @file lltree_common.h
* @brief LLTree_gene_0 base class
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
// Common data for trees shared between simulator and viewer
#ifndef LL_LLTREE_COMMON_H
#define LL_LLTREE_COMMON_H
struct LLTree_gene_0
{
LLTree_gene_0()
: scale(0),
branches(0),
twist(0),
droop(0),
species(0),
trunk_depth(0),
branch_thickness(0),
max_depth(0),
scale_step(0)
{
}
//
// The genome for a tree, species 0
//
U8 scale; // Scales size of the tree ( / 50 = meter)
U8 branches; // When tree forks, how many branches emerge?
U8 twist; // twist about old branch axis for each branch (convert to degrees by dividing/255 * 180)
U8 droop; // Droop away from old branch axis (convert to degrees by dividing/255 * 180)
U8 species; // Branch coloring index
U8 trunk_depth; // max recursions in the main trunk
U8 branch_thickness; // Scales thickness of trunk ( / 50 = meter)
U8 max_depth; // Branch Recursions to flower
U8 scale_step; // How much to multiply scale size at each recursion 0-1.f to convert to float
};
#endif
+205
View File
@@ -0,0 +1,205 @@
/**
* @file lltreeparams.cpp
* @brief implementation of the LLTreeParams class.
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "linden_common.h"
#include "llmath.h"
#include "lltreeparams.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
LLTreeParams::LLTreeParams()
{
// LL_INFOS() << "TREE PARAMS INITIALIZED" << LL_ENDL;
// init to basic something or other...
mShape = SR_TEND_FLAME;
mLevels = 1;
mScale = 15;
mScaleV = 0;
mBaseSize = 0.3f;
mRatio = 0.015f;
mRatioPower = 1.3f;
mLobes = 0;
mLobeDepth = .1f;
mFlare = 1.2f;
mFlarePercentage = 0.1f;
mFlareRes = 3;
//mAttractionUp = .5f;
mBaseSplits = 0;
mScale0 = 2.0;
mScaleV0 = 0.0;
// level 0
// scaling
mLength[0] = 1.0f;
mLengthV[0] = 0;
mTaper[0] = 1.0f;
// stem splits
mSegSplits[0] = 0.15f;
mSplitAngle[0] = 15.0f;
mSplitAngleV[0] = 10.0f;
mVertices[0] = 5;
// curvature
mCurveRes[0] = 4;
mCurve[0] = 0;
mCurveV[0] = 25;
mCurveBack[0] = 0;
// level 1
// scaling
mLength[1] = .3f;
mLengthV[1] = 0.05f;
mTaper[1] = 1.0f;
// angle params
mDownAngle[0] = 60.0f;
mDownAngleV[0] = 20.0f;
mRotate[0] = 140.0f;
mRotateV[0] = 0.0f;
mBranches[0] = 35;
mVertices[1] = 3;
// stem splits
mSplitAngle[1] = 0.0f;
mSplitAngleV[1] = 0.0f;
mSegSplits[1] = 0.0f;
// curvature
mCurveRes[1] = 4;
mCurve[1] = 0;
mCurveV[1] = 0;
mCurveBack[1] = 40;
// level 2
mLength[2] = .6f;
mLengthV[2] = .1f;
mTaper[2] = 1;
mDownAngle[1] = 30;
mDownAngleV[1] = 10;
mRotate[1] = 140;
mRotateV[1] = 0;
mBranches[1] = 20;
mVertices[2] = 3;
mSplitAngle[2] = 0;
mSplitAngleV[2] = 0;
mSegSplits[2] = 0;
mCurveRes[2] = 3;
mCurve[2] = 10;
mCurveV[2] = 150;
mCurveBack[2] = 0;
// level 3
mLength[3] = .4f;
mLengthV[3] = 0;
mTaper[3] = 1;
mDownAngle[2] = 45;
mDownAngleV[2] = 10;
mRotate[2] = 140;
mRotateV[2] = 0;
mBranches[2] = 5;
mVertices[3] = 3;
mSplitAngle[3] = 0;
mSplitAngleV[3] = 0;
mSegSplits[3] = 0;
mCurveRes[3] = 2;
mCurve[3] = 0;
mCurveV[3] = 0;
mCurveBack[3] = 0;
mLeaves = 0;
mLeafScaleX = 1.0f;
mLeafScaleY = 1.0f;
mLeafQuality = 1.25;
}
LLTreeParams::~LLTreeParams()
{
}
F32 LLTreeParams::ShapeRatio(EShapeRatio shape, F32 ratio)
{
switch (shape) {
case (SR_CONICAL):
return (.2f + .8f * ratio);
case (SR_SPHERICAL):
return (.2f + .8f * sinf(F_PI*ratio));
case (SR_HEMISPHERICAL):
return (.2f + .8f * sinf(.5f*F_PI*ratio));
case (SR_CYLINDRICAL):
return (1);
case (SR_TAPERED_CYLINDRICAL):
return (.5f + .5f * ratio);
case (SR_FLAME):
if (ratio <= .7f) {
return ratio/.7f;
} else {
return ((1 - ratio)/.3f);
}
case (SR_INVERSE_CONICAL):
return (1 - .8f * ratio);
case (SR_TEND_FLAME):
if (ratio <= .7) {
return (.5f + .5f*(ratio/.7f));
} else {
return (.5f + .5f * (1 - ratio)/.3f);
}
case (SR_ENVELOPE):
return 1;
default:
return 1;
}
}
+201
View File
@@ -0,0 +1,201 @@
/**
* @file lltreeparams.h
* @brief Implementation of the LLTreeParams class
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#ifndef LL_LLTREEPARAMS_H
#define LL_LLTREEPARAMS_H
/* for information about formulas associated with each type
* check the Weber + Penn paper
*/
enum EShapeRatio { SR_CONICAL, SR_SPHERICAL, SR_HEMISPHERICAL,
SR_CYLINDRICAL, SR_TAPERED_CYLINDRICAL, SR_FLAME,
SR_INVERSE_CONICAL, SR_TEND_FLAME, SR_ENVELOPE};
const U32 TREE_BLOCK_SIZE = 16;
const U8 MAX_NUM_LEVELS = 4;
class LLTreeParams
{
public:
LLTreeParams();
virtual ~LLTreeParams();
static F32 ShapeRatio(EShapeRatio shape, F32 ratio);
public:
// Variables with an asterick (*) cannot be modified without a re-instancing the
// trunk/branches
// Variables with an exclamation point (!) should probably not be modified outside and instead
// be tied directly to the species
// Variables with a tilde (~) should be tied to a range specified by the
// species type but still slightly controllable by the user
// GENERAL
//! determines length/radius of branches on tree -- ie: general 'shape'
EShapeRatio mShape;
//! number of recursive branch levels...limit to MAX_NUM_LEVELS
U8 mLevels;
//~ percentage of trunk at bottom without branches
F32 mBaseSize;
//~ the general scale + variance of tree
F32 mScale, mScaleV;
// general scale of tree
F32 mScale0, mScaleV0;
// LOBING
//*! number of peaks in the radial distance about the perimeter
U8 mLobes;
// even numbers = obvius symmetry ... use odd numbers
//*! magnitude of the variations as a fraction of the radius
F32 mLobeDepth;
// FLARE
//*! causes exponential expansion near base of trunk
F32 mFlare;
// scales radius base by min 1 to '1 + flare'
//*! percentage of the height of the trunk to flair -- likely less than baseSize
F32 mFlarePercentage;
//*! number of cross sections to make for the flair
U8 mFlareRes;
// LEAVES
//~ number of leaves to make
U8 mLeaves;
//! scale of the leaves
F32 mLeafScaleX, mLeafScaleY;
// quality/density of leaves
F32 mLeafQuality;
// several params don't have level 0 values
// BRANCHES
//~ angle away from parent
F32 mDownAngle[MAX_NUM_LEVELS - 1];
F32 mDownAngleV[MAX_NUM_LEVELS - 1];
//~ rotation around parent
F32 mRotate[MAX_NUM_LEVELS - 1];
F32 mRotateV[MAX_NUM_LEVELS - 1];
//~ num branches to spawn
U8 mBranches[MAX_NUM_LEVELS - 1];
//~ fractional length of branch. 1 = same length as parent branch
F32 mLength[MAX_NUM_LEVELS];
F32 mLengthV[MAX_NUM_LEVELS];
//!~ ratio and ratiopower determine radius/length
F32 mRatio, mRatioPower;
//*! taper of branches
F32 mTaper[MAX_NUM_LEVELS];
// 0 - non-tapering cylinder
// 1 - taper to a point
// 2 - taper to a spherical end
// 3 - periodic tapering (concatenated spheres)
//! SEG SPLITTING
U8 mBaseSplits; //! num segsplits at first curve cross section of trunk
F32 mSegSplits[MAX_NUM_LEVELS]; //~ splits per cross section. 1 = 1 split per section
F32 mSplitAngle[MAX_NUM_LEVELS]; //~ angle that splits go from parent (tempered by height)
F32 mSplitAngleV[MAX_NUM_LEVELS]; //~ variance of the splits
// CURVE
F32 mCurve[MAX_NUM_LEVELS]; //* general, 1-axis, overall curve of branch
F32 mCurveV[MAX_NUM_LEVELS]; //* curve variance at each cross section from general overall curve
U8 mCurveRes[MAX_NUM_LEVELS]; //* number of cross sections for curve
F32 mCurveBack[MAX_NUM_LEVELS]; //* curveback is amount branch curves back towards
// vertices per cross section
U8 mVertices[MAX_NUM_LEVELS];
// * no longer useful with pre-instanced branches
// specifies upward tendency of branches.
//F32 mAttractionUp;
// 1 = each branch will slightly go upwards by the end of the branch
// >1 = branches tend to go upwards earlier in their length
// pruning not implemented
// Prune parameters
//F32 mPruneRatio;
//F32 mPruneWidth, mPruneWidthPeak;
//F32 mPrunePowerLow, mPrunePowerHigh;
// NETWORK MESSAGE DATA
// Below is the outline for network messages regarding trees.
// The general idea is that a user would pick a general 'tree type' (the first variable)
// and then several 'open ended' variables like 'branchiness' and 'leafiness'.
// The effect that each of these general user variables would then affect the actual
// tree parameters (like # branches, # segsplits) in different ways depending on
// the tree type selected. Essentially, each tree type should have a formula
// that expands the 'leafiness' and 'branchiness' user variables into actual
// values for the tree parameters.
// These formulas aren't made yet and will certainly require some tuning. The
// estimates below for the # bits required seems like a good guesstimate.
// VARIABLE - # bits (range) - VARIABLES AFFECTED
// tree type - 5 bits (32) -
// branches - 6 bits (64) - numBranches
// splits - 6 bits (64) - segsplits
// leafiness - 3 bits (8) - numLeaves
// branch spread - 5 bits (32) - splitAngle(V), rotate(V)
// angle - 5 bits (32) - downAngle(V)
// branch length - 6 bits (64) - branchlength(V)
// randomness - 7 bits (128) - percentage for randomness of the (V)'s
// basesize - 5 bits (32) - basesize
// total - 48 bits
//U8 mNetSpecies;
};
#endif
+557
View File
@@ -0,0 +1,557 @@
/**
* @file llvolumemessage.cpp
* @brief LLVolumeMessage base class
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "linden_common.h"
#include "message.h"
#include "llvolumemessage.h"
#include "lldatapacker.h"
//============================================================================
// LLVolumeMessage is just a wrapper class; all members are static
//============================================================================
bool LLVolumeMessage::packProfileParams(
const LLProfileParams* params,
LLMessageSystem *mesgsys)
{
// Default to cylinder
static LLProfileParams defaultparams(LL_PCODE_PROFILE_CIRCLE, U16(0), U16(0), U16(0));
if (!params)
params = &defaultparams;
U8 tempU8;
U16 tempU16;
tempU8 = params->getCurveType();
mesgsys->addU8Fast(_PREHASH_ProfileCurve, tempU8);
tempU16 = (U16) ll_round( params->getBegin() / CUT_QUANTA);
mesgsys->addU16Fast(_PREHASH_ProfileBegin, tempU16);
tempU16 = 50000 - (U16) ll_round(params->getEnd() / CUT_QUANTA);
mesgsys->addU16Fast(_PREHASH_ProfileEnd, tempU16);
tempU16 = (U16) ll_round(params->getHollow() / HOLLOW_QUANTA);
mesgsys->addU16Fast(_PREHASH_ProfileHollow, tempU16);
return true;
}
bool LLVolumeMessage::packProfileParams(
const LLProfileParams* params,
LLDataPacker &dp)
{
// Default to cylinder
static LLProfileParams defaultparams(LL_PCODE_PROFILE_CIRCLE, U16(0), U16(0), U16(0));
if (!params)
params = &defaultparams;
U8 tempU8;
U16 tempU16;
tempU8 = params->getCurveType();
dp.packU8(tempU8, "Curve");
tempU16 = (U16) ll_round( params->getBegin() / CUT_QUANTA);
dp.packU16(tempU16, "Begin");
tempU16 = 50000 - (U16) ll_round(params->getEnd() / CUT_QUANTA);
dp.packU16(tempU16, "End");
tempU16 = (U16) ll_round(params->getHollow() / HOLLOW_QUANTA);
dp.packU16(tempU16, "Hollow");
return true;
}
bool LLVolumeMessage::unpackProfileParams(
LLProfileParams* params,
LLMessageSystem* mesgsys,
char const* block_name,
S32 block_num)
{
bool ok = true;
U8 temp_u8;
U16 temp_u16;
F32 temp_f32;
mesgsys->getU8Fast(block_name, _PREHASH_ProfileCurve, temp_u8, block_num);
params->setCurveType(temp_u8);
mesgsys->getU16Fast(block_name, _PREHASH_ProfileBegin, temp_u16, block_num);
temp_f32 = temp_u16 * CUT_QUANTA;
if (temp_f32 > 1.f)
{
LL_WARNS() << "Profile begin out of range: " << temp_f32
<< ". Clamping to 0.0." << LL_ENDL;
temp_f32 = 0.f;
ok = false;
}
params->setBegin(temp_f32);
mesgsys->getU16Fast(block_name, _PREHASH_ProfileEnd, temp_u16, block_num);
temp_f32 = temp_u16 * CUT_QUANTA;
if (temp_f32 > 1.f)
{
LL_WARNS() << "Profile end out of range: " << 1.f - temp_f32
<< ". Clamping to 1.0." << LL_ENDL;
temp_f32 = 1.f;
ok = false;
}
params->setEnd(1.f - temp_f32);
mesgsys->getU16Fast(block_name, _PREHASH_ProfileHollow, temp_u16, block_num);
temp_f32 = temp_u16 * HOLLOW_QUANTA;
if (temp_f32 > 1.f)
{
LL_WARNS() << "Profile hollow out of range: " << temp_f32
<< ". Clamping to 0.0." << LL_ENDL;
temp_f32 = 0.f;
ok = false;
}
params->setHollow(temp_f32);
/*
LL_INFOS() << "Unpacking Profile Block " << block_num << LL_ENDL;
LL_INFOS() << "Curve: " << (U32)getCurve() << LL_ENDL;
LL_INFOS() << "Begin: " << getBegin() << LL_ENDL;
LL_INFOS() << "End: " << getEnd() << LL_ENDL;
LL_INFOS() << "Hollow: " << getHollow() << LL_ENDL;
*/
return ok;
}
bool LLVolumeMessage::unpackProfileParams(
LLProfileParams* params,
LLDataPacker &dp)
{
bool ok = true;
U8 temp_u8;
U16 temp_u16;
F32 temp_f32;
dp.unpackU8(temp_u8, "Curve");
params->setCurveType(temp_u8);
dp.unpackU16(temp_u16, "Begin");
temp_f32 = temp_u16 * CUT_QUANTA;
if (temp_f32 > 1.f)
{
LL_WARNS() << "Profile begin out of range: " << temp_f32 << LL_ENDL;
LL_WARNS() << "Clamping to 0.0" << LL_ENDL;
temp_f32 = 0.f;
ok = false;
}
params->setBegin(temp_f32);
dp.unpackU16(temp_u16, "End");
temp_f32 = temp_u16 * CUT_QUANTA;
if (temp_f32 > 1.f)
{
LL_WARNS() << "Profile end out of range: " << 1.f - temp_f32 << LL_ENDL;
LL_WARNS() << "Clamping to 1.0" << LL_ENDL;
temp_f32 = 1.f;
ok = false;
}
params->setEnd(1.f - temp_f32);
dp.unpackU16(temp_u16, "Hollow");
temp_f32 = temp_u16 * HOLLOW_QUANTA;
if (temp_f32 > 1.f)
{
LL_WARNS() << "Profile hollow out of range: " << temp_f32 << LL_ENDL;
LL_WARNS() << "Clamping to 0.0" << LL_ENDL;
temp_f32 = 0.f;
ok = false;
}
params->setHollow(temp_f32);
return ok;
}
//============================================================================
// Quantization:
// For cut begin, range is 0 to 1, quanta is 0.005, 0 maps to 0
// For cut end, range is 0 to 1, quanta is 0.005, 1 maps to 0
// For scale, range is 0 to 1, quanta is 0.01, 0 maps to 0, 1 maps to 100
// For shear, range is -0.5 to 0.5, quanta is 0.01, 0 maps to 0
// For taper, range is -1 to 1, quanta is 0.01, 0 maps to 0
bool LLVolumeMessage::packPathParams(
const LLPathParams* params,
LLMessageSystem *mesgsys)
{
// Default to cylinder with no cut, top same size as bottom, no shear, no twist
static LLPathParams defaultparams(LL_PCODE_PATH_LINE, U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), 0);
if (!params)
params = &defaultparams;
U8 curve = params->getCurveType();
mesgsys->addU8Fast(_PREHASH_PathCurve, curve);
U16 begin = (U16) ll_round(params->getBegin() / CUT_QUANTA);
mesgsys->addU16Fast(_PREHASH_PathBegin, begin);
U16 end = 50000 - (U16) ll_round(params->getEnd() / CUT_QUANTA);
mesgsys->addU16Fast(_PREHASH_PathEnd, end);
// Avoid truncation problem with direct F32->U8 cast.
// (e.g., (U8) (0.50 / 0.01) = (U8) 49.9999999 = 49 not 50.
U8 pack_scale_x = 200 - (U8) ll_round(params->getScaleX() / SCALE_QUANTA);
mesgsys->addU8Fast(_PREHASH_PathScaleX, pack_scale_x );
U8 pack_scale_y = 200 - (U8) ll_round(params->getScaleY() / SCALE_QUANTA);
mesgsys->addU8Fast(_PREHASH_PathScaleY, pack_scale_y );
U8 pack_shear_x = (U8) ll_round(params->getShearX() / SHEAR_QUANTA);
mesgsys->addU8Fast(_PREHASH_PathShearX, pack_shear_x );
U8 pack_shear_y = (U8) ll_round(params->getShearY() / SHEAR_QUANTA);
mesgsys->addU8Fast(_PREHASH_PathShearY, pack_shear_y );
S8 twist = (S8) ll_round(params->getTwist() / SCALE_QUANTA);
mesgsys->addS8Fast(_PREHASH_PathTwist, twist);
S8 twist_begin = (S8) ll_round(params->getTwistBegin() / SCALE_QUANTA);
mesgsys->addS8Fast(_PREHASH_PathTwistBegin, twist_begin);
S8 radius_offset = (S8) ll_round(params->getRadiusOffset() / SCALE_QUANTA);
mesgsys->addS8Fast(_PREHASH_PathRadiusOffset, radius_offset);
S8 taper_x = (S8) ll_round(params->getTaperX() / TAPER_QUANTA);
mesgsys->addS8Fast(_PREHASH_PathTaperX, taper_x);
S8 taper_y = (S8) ll_round(params->getTaperY() / TAPER_QUANTA);
mesgsys->addS8Fast(_PREHASH_PathTaperY, taper_y);
U8 revolutions = (U8) ll_round( (params->getRevolutions() - 1.0f) / REV_QUANTA);
mesgsys->addU8Fast(_PREHASH_PathRevolutions, revolutions);
S8 skew = (S8) ll_round(params->getSkew() / SCALE_QUANTA);
mesgsys->addS8Fast(_PREHASH_PathSkew, skew);
return true;
}
bool LLVolumeMessage::packPathParams(
const LLPathParams* params,
LLDataPacker &dp)
{
// Default to cylinder with no cut, top same size as bottom, no shear, no twist
static LLPathParams defaultparams(LL_PCODE_PATH_LINE, U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), 0);
if (!params)
params = &defaultparams;
U8 curve = params->getCurveType();
dp.packU8(curve, "Curve");
U16 begin = (U16) ll_round(params->getBegin() / CUT_QUANTA);
dp.packU16(begin, "Begin");
U16 end = 50000 - (U16) ll_round(params->getEnd() / CUT_QUANTA);
dp.packU16(end, "End");
// Avoid truncation problem with direct F32->U8 cast.
// (e.g., (U8) (0.50 / 0.01) = (U8) 49.9999999 = 49 not 50.
U8 pack_scale_x = 200 - (U8) ll_round(params->getScaleX() / SCALE_QUANTA);
dp.packU8(pack_scale_x, "ScaleX");
U8 pack_scale_y = 200 - (U8) ll_round(params->getScaleY() / SCALE_QUANTA);
dp.packU8(pack_scale_y, "ScaleY");
S8 pack_shear_x = (S8) ll_round(params->getShearX() / SHEAR_QUANTA);
dp.packU8(*(U8 *)&pack_shear_x, "ShearX");
S8 pack_shear_y = (S8) ll_round(params->getShearY() / SHEAR_QUANTA);
dp.packU8(*(U8 *)&pack_shear_y, "ShearY");
S8 twist = (S8) ll_round(params->getTwist() / SCALE_QUANTA);
dp.packU8(*(U8 *)&twist, "Twist");
S8 twist_begin = (S8) ll_round(params->getTwistBegin() / SCALE_QUANTA);
dp.packU8(*(U8 *)&twist_begin, "TwistBegin");
S8 radius_offset = (S8) ll_round(params->getRadiusOffset() / SCALE_QUANTA);
dp.packU8(*(U8 *)&radius_offset, "RadiusOffset");
S8 taper_x = (S8) ll_round(params->getTaperX() / TAPER_QUANTA);
dp.packU8(*(U8 *)&taper_x, "TaperX");
S8 taper_y = (S8) ll_round(params->getTaperY() / TAPER_QUANTA);
dp.packU8(*(U8 *)&taper_y, "TaperY");
U8 revolutions = (U8) ll_round( (params->getRevolutions() - 1.0f) / REV_QUANTA);
dp.packU8(*(U8 *)&revolutions, "Revolutions");
S8 skew = (S8) ll_round(params->getSkew() / SCALE_QUANTA);
dp.packU8(*(U8 *)&skew, "Skew");
return true;
}
bool LLVolumeMessage::unpackPathParams(
LLPathParams* params,
LLMessageSystem* mesgsys,
char const* block_name,
S32 block_num)
{
U8 curve;
mesgsys->getU8Fast(block_name, _PREHASH_PathCurve, curve, block_num);
params->setCurveType(curve);
U16 begin;
mesgsys->getU16Fast(block_name, _PREHASH_PathBegin, begin, block_num);
params->setBegin((F32)(begin * CUT_QUANTA));
U16 end;
mesgsys->getU16Fast(block_name, _PREHASH_PathEnd, end, block_num);
params->setEnd((F32)((50000 - end) * CUT_QUANTA));
U8 pack_scale_x, pack_scale_y;
mesgsys->getU8Fast(block_name, _PREHASH_PathScaleX, pack_scale_x, block_num);
mesgsys->getU8Fast(block_name, _PREHASH_PathScaleY, pack_scale_y, block_num);
F32 x = (F32) (200 - pack_scale_x) * SCALE_QUANTA;
F32 y = (F32) (200 - pack_scale_y) * SCALE_QUANTA;
params->setScale( x, y );
S8 shear_x_quant, shear_y_quant;
mesgsys->getS8Fast(block_name, _PREHASH_PathShearX, shear_x_quant, block_num);
mesgsys->getS8Fast(block_name, _PREHASH_PathShearY, shear_y_quant, block_num);
F32 shear_x = (F32) shear_x_quant * SHEAR_QUANTA;
F32 shear_y = (F32) shear_y_quant * SHEAR_QUANTA;
params->setShear( shear_x, shear_y );
S8 twist;
mesgsys->getS8Fast(block_name, _PREHASH_PathTwist, twist, block_num );
params->setTwist((F32)(twist * SCALE_QUANTA));
S8 twist_begin;
mesgsys->getS8Fast(block_name, _PREHASH_PathTwistBegin, twist_begin, block_num );
params->setTwistBegin((F32)(twist_begin * SCALE_QUANTA));
S8 radius_offset;
mesgsys->getS8Fast(block_name, _PREHASH_PathRadiusOffset, radius_offset, block_num );
params->setRadiusOffset((F32)(radius_offset * SCALE_QUANTA));
S8 taper_x_quant, taper_y_quant;
mesgsys->getS8Fast(block_name, _PREHASH_PathTaperX, taper_x_quant, block_num );
mesgsys->getS8Fast(block_name, _PREHASH_PathTaperY, taper_y_quant, block_num );
F32 taper_x = (F32)(taper_x_quant * TAPER_QUANTA);
F32 taper_y = (F32)(taper_y_quant * TAPER_QUANTA);
params->setTaper( taper_x, taper_y );
U8 revolutions;
mesgsys->getU8Fast(block_name, _PREHASH_PathRevolutions, revolutions, block_num );
params->setRevolutions((F32)(revolutions * REV_QUANTA + 1.0f));
S8 skew;
mesgsys->getS8Fast(block_name, _PREHASH_PathSkew, skew, block_num );
params->setSkew((F32)(skew * SCALE_QUANTA));
/*
LL_INFOS() << "Unpacking Path Block " << block_num << LL_ENDL;
LL_INFOS() << "Curve: " << (U32)params->getCurve() << LL_ENDL;
LL_INFOS() << "Begin: " << params->getBegin() << LL_ENDL;
LL_INFOS() << "End: " << params->getEnd() << LL_ENDL;
LL_INFOS() << "Scale: " << params->getScale() << LL_ENDL;
LL_INFOS() << "Twist: " << params->getTwist() << LL_ENDL;
*/
return true;
}
bool LLVolumeMessage::unpackPathParams(LLPathParams* params, LLDataPacker &dp)
{
U8 value;
S8 svalue;
U16 temp_u16;
dp.unpackU8(value, "Curve");
params->setCurveType( value );
dp.unpackU16(temp_u16, "Begin");
params->setBegin((F32)(temp_u16 * CUT_QUANTA));
dp.unpackU16(temp_u16, "End");
params->setEnd((F32)((50000 - temp_u16) * CUT_QUANTA));
dp.unpackU8(value, "ScaleX");
F32 x = (F32) (200 - value) * SCALE_QUANTA;
dp.unpackU8(value, "ScaleY");
F32 y = (F32) (200 - value) * SCALE_QUANTA;
params->setScale( x, y );
dp.unpackU8(value, "ShearX");
svalue = *(S8 *)&value;
F32 shear_x = (F32) svalue * SHEAR_QUANTA;
dp.unpackU8(value, "ShearY");
svalue = *(S8 *)&value;
F32 shear_y = (F32) svalue * SHEAR_QUANTA;
params->setShear( shear_x, shear_y );
dp.unpackU8(value, "Twist");
svalue = *(S8 *)&value;
params->setTwist((F32)(svalue * SCALE_QUANTA));
dp.unpackU8(value, "TwistBegin");
svalue = *(S8 *)&value;
params->setTwistBegin((F32)(svalue * SCALE_QUANTA));
dp.unpackU8(value, "RadiusOffset");
svalue = *(S8 *)&value;
params->setRadiusOffset((F32)(svalue * SCALE_QUANTA));
dp.unpackU8(value, "TaperX");
svalue = *(S8 *)&value;
params->setTaperX((F32)(svalue * TAPER_QUANTA));
dp.unpackU8(value, "TaperY");
svalue = *(S8 *)&value;
params->setTaperY((F32)(svalue * TAPER_QUANTA));
dp.unpackU8(value, "Revolutions");
params->setRevolutions((F32)(value * REV_QUANTA + 1.0f));
dp.unpackU8(value, "Skew");
svalue = *(S8 *)&value;
params->setSkew((F32)(svalue * SCALE_QUANTA));
return true;
}
//============================================================================
// static
bool LLVolumeMessage::constrainVolumeParams(LLVolumeParams& params)
{
U32 bad = 0;
// This is called immediately after an unpack. feed the raw data
// through the checked setters to constraint it to a valid set of
// volume params.
bad |= params.setType(params.getProfileParams().getCurveType(),
params.getPathParams().getCurveType()) ? 0 : 1;
bad |= params.setBeginAndEndS(params.getProfileParams().getBegin(),
params.getProfileParams().getEnd()) ? 0 : 2;
bad |= params.setBeginAndEndT(params.getPathParams().getBegin(),
params.getPathParams().getEnd()) ? 0 : 4;
bad |= params.setHollow(params.getProfileParams().getHollow()) ? 0 : 8;
bad |= params.setTwistBegin(params.getPathParams().getTwistBegin()) ? 0 : 0x10;
bad |= params.setTwistEnd(params.getPathParams().getTwistEnd()) ? 0 : 0x20;
bad |= params.setRatio(params.getPathParams().getScaleX(),
params.getPathParams().getScaleY()) ? 0 : 0x40;
bad |= params.setShear(params.getPathParams().getShearX(),
params.getPathParams().getShearY()) ? 0 : 0x80;
bad |= params.setTaper(params.getPathParams().getTaperX(),
params.getPathParams().getTaperY()) ? 0 : 0x100;
bad |= params.setRevolutions(params.getPathParams().getRevolutions()) ? 0 : 0x200;
bad |= params.setRadiusOffset(params.getPathParams().getRadiusOffset()) ? 0 : 0x400;
bad |= params.setSkew(params.getPathParams().getSkew()) ? 0 : 0x800;
if (bad)
{
LL_WARNS() << "LLVolumeMessage::constrainVolumeParams() - "
<< "forced to constrain incoming volume params: "
<< llformat("0x%04x", bad) << LL_ENDL;
}
return bad == 0;
}
bool LLVolumeMessage::packVolumeParams(const LLVolumeParams* params, LLMessageSystem *mesgsys)
{
// LL_INFOS() << "pack volume" << LL_ENDL;
if (params)
{
packPathParams(&params->getPathParams(), mesgsys);
packProfileParams(&params->getProfileParams(), mesgsys);
}
else
{
packPathParams(0, mesgsys);
packProfileParams(0, mesgsys);
}
return true;
}
bool LLVolumeMessage::packVolumeParams(const LLVolumeParams* params, LLDataPacker &dp)
{
// LL_INFOS() << "pack volume" << LL_ENDL;
if (params)
{
packPathParams(&params->getPathParams(), dp);
packProfileParams(&params->getProfileParams(), dp);
}
else
{
packPathParams(0, dp);
packProfileParams(0, dp);
}
return true;
}
bool LLVolumeMessage::unpackVolumeParams(
LLVolumeParams* params,
LLMessageSystem* mesgsys,
char const* block_name,
S32 block_num)
{
bool ok = true;
ok &= unpackPathParams(
&params->getPathParams(),
mesgsys,
block_name,
block_num);
ok &= unpackProfileParams(
&params->getProfileParams(),
mesgsys,
block_name,
block_num);
ok &= constrainVolumeParams(*params);
return ok;
}
bool LLVolumeMessage::unpackVolumeParams(
LLVolumeParams* params,
LLDataPacker &dp)
{
bool ok = true;
ok &= unpackPathParams(&params->getPathParams(), dp);
ok &= unpackProfileParams(&params->getProfileParams(), dp);
ok &= constrainVolumeParams(*params);
return ok;
}
//============================================================================
+92
View File
@@ -0,0 +1,92 @@
/**
* @file llvolumemessage.h
* @brief LLVolumeMessage base class
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#ifndef LL_LLVOLUMEMESSAGE_H
#define LL_LLVOLUMEMESSAGE_H
#include "llvolume.h"
class LLMessageSystem;
class LLDataPacker;
// wrapper class for some volume/message functions
class LLVolumeMessage
{
protected:
// The profile and path params are protected since they do not do
// any kind of parameter validation or clamping. Use the public
// pack and unpack volume param methods below
static bool packProfileParams(
const LLProfileParams* params,
LLMessageSystem* mesgsys);
static bool packProfileParams(
const LLProfileParams* params,
LLDataPacker& dp);
static bool unpackProfileParams(
LLProfileParams* params,
LLMessageSystem* mesgsys,
char const* block_name,
S32 block_num = 0);
static bool unpackProfileParams(LLProfileParams* params, LLDataPacker& dp);
static bool packPathParams(
const LLPathParams* params,
LLMessageSystem* mesgsys);
static bool packPathParams(const LLPathParams* params, LLDataPacker& dp);
static bool unpackPathParams(
LLPathParams* params,
LLMessageSystem* mesgsys,
char const* block_name,
S32 block_num = 0);
static bool unpackPathParams(LLPathParams* params, LLDataPacker& dp);
public:
/**
* @brief This method constrains any volume params to make them valid.
*
* @param[in,out] Possibly invalid params in, always valid out.
* @return Returns true if the in params were valid, and therefore
* unchanged.
*/
static bool constrainVolumeParams(LLVolumeParams& params);
static bool packVolumeParams(
const LLVolumeParams* params,
LLMessageSystem* mesgsys);
static bool packVolumeParams(
const LLVolumeParams* params,
LLDataPacker& dp);
static bool unpackVolumeParams(
LLVolumeParams* params,
LLMessageSystem* mesgsys,
char const* block_name,
S32 block_num = 0);
static bool unpackVolumeParams(LLVolumeParams* params, LLDataPacker &dp);
};
#endif // LL_LLVOLUMEMESSAGE_H
+40
View File
@@ -0,0 +1,40 @@
/**
* @file material_codes.cpp
* @brief Material_codes definitions
*
* $LicenseInfo:firstyear=2000&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "linden_common.h"
#include "material_codes.h"
#include "lluuid.h"
const LLUUID LL_DEFAULT_STONE_UUID("87c5765b-aa26-43eb-b8c6-c09a1ca6208e");
const LLUUID LL_DEFAULT_METAL_UUID("6f3c53e9-ba60-4010-8f3e-30f51a762476");
const LLUUID LL_DEFAULT_GLASS_UUID("b4ba225c-373f-446d-9f7e-6cb7b5cf9b3d");
const LLUUID LL_DEFAULT_WOOD_UUID("89556747-24cb-43ed-920b-47caed15465f");
const LLUUID LL_DEFAULT_FLESH_UUID("80736669-e4b9-450e-8890-d5169f988a50");
const LLUUID LL_DEFAULT_PLASTIC_UUID("304fcb4e-7d33-4339-ba80-76d3d22dc11a");
const LLUUID LL_DEFAULT_RUBBER_UUID("9fae0bc5-666d-477e-9f70-84e8556ec867");
const LLUUID LL_DEFAULT_LIGHT_UUID("00000000-0000-0000-0000-000000000000");
+54
View File
@@ -0,0 +1,54 @@
/**
* @file material_codes.h
* @brief Material_codes definitions
*
* $LicenseInfo:firstyear=2000&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#ifndef LL_MATERIAL_CODES_H
#define LL_MATERIAL_CODES_H
class LLUUID;
// material types
const U8 LL_MCODE_STONE = 0;
const U8 LL_MCODE_METAL = 1;
const U8 LL_MCODE_GLASS = 2;
const U8 LL_MCODE_WOOD = 3;
const U8 LL_MCODE_FLESH = 4;
const U8 LL_MCODE_PLASTIC = 5;
const U8 LL_MCODE_RUBBER = 6;
const U8 LL_MCODE_LIGHT = 7;
const U8 LL_MCODE_END = 8;
const U8 LL_MCODE_MASK = 0x0F;
// *NOTE: Define these in .cpp file to reduce duplicate instances
extern const LLUUID LL_DEFAULT_STONE_UUID;
extern const LLUUID LL_DEFAULT_METAL_UUID;
extern const LLUUID LL_DEFAULT_GLASS_UUID;
extern const LLUUID LL_DEFAULT_WOOD_UUID;
extern const LLUUID LL_DEFAULT_FLESH_UUID;
extern const LLUUID LL_DEFAULT_PLASTIC_UUID;
extern const LLUUID LL_DEFAULT_RUBBER_UUID;
extern const LLUUID LL_DEFAULT_LIGHT_UUID;
#endif
+84
View File
@@ -0,0 +1,84 @@
/**
* @file object_flags.h
* @brief Flags for object creation and transmission
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#ifndef LL_OBJECT_FLAGS_H
#define LL_OBJECT_FLAGS_H
// downstream flags from sim->viewer
const U32 FLAGS_USE_PHYSICS = (1U << 0);
const U32 FLAGS_CREATE_SELECTED = (1U << 1);
const U32 FLAGS_OBJECT_MODIFY = (1U << 2);
const U32 FLAGS_OBJECT_COPY = (1U << 3);
const U32 FLAGS_OBJECT_ANY_OWNER = (1U << 4);
const U32 FLAGS_OBJECT_YOU_OWNER = (1U << 5);
const U32 FLAGS_SCRIPTED = (1U << 6);
const U32 FLAGS_HANDLE_TOUCH = (1U << 7);
const U32 FLAGS_OBJECT_MOVE = (1U << 8);
const U32 FLAGS_TAKES_MONEY = (1U << 9);
const U32 FLAGS_PHANTOM = (1U << 10);
const U32 FLAGS_INVENTORY_EMPTY = (1U << 11);
const U32 FLAGS_AFFECTS_NAVMESH = (1U << 12);
const U32 FLAGS_CHARACTER = (1U << 13);
const U32 FLAGS_VOLUME_DETECT = (1U << 14);
const U32 FLAGS_INCLUDE_IN_SEARCH = (1U << 15);
const U32 FLAGS_ALLOW_INVENTORY_DROP = (1U << 16);
const U32 FLAGS_OBJECT_TRANSFER = (1U << 17);
const U32 FLAGS_OBJECT_GROUP_OWNED = (1U << 18);
//const U32 FLAGS_UNUSED_000 = (1U << 19); // was FLAGS_OBJECT_YOU_OFFICER
const U32 FLAGS_CAMERA_DECOUPLED = (1U << 20);
const U32 FLAGS_ANIM_SOURCE = (1U << 21);
const U32 FLAGS_CAMERA_SOURCE = (1U << 22);
//const U32 FLAGS_UNUSED_001 = (1U << 23); // was FLAGS_CAST_SHADOWS
//const U32 FLAGS_UNUSED_002 = (1U << 24);
//const U32 FLAGS_UNUSED_003 = (1U << 25);
//const U32 FLAGS_UNUSED_004 = (1U << 26);
//const U32 FLAGS_UNUSED_005 = (1U << 27);
const U32 FLAGS_OBJECT_OWNER_MODIFY = (1U << 28);
const U32 FLAGS_TEMPORARY_ON_REZ = (1U << 29);
//const U32 FLAGS_UNUSED_006 = (1U << 30); // was FLAGS_TEMPORARY
//const U32 FLAGS_UNUSED_007 = (1U << 31); // was FLAGS_ZLIB_COMPRESSED
const U32 FLAGS_LOCAL = FLAGS_ANIM_SOURCE | FLAGS_CAMERA_SOURCE;
const U32 FLAGS_WORLD = FLAGS_USE_PHYSICS | FLAGS_PHANTOM | FLAGS_TEMPORARY_ON_REZ;
typedef enum e_havok_joint_type
{
HJT_INVALID = 0,
HJT_HINGE = 1,
HJT_POINT = 2,
// HJT_LPOINT = 3,
// HJT_WHEEL = 4,
HJT_EOF = 3
} EHavokJointType;
#endif
@@ -0,0 +1,441 @@
/**
* @file llgltfmaterial_test.cpp
*
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2023, 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 "linden_common.h"
#include "lltut.h"
#include <set>
#include "../llgltfmaterial.h"
#include "lluuid.cpp"
// Import & define single-header gltf import/export lib
#define TINYGLTF_IMPLEMENTATION
#define TINYGLTF_USE_CPP14 // default is C++ 11
// tinygltf by default loads image files using STB
#define STB_IMAGE_IMPLEMENTATION
// to use our own image loading:
// 1. replace this definition with TINYGLTF_NO_STB_IMAGE
// 2. provide image loader callback with TinyGLTF::SetImageLoader(LoadimageDataFunction LoadImageData, void *user_data)
// tinygltf saves image files using STB
#define STB_IMAGE_WRITE_IMPLEMENTATION
// similarly, can override with TINYGLTF_NO_STB_IMAGE_WRITE and TinyGLTF::SetImageWriter(fxn, data)
// Disable reading external images to prevent warnings and speed up the tests.
// We don't need this for the tests, but still need the filesystem
// implementation to be defined in order for llprimitive to link correctly.
#define TINYGLTF_NO_EXTERNAL_IMAGE 1
#include "tinygltf/tiny_gltf.h"
namespace tut
{
struct llgltfmaterial
{
};
typedef test_group<llgltfmaterial> llgltfmaterial_t;
typedef llgltfmaterial_t::object llgltfmaterial_object_t;
tut::llgltfmaterial_t tut_llgltfmaterial("llgltfmaterial");
// A positive 32-bit float with a long string representation
constexpr F32 test_fraction = 1.09045365e-32;
// A larger positive 32-bit float for values that get zeroed if below a threshold
constexpr F32 test_fraction_big = 0.109045;
void apply_test_material_texture_ids(LLGLTFMaterial& material)
{
material.setBaseColorId(LLUUID::generateNewID());
material.setNormalId(LLUUID::generateNewID());
material.setOcclusionRoughnessMetallicId(LLUUID::generateNewID());
material.setEmissiveId(LLUUID::generateNewID());
}
void apply_test_material_texture_transforms(LLGLTFMaterial& material)
{
LLGLTFMaterial::TextureTransform test_transform;
test_transform.mOffset.mV[VX] = test_fraction;
test_transform.mOffset.mV[VY] = test_fraction;
test_transform.mScale.mV[VX] = test_fraction;
test_transform.mScale.mV[VY] = test_fraction;
test_transform.mRotation = test_fraction;
for (LLGLTFMaterial::TextureInfo i = LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; i = LLGLTFMaterial::TextureInfo((U32)i + 1))
{
material.setTextureOffset(i, test_transform.mOffset);
material.setTextureScale(i, test_transform.mScale);
material.setTextureRotation(i, test_transform.mRotation);
}
}
void apply_test_material_factors(LLGLTFMaterial& material)
{
material.setBaseColorFactor(LLColor4(test_fraction_big, test_fraction_big, test_fraction_big, test_fraction_big));
material.setEmissiveColorFactor(LLColor3(test_fraction_big, test_fraction_big, test_fraction_big));
material.setMetallicFactor(test_fraction);
material.setRoughnessFactor(test_fraction);
}
LLGLTFMaterial create_test_material()
{
LLGLTFMaterial material;
apply_test_material_texture_ids(material);
apply_test_material_texture_transforms(material);
apply_test_material_factors(material);
material.setAlphaCutoff(test_fraction);
// Because this is the default value, it should append to the extras field to mark it as an override
material.setAlphaMode(LLGLTFMaterial::ALPHA_MODE_OPAQUE, true);
// Because this is the default value, it should append to the extras field to mark it as an override
material.setDoubleSided(false, true);
return material;
}
void ensure_gltf_material_serialize(const std::string& ensure_suffix, const LLGLTFMaterial& material_in)
{
const std::string json_in = material_in.asJSON();
LLGLTFMaterial material_out;
std::string warn_msg;
std::string error_msg;
bool serialize_success = material_out.fromJSON(json_in, warn_msg, error_msg);
ensure_equals("LLGLTFMaterial serialization has no warnings: " + ensure_suffix, "", warn_msg);
ensure_equals("LLGLTFMaterial serialization has no errors: " + ensure_suffix, "", error_msg);
ensure("LLGLTFMaterial serializes successfully: " + ensure_suffix, serialize_success);
ensure("LLGLTFMaterial is preserved when deserialized: " + ensure_suffix, material_in == material_out);
const std::string json_out = material_out.asJSON();
ensure_equals("LLGLTFMaterial is preserved when serialized: " + ensure_suffix, json_in, json_out);
}
void ensure_gltf_material_trimmed(const std::string& material_json, const std::string& must_not_contain)
{
ensure("LLGLTFMaterial serialization trims property '" + must_not_contain + "'", material_json.find(must_not_contain) == std::string::npos);
}
// Test that GLTF material fields have not changed since these tests were written
template<> template<>
void llgltfmaterial_object_t::test<1>()
{
#if ADDRESS_SIZE != 32
#if LL_WINDOWS
// If any fields are added/changed, these tests should be updated (consider also updating ASSET_VERSION in LLGLTFMaterial)
// This test result will vary between compilers, so only test a single platform
ensure_equals("fields supported for GLTF (sizeof check)", sizeof(LLGLTFMaterial), 232);
#endif
#endif
ensure_equals("LLGLTFMaterial texture info count", (U32)LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT, 4);
}
// Test that occlusion and metallicRoughness are the same (They are different for asset validation. See lluploadmaterial.cpp)
template<> template<>
void llgltfmaterial_object_t::test<2>()
{
ensure_equals("LLGLTFMaterial occlusion does not differ from metallic roughness", LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS, LLGLTFMaterial::GLTF_TEXTURE_INFO_OCCLUSION);
}
// Ensure double sided and alpha mode overrides serialize as expected
template<> template<>
void llgltfmaterial_object_t::test<3>()
{
const bool doubleSideds[] { false, true };
const LLGLTFMaterial::AlphaMode alphaModes[] { LLGLTFMaterial::ALPHA_MODE_OPAQUE, LLGLTFMaterial::ALPHA_MODE_BLEND, LLGLTFMaterial::ALPHA_MODE_MASK };
const bool forOverrides[] { false, true };
for (bool doubleSided : doubleSideds)
{
for (bool forOverride : forOverrides)
{
LLGLTFMaterial material;
material.setDoubleSided(doubleSided, forOverride);
const bool overrideBit = (doubleSided == false) && forOverride;
ensure_equals("LLGLTFMaterial: double sided = " + std::to_string(doubleSided) + " override bit when forOverride = " + std::to_string(forOverride), material.mOverrideDoubleSided, overrideBit);
ensure_gltf_material_serialize("double sided = " + std::to_string(doubleSided), material);
}
}
for (LLGLTFMaterial::AlphaMode alphaMode : alphaModes)
{
for (bool forOverride : forOverrides)
{
LLGLTFMaterial material;
material.setAlphaMode(alphaMode, forOverride);
const bool overrideBit = (alphaMode == LLGLTFMaterial::ALPHA_MODE_OPAQUE) && forOverride;
ensure_equals("LLGLTFMaterial: alpha mode = " + std::to_string(alphaMode) + " override bit when forOverride = " + std::to_string(forOverride), material.mOverrideAlphaMode, overrideBit);
ensure_gltf_material_serialize("alpha mode = " + std::to_string(alphaMode), material);
}
}
}
// Test that a GLTF material's transform components serialize as expected
template<> template<>
void llgltfmaterial_object_t::test<4>()
{
LLGLTFMaterial material;
LLGLTFMaterial::TextureTransform& transform = material.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR];
transform.mOffset[VX] = 1.f;
transform.mOffset[VY] = 2.f;
transform.mScale[VX] = 0.05f;
transform.mScale[VY] = 100.f;
transform.mRotation = 1.571f;
ensure_gltf_material_serialize("material with transform", material);
}
// Test that a GLTF material avoids serializing a material unnecessarily
template<> template<>
void llgltfmaterial_object_t::test<5>()
{
{
const LLGLTFMaterial material;
const std::string material_json = material.asJSON();
ensure_gltf_material_trimmed(material_json, "pbrMetallicRoughness");
ensure_gltf_material_trimmed(material_json, "normalTexture");
ensure_gltf_material_trimmed(material_json, "emissiveTexture");
ensure_gltf_material_trimmed(material_json, "occlusionTexture");
}
{
LLGLTFMaterial metallic_factor_material;
metallic_factor_material.setMetallicFactor(0.5);
const std::string metallic_factor_material_json = metallic_factor_material.asJSON();
ensure_gltf_material_trimmed(metallic_factor_material_json, "baseColorTexture");
ensure_gltf_material_trimmed(metallic_factor_material_json, "metallicRoughnessTexture");
}
}
// Test that a GLTF material preserves values on serialization
template<> template<>
void llgltfmaterial_object_t::test<6>()
{
{
const LLGLTFMaterial full_material = create_test_material();
ensure_gltf_material_serialize("full material", full_material);
}
{
LLGLTFMaterial texture_ids_only_material;
apply_test_material_texture_ids(texture_ids_only_material);
ensure_gltf_material_serialize("material with texture IDs only", texture_ids_only_material);
}
{
LLGLTFMaterial texture_transforms_only_material;
apply_test_material_texture_ids(texture_transforms_only_material);
ensure_gltf_material_serialize("material with texture transforms only", texture_transforms_only_material);
}
{
LLGLTFMaterial factors_only_material;
apply_test_material_factors(factors_only_material);
ensure_gltf_material_serialize("material with scaling/tint factors only", factors_only_material);
}
}
// Test that sDefault is a no-op override
template<> template<>
void llgltfmaterial_object_t::test<7>()
{
const LLGLTFMaterial material_asset = create_test_material();
LLGLTFMaterial render_material = material_asset;
render_material.applyOverride(LLGLTFMaterial::sDefault);
ensure("LLGLTFMaterial: sDefault is a no-op override", material_asset == render_material);
}
// Test application of transform overrides
template<> template<>
void llgltfmaterial_object_t::test<8>()
{
LLGLTFMaterial override_material;
apply_test_material_texture_transforms(override_material);
LLGLTFMaterial render_material;
render_material.applyOverride(override_material);
ensure("LLGLTFMaterial: transform overrides", render_material == override_material);
}
// Test application of flag-based overrides
template<> template<>
void llgltfmaterial_object_t::test<9>()
{
{
LLGLTFMaterial override_material;
override_material.setAlphaMode(LLGLTFMaterial::ALPHA_MODE_BLEND, true);
override_material.setDoubleSided(true, true);
LLGLTFMaterial render_material;
render_material.applyOverride(override_material);
ensure("LLGLTFMaterial: extra overrides with non-default values applied over default", render_material == override_material);
}
{
LLGLTFMaterial override_material;
override_material.setAlphaMode(LLGLTFMaterial::ALPHA_MODE_OPAQUE, true);
override_material.setDoubleSided(false, true);
LLGLTFMaterial render_material;
override_material.setAlphaMode(LLGLTFMaterial::ALPHA_MODE_BLEND, false);
override_material.setDoubleSided(true, false);
render_material.applyOverride(override_material);
// Not interested in these flags for equality comparison
override_material.mOverrideDoubleSided = false;
override_material.mOverrideAlphaMode = false;
ensure("LLGLTFMaterial: extra overrides with default values applied over non-default", render_material == override_material);
}
}
// Test application of texture overrides
template<> template<>
void llgltfmaterial_object_t::test<10>()
{
const U32 texture_count = 2;
const LLUUID override_textures[texture_count] = { LLUUID::null, LLUUID::generateNewID() };
const LLUUID asset_textures[texture_count] = { LLUUID::generateNewID(), LLUUID::null };
for (U32 i = 0; i < texture_count; ++i)
{
LLGLTFMaterial override_material;
const LLUUID& override_texture = override_textures[i];
for (LLGLTFMaterial::TextureInfo j = LLGLTFMaterial::TextureInfo(0); j < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; j = LLGLTFMaterial::TextureInfo(U32(j) + 1))
{
override_material.setTextureId(j, override_texture, true);
}
LLGLTFMaterial render_material;
const LLUUID& asset_texture = asset_textures[i];
for (LLGLTFMaterial::TextureInfo j = LLGLTFMaterial::TextureInfo(0); j < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; j = LLGLTFMaterial::TextureInfo(U32(j) + 1))
{
render_material.setTextureId(j, asset_texture, false);
}
render_material.applyOverride(override_material);
for (LLGLTFMaterial::TextureInfo j = LLGLTFMaterial::TextureInfo(0); j < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; j = LLGLTFMaterial::TextureInfo(U32(j) + 1))
{
const LLUUID& render_texture = render_material.mTextureId[j];
ensure_equals("LLGLTFMaterial: Override texture ID " + override_texture.asString() + " replaces underlying texture ID " + asset_texture.asString(), render_texture, override_texture);
}
}
}
// Test non-persistence of default value flags in overrides
template<> template<>
void llgltfmaterial_object_t::test<11>()
{
const S32 non_default_alpha_modes[] = { LLGLTFMaterial::ALPHA_MODE_BLEND, LLGLTFMaterial::ALPHA_MODE_MASK };
for (S32 non_default_alpha_mode : non_default_alpha_modes)
{
LLGLTFMaterial material;
// Set default alpha mode
material.setAlphaMode(LLGLTFMaterial::ALPHA_MODE_OPAQUE, true);
ensure_equals("LLGLTFMaterial: alpha mode override flag set", material.mOverrideAlphaMode, true);
// Set non-default alpha mode
material.setAlphaMode(non_default_alpha_mode, true);
ensure_equals("LLGLTFMaterial: alpha mode override flag unset", material.mOverrideAlphaMode, false);
}
{
// Set default double sided
LLGLTFMaterial material;
material.setDoubleSided(false, true);
ensure_equals("LLGLTFMaterial: double sided override flag set", material.mOverrideDoubleSided, true);
// Set non-default double sided
material.setDoubleSided(true, true);
ensure_equals("LLGLTFMaterial: double sided override flag unset", material.mOverrideDoubleSided, false);
}
}
template<typename T>
void ensure_material_hash_pre(LLGLTFMaterial& material, T& material_field, const T new_value, const std::string& field_name)
{
ensure("LLGLTFMaterial: Hash: Test field " + field_name + " is part of the test material object", (
size_t(&material_field) >= size_t(&material) &&
(size_t(&material_field) + sizeof(material_field)) <= (size_t(&material) + sizeof(material))
));
ensure("LLGLTFMaterial: Hash: " + field_name + " differs and will cause a perturbation worth hashing", material_field != new_value);
}
template<typename T>
void ensure_material_hash_not_changed(LLGLTFMaterial& material, T& material_field, const T new_value, const std::string& field_name)
{
ensure_material_hash_pre(material, material_field, new_value, field_name);
const LLGLTFMaterial old_material = material;
material_field = new_value;
// If this test fails, consult LLGLTFMaterial::getHash, and optionally consult http://www.catb.org/esr/structure-packing/ for guidance on optimal memory packing (effectiveness is platform-dependent)
ensure_equals(("LLGLTFMaterial: Hash: Perturbing " + field_name + " to new value does NOT change the hash").c_str(), material.getHash(), old_material.getHash());
}
template<typename T>
void ensure_material_hash_changed(LLGLTFMaterial& material, T& material_field, const T new_value, const std::string& field_name)
{
ensure_material_hash_pre(material, material_field, new_value, field_name);
const LLGLTFMaterial old_material = material;
material_field = new_value;
// If this test fails, consult LLGLTFMaterial::getHash, and optionally consult http://www.catb.org/esr/structure-packing/ for guidance on optimal memory packing (effectiveness is platform-dependent)
ensure_not_equals(("LLGLTFMaterial: Hash: Perturbing " + field_name + " to new value changes the hash").c_str(), material.getHash(), old_material.getHash());
}
#define ENSURE_HASH_NOT_CHANGED(HASH_MAT, SOURCE_MAT, FIELD) ensure_material_hash_not_changed(HASH_MAT, HASH_MAT.FIELD, SOURCE_MAT.FIELD, #FIELD)
#define ENSURE_HASH_CHANGED(HASH_MAT, SOURCE_MAT, FIELD) ensure_material_hash_changed(HASH_MAT, HASH_MAT.FIELD, SOURCE_MAT.FIELD, #FIELD)
// Test LLGLTFMaterial::getHash, which is very sensitive to the ordering of fields
template<> template<>
void llgltfmaterial_object_t::test<12>()
{
// *NOTE: Due to direct manipulation of the fields of materials
// throughout this test, the resulting modified materials may not be
// compliant or properly serializable.
// Ensure all fields of source_mat are set to values that differ from
// LLGLTFMaterial::sDefault, even if that would result in an invalid
// material object.
LLGLTFMaterial source_mat = create_test_material();
source_mat.mTrackingIdToLocalTexture[LLUUID::generateNewID()] = LLUUID::generateNewID();
source_mat.mLocalTexDataDigest = 1;
source_mat.mAlphaMode = LLGLTFMaterial::ALPHA_MODE_MASK;
source_mat.mDoubleSided = true;
LLGLTFMaterial hash_mat;
ENSURE_HASH_NOT_CHANGED(hash_mat, source_mat, mTrackingIdToLocalTexture);
ENSURE_HASH_CHANGED(hash_mat, source_mat, mLocalTexDataDigest);
ENSURE_HASH_CHANGED(hash_mat, source_mat, mTextureId);
ENSURE_HASH_CHANGED(hash_mat, source_mat, mTextureTransform);
ENSURE_HASH_CHANGED(hash_mat, source_mat, mBaseColor);
ENSURE_HASH_CHANGED(hash_mat, source_mat, mEmissiveColor);
ENSURE_HASH_CHANGED(hash_mat, source_mat, mMetallicFactor);
ENSURE_HASH_CHANGED(hash_mat, source_mat, mRoughnessFactor);
ENSURE_HASH_CHANGED(hash_mat, source_mat, mAlphaCutoff);
ENSURE_HASH_CHANGED(hash_mat, source_mat, mAlphaMode);
ENSURE_HASH_CHANGED(hash_mat, source_mat, mDoubleSided);
ENSURE_HASH_CHANGED(hash_mat, source_mat, mOverrideDoubleSided);
ENSURE_HASH_CHANGED(hash_mat, source_mat, mOverrideAlphaMode);
}
}
@@ -0,0 +1,497 @@
/**
* @file llmediaentry_test.cpp
* @brief llmediaentry unit tests
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "linden_common.h"
#include "lltut.h"
#include <boost/lexical_cast.hpp>
#include "llstring.h"
#include "llsdutil.h"
#include "llsdserialize.h"
#include "../llmediaentry.h"
#include "indra_constants.h"
#define DEFAULT_MEDIA_ENTRY "<llsd>\n\
<map>\n\
<key>alt_image_enable</key>\n\
<boolean>0</boolean>\n\
<key>auto_loop</key>\n\
<boolean>0</boolean>\n\
<key>auto_play</key>\n\
<boolean>0</boolean>\n\
<key>auto_scale</key>\n\
<boolean>0</boolean>\n\
<key>auto_zoom</key>\n\
<boolean>0</boolean>\n\
<key>controls</key>\n\
<integer>0</integer>\n\
<key>current_url</key>\n\
<string />\n\
<key>first_click_interact</key>\n\
<boolean>0</boolean>\n\
<key>height_pixels</key>\n\
<integer>0</integer>\n\
<key>home_url</key>\n\
<string />\n\
<key>perms_control</key>\n\
<integer>7</integer>\n\
<key>perms_interact</key>\n\
<integer>7</integer>\n\
<key>whitelist_enable</key>\n\
<boolean>0</boolean>\n\
<key>width_pixels</key>\n\
<integer>0</integer>\n\
</map>\n\
</llsd>"
#define EMPTY_MEDIA_ENTRY "<llsd>\n\
<map>\n\
<key>alt_image_enable</key>\n\
<boolean>0</boolean>\n\
<key>auto_loop</key>\n\
<boolean>0</boolean>\n\
<key>auto_play</key>\n\
<boolean>0</boolean>\n\
<key>auto_scale</key>\n\
<boolean>0</boolean>\n\
<key>auto_zoom</key>\n\
<boolean>0</boolean>\n\
<key>controls</key>\n\
<integer>0</integer>\n\
<key>current_url</key>\n\
<string />\n\
<key>first_click_interact</key>\n\
<boolean>0</boolean>\n\
<key>height_pixels</key>\n\
<integer>0</integer>\n\
<key>home_url</key>\n\
<string />\n\
<key>perms_control</key>\n\
<integer>0</integer>\n\
<key>perms_interact</key>\n\
<integer>0</integer>\n\
<key>whitelist_enable</key>\n\
<boolean>0</boolean>\n\
<key>width_pixels</key>\n\
<integer>0</integer>\n\
</map>\n\
</llsd>"
#define PARTIAL_MEDIA_ENTRY(CURRENT_URL) "<llsd>\n\
<map>\n\
<key>alt_image_enable</key>\n\
<boolean>0</boolean>\n\
<key>auto_loop</key>\n\
<boolean>0</boolean>\n\
<key>auto_play</key>\n\
<boolean>0</boolean>\n\
<key>auto_scale</key>\n\
<boolean>0</boolean>\n\
<key>auto_zoom</key>\n\
<boolean>0</boolean>\n\
<key>controls</key>\n\
<integer>0</integer>\n\
<key>current_url</key>\n\
<string>" CURRENT_URL "</string>\n\
<key>first_click_interact</key>\n\
<boolean>0</boolean>\n\
<key>height_pixels</key>\n\
<integer>0</integer>\n\
<key>home_url</key>\n\
<string />\n\
<key>perms_control</key>\n\
<integer>0</integer>\n\
<key>perms_interact</key>\n\
<integer>0</integer>\n\
<key>whitelist_enable</key>\n\
<boolean>0</boolean>\n\
<key>width_pixels</key>\n\
<integer>0</integer>\n\
</map>\n\
</llsd>"
namespace tut
{
// this is fixture data that gets created before each test and destroyed
// after each test. this is where we put all of the setup/takedown code
// and data needed for each test.
struct MediaEntry_test
{
MediaEntry_test() {
emptyMediaEntryStr = EMPTY_MEDIA_ENTRY;
std::istringstream e(EMPTY_MEDIA_ENTRY);
LLSDSerialize::fromXML(emptyMediaEntryLLSD, e);
defaultMediaEntryStr = DEFAULT_MEDIA_ENTRY;
std::istringstream d(DEFAULT_MEDIA_ENTRY);
LLSDSerialize::fromXML(defaultMediaEntryLLSD, d);
}
std::string emptyMediaEntryStr;
LLSD emptyMediaEntryLLSD;
std::string defaultMediaEntryStr;
LLSD defaultMediaEntryLLSD;
};
typedef test_group<MediaEntry_test, 55> factory;
typedef factory::object object;
}
namespace
{
// this is for naming our tests to make pretty output
tut::factory tf("LLMediaEntry");
}
namespace tut
{
void ensure_llsd_equals(const std::string& msg, const LLSD& expected, const LLSD& actual)
{
if (!llsd_equals(expected, actual))
{
std::string message = msg;
message += ": actual: ";
message += ll_pretty_print_sd(actual);
message += "\n expected: ";
message += ll_pretty_print_sd(expected);
message += "\n";
ensure(message, false);
}
}
void ensure_string_equals(const std::string& msg, const std::string& expected, const std::string& actual)
{
if ( expected != actual )
{
std::string message = msg;
message += ": actual: ";
message += actual;
message += "\n expected: ";
message += expected;
message += "\n";
ensure(message, false);
}
}
void set_whitelist(LLMediaEntry &entry, const char *str)
{
std::vector<std::string> tokens;
LLStringUtil::getTokens(std::string(str), tokens, ",");
entry.setWhiteList(tokens);
}
void whitelist_test(int num, bool enable, const char *whitelist, const char *candidate_url, bool expected_pass)
{
std::string message = "Whitelist test " + std::to_string(num);
LLMediaEntry entry;
entry.setWhiteListEnable(enable);
set_whitelist(entry, whitelist);
bool passed_whitelist = entry.checkCandidateUrl(candidate_url);
if (passed_whitelist != expected_pass)
{
message += " failed: expected ";
message += (expected_pass) ? "" : "NOT ";
message += "to match\nwhitelist = ";
message += whitelist;
message += "\ncandidate_url = ";
message += candidate_url;
}
ensure(message, expected_pass == passed_whitelist);
}
void whitelist_test(int num, const char *whitelist, const char *candidate_url, bool expected_pass)
{
whitelist_test(num, true, whitelist, candidate_url, expected_pass);
}
void whitelist_test(int num, const char *whitelist, const char *candidate_url)
{
whitelist_test(num, true, whitelist, candidate_url, true);
}
template<> template<>
void object::test<1>()
{
set_test_name("Test LLMediaEntry Instantiation");
LLMediaEntry entry;
ensure_llsd_equals(get_test_name() + " failed", defaultMediaEntryLLSD, entry.asLLSD());
}
template<> template<>
void object::test<2>()
{
set_test_name("Test LLMediaEntry Instantiation from LLSD");
LLMediaEntry entry;
LLSD sd;
entry.fromLLSD(sd);
ensure_llsd_equals(get_test_name() + " failed", emptyMediaEntryLLSD, entry.asLLSD());
}
template<> template<>
void object::test<3>()
{
set_test_name("Test LLMediaEntry Partial Instantiation from LLSD");
LLMediaEntry entry;
LLSD sd;
sd[LLMediaEntry::CURRENT_URL_KEY] = "http://www.example.com";
entry.fromLLSD(sd);
LLSD golden;
std::istringstream p(PARTIAL_MEDIA_ENTRY("http://www.example.com"));
LLSDSerialize::fromXML(golden,p);
ensure_llsd_equals(get_test_name() + " failed", golden, entry.asLLSD());
}
template<> template<>
void object::test<4>()
{
set_test_name("Test LLMediaEntry::asLLSD()");
LLMediaEntry entry;
LLSD sd;
// Put some cruft in the LLSD
sd[LLMediaEntry::CURRENT_URL_KEY] = "http://www.example.com";
LLSD whitelist;
whitelist.append("*.example.com");
sd[LLMediaEntry::WHITELIST_KEY] = whitelist;
entry.asLLSD(sd);
ensure_llsd_equals(get_test_name() + " failed", defaultMediaEntryLLSD, sd);
}
template<> template<>
void object::test<5>()
{
set_test_name("Test LLMediaEntry::asLLSD() -> LLMediaEntry::fromLLSD()");
LLMediaEntry entry1, entry2;
// Add a whitelist to entry2
std::vector<std::string> whitelist;
whitelist.push_back("*.example.com");
entry2.setWhiteList(whitelist);
// Render entry1 (which has no whitelist) as an LLSD
LLSD sd;
entry1.asLLSD(sd);
// "read" that LLSD into entry 2
entry2.fromLLSD(sd);
ensure_llsd_equals(get_test_name() + " failed", defaultMediaEntryLLSD, entry2.asLLSD());
}
// limit tests
const char *URL_OK = "http://www.example.com";
const char *URL_TOO_BIG = "http://www.example.com.qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq";
template<> template<>
void object::test<6>()
{
set_test_name("Test Limits on setting current URL");
LLMediaEntry entry;
U32 status = entry.setCurrentURL(URL_OK);
ensure(get_test_name() + " ok failed", status == LSL_STATUS_OK);
status = entry.setCurrentURL(URL_TOO_BIG);
ensure(get_test_name() + " ok failed", status == LSL_STATUS_BOUNDS_ERROR);
}
template<> template<>
void object::test<7>()
{
set_test_name("Test Limits on setting home URL");
LLMediaEntry entry;
U32 status = entry.setHomeURL(URL_OK);
ensure(get_test_name() + " ok failed", status == LSL_STATUS_OK);
status = entry.setHomeURL(URL_TOO_BIG);
ensure(get_test_name() + " ok failed", status == LSL_STATUS_BOUNDS_ERROR);
}
template<> template<>
void object::test<8>()
{
set_test_name("Test Limits on setting whitelist");
// Test a valid list
LLMediaEntry entry;
std::vector<std::string> whitelist;
whitelist.push_back(std::string(URL_OK));
S32 status = entry.setWhiteList(whitelist);
ensure(get_test_name() + " invalid result", status == LSL_STATUS_OK);
ensure(get_test_name() + " failed", whitelist == entry.getWhiteList());
}
template<> template<>
void object::test<9>()
{
set_test_name("Test Limits on setting whitelist too big");
// Test an invalid list
LLMediaEntry entry;
std::vector<std::string> whitelist, empty;
whitelist.push_back(std::string(URL_OK));
whitelist.push_back(std::string(URL_TOO_BIG));
S32 status = entry.setWhiteList(whitelist);
ensure(get_test_name() + " invalid result", status == LSL_STATUS_BOUNDS_ERROR);
ensure(get_test_name() + " failed", empty == entry.getWhiteList());
}
template<> template<>
void object::test<10>()
{
set_test_name("Test Limits on setting whitelist too many");
// Test an invalid list
LLMediaEntry entry;
std::vector<std::string> whitelist, empty;
for (int i=0; i < LLMediaEntry::MAX_WHITELIST_SIZE+1; i++) {
whitelist.push_back("Q");
}
S32 status = entry.setWhiteList(whitelist);
ensure(get_test_name() + " invalid result", status == LSL_STATUS_BOUNDS_ERROR);
ensure(get_test_name() + " failed", empty == entry.getWhiteList());
}
template<> template<>
void object::test<11>()
{
set_test_name("Test to make sure both setWhiteList() functions behave the same");
// Test a valid list
std::vector<std::string> whitelist, empty;
LLSD whitelist_llsd;
whitelist.push_back(std::string(URL_OK));
whitelist_llsd.append(std::string(URL_OK));
LLMediaEntry entry1, entry2;
ensure(get_test_name() + " setWhiteList(s) don't match",
entry1.setWhiteList(whitelist) == LSL_STATUS_OK &&
entry2.setWhiteList(whitelist_llsd)== LSL_STATUS_OK );
ensure(get_test_name() + " failed",
entry1.getWhiteList() == entry2.getWhiteList());
}
template<> template<>
void object::test<12>()
{
set_test_name("Test to make sure both setWhiteList() functions behave the same");
// Test an invalid list
std::vector<std::string> whitelist, empty;
LLSD whitelist_llsd;
whitelist.push_back(std::string(URL_OK));
whitelist.push_back(std::string(URL_TOO_BIG));
whitelist_llsd.append(std::string(URL_OK));
whitelist_llsd.append(std::string(URL_TOO_BIG));
LLMediaEntry entry1, entry2;
ensure(get_test_name() + " setWhiteList(s) don't match",
entry1.setWhiteList(whitelist) == LSL_STATUS_BOUNDS_ERROR &&
entry2.setWhiteList(whitelist_llsd) == LSL_STATUS_BOUNDS_ERROR);
ensure(get_test_name() + " failed",
empty == entry1.getWhiteList() &&
empty == entry2.getWhiteList());
}
template<> template<>
void object::test<13>()
{
set_test_name("Test to make sure both setWhiteList() functions behave the same");
// Test an invalid list, too many
std::vector<std::string> whitelist, empty;
LLSD whitelist_llsd;
for (int i=0; i < LLMediaEntry::MAX_WHITELIST_SIZE+1; i++) {
whitelist.push_back("Q");
whitelist_llsd.append("Q");
}
LLMediaEntry entry1, entry2;
ensure(get_test_name() + " invalid result",
entry1.setWhiteList(whitelist) == LSL_STATUS_BOUNDS_ERROR &&
entry2.setWhiteList(whitelist_llsd) == LSL_STATUS_BOUNDS_ERROR);
ensure(get_test_name() + " failed",
empty == entry1.getWhiteList() &&
empty == entry2.getWhiteList());
}
template<> template<>
void object::test<14>()
{
// Whitelist check tests
int n=0;
// Check the "empty whitelist" case
whitelist_test(++n, "", "http://www.example.com", true);
// Check the "missing scheme" case
whitelist_test(++n, "www.example.com", "http://www.example.com", true);
// Check the "exactly the same" case
whitelist_test(++n, "http://example.com", "http://example.com", true);
// Check the enable flag
whitelist_test(++n, false, "www.example.com", "http://www.secondlife.com", true);
whitelist_test(++n, true, "www.example.com", "http://www.secondlife.com", false);
// Check permutations of trailing slash:
whitelist_test(++n, "http://www.example.com", "http://www.example.com/", true);
whitelist_test(++n, "http://www.example.com/", "http://www.example.com/", true);
whitelist_test(++n, "http://www.example.com/", "http://www.example.com", false);
whitelist_test(++n, "http://www.example.com", "http://www.example.com/foobar", true);
whitelist_test(++n, "http://www.example.com/", "http://www.example.com/foobar", false);
// More cases...
whitelist_test(++n, "http://example.com", "http://example.com/wiki", true);
whitelist_test(++n, "www.example.com", "http://www.example.com/help", true);
whitelist_test(++n, "http://www.example.com", "http://wwwexample.com", false);
whitelist_test(++n, "http://www.example.com", "http://www.example.com/wiki", true);
whitelist_test(++n, "example.com", "http://wwwexample.com", false);
whitelist_test(++n, "http://www.example.com/", "http://www.amazon.com/wiki", false);
whitelist_test(++n, "www.example.com", "http://www.amazon.com", false);
// regexp cases
whitelist_test(++n, "*.example.com", "http://www.example.com", true);
whitelist_test(++n, "*.example.com", "http://www.amazon.com", false);
whitelist_test(++n, "*.example.com", "http://www.example.com/foo/bar", true);
whitelist_test(++n, "*.example.com", "http:/example.com/foo/bar", false);
whitelist_test(++n, "*example.com", "http://example.com/foo/bar", true);
whitelist_test(++n, "*example.com", "http://my.virus.com/foo/bar?example.com", false);
whitelist_test(++n, "example.com", "http://my.virus.com/foo/bar?example.com", false);
whitelist_test(++n, "*example.com", "http://my.virus.com/foo/bar?*example.com", false);
whitelist_test(++n, "http://*example.com", "http://www.example.com", true);
whitelist_test(++n, "http://*.example.com", "http://www.example.com", true);
whitelist_test(++n, "http://*.e$?^.com", "http://www.e$?^.com", true);
whitelist_test(++n, "*.example.com/foo/bar", "http://www.example.com/", false);
whitelist_test(++n, "*.example.com/foo/bar", "http://example.com/foo/bar", false);
whitelist_test(++n, "http://*.example.com/foo/bar", "http://www.example.com", false);
whitelist_test(++n, "http://*.example.com", "https://www.example.com", false);
whitelist_test(++n, "http*://*.example.com", "rtsp://www.example.com", false);
whitelist_test(++n, "http*://*.example.com", "https://www.example.com", true);
whitelist_test(++n, "example.com", "http://www.example.com", false);
whitelist_test(++n, "www.example.com", "http://www.example.com:80", false);
whitelist_test(++n, "www.example.com", "http://www.example.com", true);
whitelist_test(++n, "www.example.com/", "http://www.example.com", false);
whitelist_test(++n, "www.example.com/foo/bar/*", "http://www.example.com/foo/bar/baz", true);
// Path only
whitelist_test(++n, "/foo/*/baz", "http://www.example.com/foo/bar/baz", true);
whitelist_test(++n, "/foo/*/baz", "http://www.example.com/foo/bar/", false);
}
}
@@ -0,0 +1,47 @@
/**
* @file llmessagesystem_stub.cpp
*
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "linden_common.h"
const char * const _PREHASH_TextureEntry = "TextureEntry";
S32 LLMessageSystem::getSizeFast(char const*, char const*) const
{
return 0;
}
S32 LLMessageSystem::getSizeFast(char const*, int, char const*) const
{
return 0;
}
void LLMessageSystem::getBinaryDataFast(char const*, char const*, void*, int, int, int)
{
}
void LLMessageSystem::addBinaryDataFast(char const*, void const*, int)
{
}
@@ -0,0 +1,271 @@
/**
* @file llprimitive_test.cpp
* @brief llprimitive tests
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "linden_common.h"
#include "../test/lltut.h"
#include "../llprimitive.h"
#include "../../llmath/llvolumemgr.h"
class DummyVolumeMgr : public LLVolumeMgr
{
public:
DummyVolumeMgr() : LLVolumeMgr(), mVolumeTest(NULL), mCurrDetailTest(0) {}
~DummyVolumeMgr()
{
}
virtual LLVolume *refVolume(const LLVolumeParams &volume_params, const S32 detail)
{
if (mVolumeTest.isNull() || volume_params != mCurrParamsTest || detail != mCurrDetailTest)
{
F32 volume_detail = LLVolumeLODGroup::getVolumeScaleFromDetail(detail);
mVolumeTest = new LLVolume(volume_params, volume_detail, false, false);
mCurrParamsTest = volume_params;
mCurrDetailTest = detail;
return mVolumeTest;
}
else
{
return mVolumeTest;
}
}
virtual void unrefVolume(LLVolume *volumep)
{
if (mVolumeTest == volumep)
{
mVolumeTest = NULL;
}
}
private:
LLPointer<LLVolume> mVolumeTest;
LLVolumeParams mCurrParamsTest;
S32 mCurrDetailTest;
};
LLMaterialID::LLMaterialID() {}
LLMaterialID::LLMaterialID(LLMaterialID const &m) = default;
LLMaterialID::~LLMaterialID() {}
void LLMaterialID::set(void const*) { }
U8 const * LLMaterialID::get() const { return mID; }
LLPrimTextureList::LLPrimTextureList() { }
LLPrimTextureList::~LLPrimTextureList() { }
S32 LLPrimTextureList::setBumpMap(const U8 index, const U8 bump) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::setOffsetS(const U8 index, const F32 s) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::setOffsetT(const U8 index, const F32 t) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::copyTexture(const U8 index, const LLTextureEntry &te) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::setRotation(const U8 index, const F32 r) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::setBumpShiny(const U8 index, const U8 bump_shiny) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::setFullbright(const U8 index, const U8 t) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::setMaterialID(const U8 index, const LLMaterialID& pMaterialID) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::setMediaFlags(const U8 index, const U8 media_flags) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::setMediaTexGen(const U8 index, const U8 media) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::setBumpShinyFullbright(const U8 index, const U8 bump) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::setID(const U8 index, const LLUUID& id) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::setGlow(const U8 index, const F32 glow) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::setAlpha(const U8 index, const F32 alpha) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::setColor(const U8 index, const LLColor3& color) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::setColor(const U8 index, const LLColor4& color) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::setScale(const U8 index, const F32 s, const F32 t) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::setScaleS(const U8 index, const F32 s) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::setScaleT(const U8 index, const F32 t) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::setShiny(const U8 index, const U8 shiny) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::setOffset(const U8 index, const F32 s, const F32 t) { return TEM_CHANGE_NONE; }
S32 LLPrimTextureList::setTexGen(const U8 index, const U8 texgen) { return TEM_CHANGE_NONE; }
LLMaterialPtr LLPrimTextureList::getMaterialParams(const U8 index) { return LLMaterialPtr(); }
void LLPrimTextureList::copy(LLPrimTextureList const & ptl) { mEntryList = ptl.mEntryList; } // do we need to call getTexture()->newCopy()?
void LLPrimTextureList::take(LLPrimTextureList &other_list) { }
void LLPrimTextureList::setSize(S32 new_size) { mEntryList.resize(new_size); }
void LLPrimTextureList::setAllIDs(const LLUUID &id) { }
LLTextureEntry * LLPrimTextureList::getTexture(const U8 index) const { return nullptr; }
S32 LLPrimTextureList::size() const { return static_cast<S32>(mEntryList.size()); }
class PRIMITIVE_TEST_SETUP
{
public:
PRIMITIVE_TEST_SETUP()
{
volume_manager_test = new DummyVolumeMgr();
LLPrimitive::setVolumeManager(volume_manager_test);
}
~PRIMITIVE_TEST_SETUP()
{
LLPrimitive::cleanupVolumeManager();
}
DummyVolumeMgr * volume_manager_test;
};
namespace tut
{
struct llprimitive
{
PRIMITIVE_TEST_SETUP setup_class;
};
typedef test_group<llprimitive> llprimitive_t;
typedef llprimitive_t::object llprimitive_object_t;
tut::llprimitive_t tut_llprimitive("LLPrimitive");
template<> template<>
void llprimitive_object_t::test<1>()
{
set_test_name("Test LLPrimitive Instantiation");
LLPrimitive test;
}
template<> template<>
void llprimitive_object_t::test<2>()
{
set_test_name("Test LLPrimitive PCode setter and getter.");
LLPrimitive test;
ensure_equals(test.getPCode(), 0);
LLPCode code = 1;
test.setPCode(code);
ensure_equals(test.getPCode(), code);
}
template<> template<>
void llprimitive_object_t::test<3>()
{
set_test_name("Test llprimitive constructor and initer.");
LLPCode code = 1;
LLPrimitive primitive;
primitive.init_primitive(code);
ensure_equals(primitive.getPCode(), code);
}
template<> template<>
void llprimitive_object_t::test<4>()
{
set_test_name("Test Static llprimitive constructor and initer.");
LLPCode code = 1;
LLPrimitive * primitive = LLPrimitive::createPrimitive(code);
ensure(primitive != NULL);
ensure_equals(primitive->getPCode(), code);
}
template<> template<>
void llprimitive_object_t::test<5>()
{
set_test_name("Test setVolume creation of new unique volume.");
LLPrimitive primitive;
LLVolumeParams params;
// Make sure volume starts off null
ensure(primitive.getVolume() == NULL);
// Make sure we have no texture entries before setting the volume
ensure_equals(primitive.getNumTEs(), 0);
// Test that GEOMETRY has not been flagged as changed.
ensure(!primitive.isChanged(LLXform::GEOMETRY));
// Make sure setVolume returns true
ensure(primitive.setVolume(params, 0, true) == true);
LLVolume* new_volume = primitive.getVolume();
// make sure new volume was actually created
ensure(new_volume != NULL);
// Make sure that now that we've set the volume we have texture entries
ensure_not_equals(primitive.getNumTEs(), 0);
// Make sure that the number of texture entries equals the number of faces in the volume (should be 6)
ensure_equals(new_volume->getNumFaces(), 6);
ensure_equals(primitive.getNumTEs(), new_volume->getNumFaces());
// Test that GEOMETRY has been flagged as changed.
ensure(primitive.isChanged(LLXform::GEOMETRY));
// Run it twice to make sure it doesn't create a different one if params are the same
ensure(primitive.setVolume(params, 0, true) == false);
ensure(new_volume == primitive.getVolume());
// Change the param definition and try setting it again.
params.setRevolutions(4);
ensure(primitive.setVolume(params, 0, true) == true);
// Ensure that we now have a different volume
ensure(new_volume != primitive.getVolume());
}
template<> template<>
void llprimitive_object_t::test<6>()
{
set_test_name("Test setVolume creation of new NOT-unique volume.");
LLPrimitive primitive;
LLVolumeParams params;
// Make sure volume starts off null
ensure(primitive.getVolume() == NULL);
// Make sure we have no texture entries before setting the volume
ensure_equals(primitive.getNumTEs(), 0);
// Test that GEOMETRY has not been flagged as changed.
ensure(!primitive.isChanged(LLXform::GEOMETRY));
// Make sure setVolume returns true
ensure(primitive.setVolume(params, 0, false) == true);
LLVolume* new_volume = primitive.getVolume();
// make sure new volume was actually created
ensure(new_volume != NULL);
// Make sure that now that we've set the volume we have texture entries
ensure_not_equals(primitive.getNumTEs(), 0);
// Make sure that the number of texture entries equals the number of faces in the volume (should be 6)
ensure_equals(new_volume->getNumFaces(), 6);
ensure_equals(primitive.getNumTEs(), new_volume->getNumFaces());
// Test that GEOMETRY has been flagged as changed.
ensure(primitive.isChanged(LLXform::GEOMETRY));
// Run it twice to make sure it doesn't create a different one if params are the same
ensure(primitive.setVolume(params, 0, false) == false);
ensure(new_volume == primitive.getVolume());
// Change the param definition and try setting it again.
params.setRevolutions(4);
ensure(primitive.setVolume(params, 0, false) == true);
// Ensure that we now have a different volume
ensure(new_volume != primitive.getVolume());
}
}
#include "llmessagesystem_stub.cpp"